User session counters stay <= per-user limit
[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))
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))
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;
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))
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       s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
945       s->outside_address_index = ~0;
946       s->out2in = e_key;
947       s->in2out = l_key;
948       user_session_increment (sm, u, 1 /* static */);
949
950       /* Add to lookup tables */
951       s_kv.value = s - tsm->sessions;
952       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
953         clib_warning ("out2in-ed key add failed");
954
955       if (twice_nat)
956         {
957           eh_key.protocol = proto;
958           if (snat_alloc_outside_address_and_port (sm->twice_nat_addresses, 0,
959                                                    thread_index, &eh_key,
960                                                    &address_index,
961                                                    sm->port_per_thread,
962                                                    sm->per_thread_data[thread_index].snat_thread_index))
963             {
964               b->error = node->errors[SNAT_OUT2IN_ERROR_OUT_OF_PORTS];
965               return 0;
966             }
967           key.r_addr.as_u32 = s->ext_host_nat_addr.as_u32 = eh_key.addr.as_u32;
968           key.r_port = s->ext_host_nat_port = eh_key.port;
969           s->flags |= SNAT_SESSION_FLAG_TWICE_NAT;
970         }
971       key.l_addr = l_key.addr;
972       key.fib_index = l_key.fib_index;
973       key.l_port = l_key.port;
974       s_kv.key[0] = key.as_u64[0];
975       s_kv.key[1] = key.as_u64[1];
976       if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
977         clib_warning ("in2out-ed key add failed");
978     }
979
980   new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
981
982   /* Update IP checksum */
983   sum = ip->checksum;
984   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
985   if (is_twice_nat_session (s))
986     sum = ip_csum_update (sum, ip->src_address.as_u32,
987                           s->ext_host_nat_addr.as_u32, ip4_header_t,
988                           src_address);
989   ip->checksum = ip_csum_fold (sum);
990
991   if (PREDICT_TRUE(proto == SNAT_PROTOCOL_TCP))
992     {
993       old_port = tcp->dst_port;
994       tcp->dst_port = s->in2out.port;
995       new_port = tcp->dst_port;
996
997       sum = tcp->checksum;
998       sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
999       sum = ip_csum_update (sum, old_port, new_port, ip4_header_t, length);
1000       if (is_twice_nat_session (s))
1001         {
1002           sum = ip_csum_update (sum, ip->src_address.as_u32,
1003                                 s->ext_host_nat_addr.as_u32, ip4_header_t,
1004                                 dst_address);
1005           sum = ip_csum_update (sum, tcp->src_port, s->ext_host_nat_port,
1006                                 ip4_header_t, length);
1007           tcp->src_port = s->ext_host_nat_port;
1008           ip->src_address.as_u32 = s->ext_host_nat_addr.as_u32;
1009         }
1010       tcp->checksum = ip_csum_fold(sum);
1011     }
1012   else
1013     {
1014       udp->dst_port = s->in2out.port;
1015       if (is_twice_nat_session (s))
1016         {
1017           udp->src_port = s->ext_host_nat_port;
1018           ip->src_address.as_u32 = s->ext_host_nat_addr.as_u32;
1019         }
1020       udp->checksum = 0;
1021     }
1022
1023   vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
1024
1025   /* Accounting */
1026   s->last_heard = now;
1027   s->total_pkts++;
1028   s->total_bytes += vlib_buffer_length_in_chain (vm, b);
1029   /* Per-user LRU list maintenance */
1030   clib_dlist_remove (tsm->list_pool, s->per_user_index);
1031   clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
1032                       s->per_user_index);
1033
1034   return s;
1035 }
1036
1037 static uword
1038 snat_out2in_node_fn (vlib_main_t * vm,
1039                   vlib_node_runtime_t * node,
1040                   vlib_frame_t * frame)
1041 {
1042   u32 n_left_from, * from, * to_next;
1043   snat_out2in_next_t next_index;
1044   u32 pkts_processed = 0;
1045   snat_main_t * sm = &snat_main;
1046   f64 now = vlib_time_now (vm);
1047   u32 thread_index = vlib_get_thread_index ();
1048
1049   from = vlib_frame_vector_args (frame);
1050   n_left_from = frame->n_vectors;
1051   next_index = node->cached_next_index;
1052
1053   while (n_left_from > 0)
1054     {
1055       u32 n_left_to_next;
1056
1057       vlib_get_next_frame (vm, node, next_index,
1058                            to_next, n_left_to_next);
1059
1060       while (n_left_from >= 4 && n_left_to_next >= 2)
1061         {
1062           u32 bi0, bi1;
1063           vlib_buffer_t * b0, * b1;
1064           u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1065           u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
1066           u32 sw_if_index0, sw_if_index1;
1067           ip4_header_t * ip0, *ip1;
1068           ip_csum_t sum0, sum1;
1069           u32 new_addr0, old_addr0;
1070           u16 new_port0, old_port0;
1071           u32 new_addr1, old_addr1;
1072           u16 new_port1, old_port1;
1073           udp_header_t * udp0, * udp1;
1074           tcp_header_t * tcp0, * tcp1;
1075           icmp46_header_t * icmp0, * icmp1;
1076           snat_session_key_t key0, key1, sm0, sm1;
1077           u32 rx_fib_index0, rx_fib_index1;
1078           u32 proto0, proto1;
1079           snat_session_t * s0 = 0, * s1 = 0;
1080           clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
1081
1082           /* Prefetch next iteration. */
1083           {
1084             vlib_buffer_t * p2, * p3;
1085
1086             p2 = vlib_get_buffer (vm, from[2]);
1087             p3 = vlib_get_buffer (vm, from[3]);
1088
1089             vlib_prefetch_buffer_header (p2, LOAD);
1090             vlib_prefetch_buffer_header (p3, LOAD);
1091
1092             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
1093             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
1094           }
1095
1096           /* speculatively enqueue b0 and b1 to the current next frame */
1097           to_next[0] = bi0 = from[0];
1098           to_next[1] = bi1 = from[1];
1099           from += 2;
1100           to_next += 2;
1101           n_left_from -= 2;
1102           n_left_to_next -= 2;
1103
1104           b0 = vlib_get_buffer (vm, bi0);
1105           b1 = vlib_get_buffer (vm, bi1);
1106
1107           vnet_buffer (b0)->snat.flags = 0;
1108           vnet_buffer (b1)->snat.flags = 0;
1109
1110           ip0 = vlib_buffer_get_current (b0);
1111           udp0 = ip4_next_header (ip0);
1112           tcp0 = (tcp_header_t *) udp0;
1113           icmp0 = (icmp46_header_t *) udp0;
1114
1115           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1116           rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1117                                    sw_if_index0);
1118
1119           if (PREDICT_FALSE(ip0->ttl == 1))
1120             {
1121               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1122               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1123                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1124                                            0);
1125               next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1126               goto trace0;
1127             }
1128
1129           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1130
1131           if (PREDICT_FALSE (proto0 == ~0))
1132             {
1133               s0 = snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0,
1134                                              thread_index, now, vm, node);
1135               if (!sm->forwarding_enabled)
1136                 if (!s0)
1137                   next0 = SNAT_OUT2IN_NEXT_DROP;
1138               goto trace0;
1139             }
1140
1141           if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1142             {
1143               next0 = icmp_out2in_slow_path
1144                 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1145                  next0, now, thread_index, &s0);
1146               goto trace0;
1147             }
1148
1149           if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1150             {
1151               next0 = SNAT_OUT2IN_NEXT_REASS;
1152               goto trace0;
1153             }
1154
1155           key0.addr = ip0->dst_address;
1156           key0.port = udp0->dst_port;
1157           key0.protocol = proto0;
1158           key0.fib_index = rx_fib_index0;
1159
1160           kv0.key = key0.as_u64;
1161
1162           if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1163                                       &kv0, &value0))
1164             {
1165               /* Try to match static mapping by external address and port,
1166                  destination address and port in packet */
1167               if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
1168                 {
1169                   if (!sm->forwarding_enabled)
1170                     {
1171                       b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1172                       /*
1173                        * Send DHCP packets to the ipv4 stack, or we won't
1174                        * be able to use dhcp client on the outside interface
1175                        */
1176                       if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP
1177                           || (udp0->dst_port
1178                               != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
1179                         next0 = SNAT_OUT2IN_NEXT_DROP;
1180                       else
1181                         vnet_feature_next
1182                           (vnet_buffer (b0)->sw_if_index[VLIB_RX],
1183                            &next0, b0);
1184                       goto trace0;
1185                     }
1186                   else
1187                     {
1188                       if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
1189                         {
1190                           next0 = SNAT_OUT2IN_NEXT_IN2OUT;
1191                           goto trace0;
1192                         }
1193                       create_bypass_for_fwd(sm, ip0);
1194                       goto trace0;
1195                     }
1196                 }
1197
1198               /* Create session initiated by host from external network */
1199               s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1200                                                      thread_index);
1201               if (!s0)
1202                 {
1203                   next0 = SNAT_OUT2IN_NEXT_DROP;
1204                   goto trace0;
1205                 }
1206             }
1207           else
1208             {
1209               if (PREDICT_FALSE (value0.value == ~0ULL))
1210                 {
1211                   s0 = snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index,
1212                                       now, vm, node);
1213                   if (!s0)
1214                     next0 = SNAT_OUT2IN_NEXT_DROP;
1215                   goto trace0;
1216                 }
1217               else
1218                 {
1219                   s0 = pool_elt_at_index (
1220                     sm->per_thread_data[thread_index].sessions,
1221                     value0.value);
1222                 }
1223             }
1224
1225           old_addr0 = ip0->dst_address.as_u32;
1226           ip0->dst_address = s0->in2out.addr;
1227           new_addr0 = ip0->dst_address.as_u32;
1228           vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1229
1230           sum0 = ip0->checksum;
1231           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1232                                  ip4_header_t,
1233                                  dst_address /* changed member */);
1234           ip0->checksum = ip_csum_fold (sum0);
1235
1236           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1237             {
1238               old_port0 = tcp0->dst_port;
1239               tcp0->dst_port = s0->in2out.port;
1240               new_port0 = tcp0->dst_port;
1241
1242               sum0 = tcp0->checksum;
1243               sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1244                                      ip4_header_t,
1245                                      dst_address /* changed member */);
1246
1247               sum0 = ip_csum_update (sum0, old_port0, new_port0,
1248                                      ip4_header_t /* cheat */,
1249                                      length /* changed member */);
1250               tcp0->checksum = ip_csum_fold(sum0);
1251             }
1252           else
1253             {
1254               old_port0 = udp0->dst_port;
1255               udp0->dst_port = s0->in2out.port;
1256               udp0->checksum = 0;
1257             }
1258
1259           /* Accounting */
1260           s0->last_heard = now;
1261           s0->total_pkts++;
1262           s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1263           /* Per-user LRU list maintenance */
1264           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1265                              s0->per_user_index);
1266           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1267                               s0->per_user_list_head_index,
1268                               s0->per_user_index);
1269         trace0:
1270
1271           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1272                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1273             {
1274               snat_out2in_trace_t *t =
1275                  vlib_add_trace (vm, node, b0, sizeof (*t));
1276               t->sw_if_index = sw_if_index0;
1277               t->next_index = next0;
1278               t->session_index = ~0;
1279               if (s0)
1280                 t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1281             }
1282
1283           pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1284
1285
1286           ip1 = vlib_buffer_get_current (b1);
1287           udp1 = ip4_next_header (ip1);
1288           tcp1 = (tcp_header_t *) udp1;
1289           icmp1 = (icmp46_header_t *) udp1;
1290
1291           sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1292           rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1293                                    sw_if_index1);
1294
1295           if (PREDICT_FALSE(ip1->ttl == 1))
1296             {
1297               vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1298               icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1299                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1300                                            0);
1301               next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1302               goto trace1;
1303             }
1304
1305           proto1 = ip_proto_to_snat_proto (ip1->protocol);
1306
1307           if (PREDICT_FALSE (proto1 == ~0))
1308             {
1309               s1 = snat_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1,
1310                                              thread_index, now, vm, node);
1311               if (!sm->forwarding_enabled)
1312                 if (!s1)
1313                   next1 = SNAT_OUT2IN_NEXT_DROP;
1314               goto trace1;
1315             }
1316
1317           if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1318             {
1319               next1 = icmp_out2in_slow_path
1320                 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1321                  next1, now, thread_index, &s1);
1322               goto trace1;
1323             }
1324
1325           if (PREDICT_FALSE (ip4_is_fragment (ip1)))
1326             {
1327               next1 = SNAT_OUT2IN_NEXT_REASS;
1328               goto trace1;
1329             }
1330
1331           key1.addr = ip1->dst_address;
1332           key1.port = udp1->dst_port;
1333           key1.protocol = proto1;
1334           key1.fib_index = rx_fib_index1;
1335
1336           kv1.key = key1.as_u64;
1337
1338           if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1339                                       &kv1, &value1))
1340             {
1341               /* Try to match static mapping by external address and port,
1342                  destination address and port in packet */
1343               if (snat_static_mapping_match(sm, key1, &sm1, 1, 0, 0))
1344                 {
1345                   if (!sm->forwarding_enabled)
1346                     {
1347                       b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1348                       /*
1349                        * Send DHCP packets to the ipv4 stack, or we won't
1350                        * be able to use dhcp client on the outside interface
1351                        */
1352                       if (PREDICT_TRUE (proto1 != SNAT_PROTOCOL_UDP
1353                           || (udp1->dst_port
1354                               != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
1355                         next1 = SNAT_OUT2IN_NEXT_DROP;
1356                       else
1357                         vnet_feature_next
1358                           (vnet_buffer (b1)->sw_if_index[VLIB_RX],
1359                            &next1, b1);
1360                       goto trace1;
1361                     }
1362                   else
1363                     {
1364                       if (next_src_nat(sm, ip1, proto1, udp1->src_port, thread_index))
1365                         {
1366                           next1 = SNAT_OUT2IN_NEXT_IN2OUT;
1367                           goto trace1;
1368                         }
1369                       create_bypass_for_fwd(sm, ip1);
1370                       goto trace1;
1371                     }
1372                 }
1373
1374               /* Create session initiated by host from external network */
1375               s1 = create_session_for_static_mapping(sm, b1, sm1, key1, node,
1376                                                      thread_index);
1377               if (!s1)
1378                 {
1379                   next1 = SNAT_OUT2IN_NEXT_DROP;
1380                   goto trace1;
1381                 }
1382             }
1383           else
1384             {
1385               if (PREDICT_FALSE (value1.value == ~0ULL))
1386                 {
1387                   s1 = snat_out2in_lb(sm, b1, ip1, rx_fib_index1, thread_index,
1388                                       now, vm, node);
1389                   if (!s1)
1390                     next1 = SNAT_OUT2IN_NEXT_DROP;
1391                   goto trace1;
1392                 }
1393               else
1394                 {
1395                   s1 = pool_elt_at_index (
1396                     sm->per_thread_data[thread_index].sessions,
1397                     value1.value);
1398                 }
1399             }
1400
1401           old_addr1 = ip1->dst_address.as_u32;
1402           ip1->dst_address = s1->in2out.addr;
1403           new_addr1 = ip1->dst_address.as_u32;
1404           vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1405
1406           sum1 = ip1->checksum;
1407           sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1408                                  ip4_header_t,
1409                                  dst_address /* changed member */);
1410           ip1->checksum = ip_csum_fold (sum1);
1411
1412           if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1413             {
1414               old_port1 = tcp1->dst_port;
1415               tcp1->dst_port = s1->in2out.port;
1416               new_port1 = tcp1->dst_port;
1417
1418               sum1 = tcp1->checksum;
1419               sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1420                                      ip4_header_t,
1421                                      dst_address /* changed member */);
1422
1423               sum1 = ip_csum_update (sum1, old_port1, new_port1,
1424                                      ip4_header_t /* cheat */,
1425                                      length /* changed member */);
1426               tcp1->checksum = ip_csum_fold(sum1);
1427             }
1428           else
1429             {
1430               old_port1 = udp1->dst_port;
1431               udp1->dst_port = s1->in2out.port;
1432               udp1->checksum = 0;
1433             }
1434
1435           /* Accounting */
1436           s1->last_heard = now;
1437           s1->total_pkts++;
1438           s1->total_bytes += vlib_buffer_length_in_chain (vm, b1);
1439           /* Per-user LRU list maintenance */
1440           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1441                              s1->per_user_index);
1442           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1443                               s1->per_user_list_head_index,
1444                               s1->per_user_index);
1445         trace1:
1446
1447           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1448                             && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1449             {
1450               snat_out2in_trace_t *t =
1451                  vlib_add_trace (vm, node, b1, sizeof (*t));
1452               t->sw_if_index = sw_if_index1;
1453               t->next_index = next1;
1454               t->session_index = ~0;
1455               if (s1)
1456                 t->session_index = s1 - sm->per_thread_data[thread_index].sessions;
1457             }
1458
1459           pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
1460
1461           /* verify speculative enqueues, maybe switch current next frame */
1462           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1463                                            to_next, n_left_to_next,
1464                                            bi0, bi1, next0, next1);
1465         }
1466
1467       while (n_left_from > 0 && n_left_to_next > 0)
1468         {
1469           u32 bi0;
1470           vlib_buffer_t * b0;
1471           u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1472           u32 sw_if_index0;
1473           ip4_header_t * ip0;
1474           ip_csum_t sum0;
1475           u32 new_addr0, old_addr0;
1476           u16 new_port0, old_port0;
1477           udp_header_t * udp0;
1478           tcp_header_t * tcp0;
1479           icmp46_header_t * icmp0;
1480           snat_session_key_t key0, sm0;
1481           u32 rx_fib_index0;
1482           u32 proto0;
1483           snat_session_t * s0 = 0;
1484           clib_bihash_kv_8_8_t kv0, value0;
1485
1486           /* speculatively enqueue b0 to the current next frame */
1487           bi0 = from[0];
1488           to_next[0] = bi0;
1489           from += 1;
1490           to_next += 1;
1491           n_left_from -= 1;
1492           n_left_to_next -= 1;
1493
1494           b0 = vlib_get_buffer (vm, bi0);
1495
1496           vnet_buffer (b0)->snat.flags = 0;
1497
1498           ip0 = vlib_buffer_get_current (b0);
1499           udp0 = ip4_next_header (ip0);
1500           tcp0 = (tcp_header_t *) udp0;
1501           icmp0 = (icmp46_header_t *) udp0;
1502
1503           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1504           rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1505                                    sw_if_index0);
1506
1507           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1508
1509           if (PREDICT_FALSE (proto0 == ~0))
1510             {
1511               s0 = snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0,
1512                                              thread_index, now, vm, node);
1513               if (!sm->forwarding_enabled)
1514                 if (!s0)
1515                   next0 = SNAT_OUT2IN_NEXT_DROP;
1516               goto trace00;
1517             }
1518
1519           if (PREDICT_FALSE(ip0->ttl == 1))
1520             {
1521               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1522               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1523                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1524                                            0);
1525               next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1526               goto trace00;
1527             }
1528
1529           if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1530             {
1531               next0 = icmp_out2in_slow_path
1532                 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1533                  next0, now, thread_index, &s0);
1534               goto trace00;
1535             }
1536
1537           if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1538             {
1539               next0 = SNAT_OUT2IN_NEXT_REASS;
1540               goto trace00;
1541             }
1542
1543           key0.addr = ip0->dst_address;
1544           key0.port = udp0->dst_port;
1545           key0.protocol = proto0;
1546           key0.fib_index = rx_fib_index0;
1547
1548           kv0.key = key0.as_u64;
1549
1550           if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1551                                       &kv0, &value0))
1552             {
1553               /* Try to match static mapping by external address and port,
1554                  destination address and port in packet */
1555               if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
1556                 {
1557                   if (!sm->forwarding_enabled)
1558                     {
1559                       b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1560                       /*
1561                        * Send DHCP packets to the ipv4 stack, or we won't
1562                        * be able to use dhcp client on the outside interface
1563                        */
1564                       if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP
1565                           || (udp0->dst_port
1566                               != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
1567                         next0 = SNAT_OUT2IN_NEXT_DROP;
1568                       else
1569                         vnet_feature_next
1570                           (vnet_buffer (b0)->sw_if_index[VLIB_RX],
1571                            &next0, b0);
1572                       goto trace00;
1573                     }
1574                   else
1575                     {
1576                       if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
1577                         {
1578                           next0 = SNAT_OUT2IN_NEXT_IN2OUT;
1579                           goto trace00;
1580                         }
1581                       create_bypass_for_fwd(sm, ip0);
1582                       goto trace00;
1583                     }
1584                 }
1585
1586               /* Create session initiated by host from external network */
1587               s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1588                                                      thread_index);
1589               if (!s0)
1590                 {
1591                   next0 = SNAT_OUT2IN_NEXT_DROP;
1592                   goto trace00;
1593                 }
1594             }
1595           else
1596             {
1597               if (PREDICT_FALSE (value0.value == ~0ULL))
1598                 {
1599                   s0 = snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index,
1600                                       now, vm, node);
1601                   if (!s0)
1602                     next0 = SNAT_OUT2IN_NEXT_DROP;
1603                   goto trace00;
1604                 }
1605               else
1606                 {
1607                   s0 = pool_elt_at_index (
1608                     sm->per_thread_data[thread_index].sessions,
1609                     value0.value);
1610                 }
1611             }
1612
1613           old_addr0 = ip0->dst_address.as_u32;
1614           ip0->dst_address = s0->in2out.addr;
1615           new_addr0 = ip0->dst_address.as_u32;
1616           vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1617
1618           sum0 = ip0->checksum;
1619           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1620                                  ip4_header_t,
1621                                  dst_address /* changed member */);
1622           ip0->checksum = ip_csum_fold (sum0);
1623
1624           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1625             {
1626               old_port0 = tcp0->dst_port;
1627               tcp0->dst_port = s0->in2out.port;
1628               new_port0 = tcp0->dst_port;
1629
1630               sum0 = tcp0->checksum;
1631               sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1632                                      ip4_header_t,
1633                                      dst_address /* changed member */);
1634
1635               sum0 = ip_csum_update (sum0, old_port0, new_port0,
1636                                      ip4_header_t /* cheat */,
1637                                      length /* changed member */);
1638               tcp0->checksum = ip_csum_fold(sum0);
1639             }
1640           else
1641             {
1642               old_port0 = udp0->dst_port;
1643               udp0->dst_port = s0->in2out.port;
1644               udp0->checksum = 0;
1645             }
1646
1647           /* Accounting */
1648           s0->last_heard = now;
1649           s0->total_pkts++;
1650           s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1651           /* Per-user LRU list maintenance */
1652           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1653                              s0->per_user_index);
1654           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1655                               s0->per_user_list_head_index,
1656                               s0->per_user_index);
1657         trace00:
1658
1659           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1660                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1661             {
1662               snat_out2in_trace_t *t =
1663                  vlib_add_trace (vm, node, b0, sizeof (*t));
1664               t->sw_if_index = sw_if_index0;
1665               t->next_index = next0;
1666               t->session_index = ~0;
1667               if (s0)
1668                 t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1669             }
1670
1671           pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1672
1673           /* verify speculative enqueue, maybe switch current next frame */
1674           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1675                                            to_next, n_left_to_next,
1676                                            bi0, next0);
1677         }
1678
1679       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1680     }
1681
1682   vlib_node_increment_counter (vm, snat_out2in_node.index,
1683                                SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1684                                pkts_processed);
1685   return frame->n_vectors;
1686 }
1687
1688 VLIB_REGISTER_NODE (snat_out2in_node) = {
1689   .function = snat_out2in_node_fn,
1690   .name = "nat44-out2in",
1691   .vector_size = sizeof (u32),
1692   .format_trace = format_snat_out2in_trace,
1693   .type = VLIB_NODE_TYPE_INTERNAL,
1694
1695   .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1696   .error_strings = snat_out2in_error_strings,
1697
1698   .runtime_data_bytes = sizeof (snat_runtime_t),
1699
1700   .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1701
1702   /* edit / add dispositions here */
1703   .next_nodes = {
1704     [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1705     [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1706     [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1707     [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1708     [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
1709   },
1710 };
1711 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn);
1712
1713 static uword
1714 nat44_out2in_reass_node_fn (vlib_main_t * vm,
1715                             vlib_node_runtime_t * node,
1716                             vlib_frame_t * frame)
1717 {
1718   u32 n_left_from, *from, *to_next;
1719   snat_out2in_next_t next_index;
1720   u32 pkts_processed = 0;
1721   snat_main_t *sm = &snat_main;
1722   f64 now = vlib_time_now (vm);
1723   u32 thread_index = vlib_get_thread_index ();
1724   snat_main_per_thread_data_t *per_thread_data =
1725     &sm->per_thread_data[thread_index];
1726   u32 *fragments_to_drop = 0;
1727   u32 *fragments_to_loopback = 0;
1728
1729   from = vlib_frame_vector_args (frame);
1730   n_left_from = frame->n_vectors;
1731   next_index = node->cached_next_index;
1732
1733   while (n_left_from > 0)
1734     {
1735       u32 n_left_to_next;
1736
1737       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1738
1739       while (n_left_from > 0 && n_left_to_next > 0)
1740        {
1741           u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1742           vlib_buffer_t *b0;
1743           u32 next0;
1744           u8 cached0 = 0;
1745           ip4_header_t *ip0;
1746           nat_reass_ip4_t *reass0;
1747           udp_header_t * udp0;
1748           tcp_header_t * tcp0;
1749           snat_session_key_t key0, sm0;
1750           clib_bihash_kv_8_8_t kv0, value0;
1751           snat_session_t * s0 = 0;
1752           u16 old_port0, new_port0;
1753           ip_csum_t sum0;
1754
1755           /* speculatively enqueue b0 to the current next frame */
1756           bi0 = from[0];
1757           to_next[0] = bi0;
1758           from += 1;
1759           to_next += 1;
1760           n_left_from -= 1;
1761           n_left_to_next -= 1;
1762
1763           b0 = vlib_get_buffer (vm, bi0);
1764           next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1765
1766           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1767           rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1768                                                                sw_if_index0);
1769
1770           if (PREDICT_FALSE (nat_reass_is_drop_frag(0)))
1771             {
1772               next0 = SNAT_OUT2IN_NEXT_DROP;
1773               b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
1774               goto trace0;
1775             }
1776
1777           ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1778           udp0 = ip4_next_header (ip0);
1779           tcp0 = (tcp_header_t *) udp0;
1780           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1781
1782           reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1783                                                  ip0->dst_address,
1784                                                  ip0->fragment_id,
1785                                                  ip0->protocol,
1786                                                  1,
1787                                                  &fragments_to_drop);
1788
1789           if (PREDICT_FALSE (!reass0))
1790             {
1791               next0 = SNAT_OUT2IN_NEXT_DROP;
1792               b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
1793               goto trace0;
1794             }
1795
1796           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1797             {
1798               key0.addr = ip0->dst_address;
1799               key0.port = udp0->dst_port;
1800               key0.protocol = proto0;
1801               key0.fib_index = rx_fib_index0;
1802               kv0.key = key0.as_u64;
1803
1804               if (clib_bihash_search_8_8 (&per_thread_data->out2in, &kv0, &value0))
1805                 {
1806                   /* Try to match static mapping by external address and port,
1807                      destination address and port in packet */
1808                   if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
1809                     {
1810                       if (!sm->forwarding_enabled)
1811                         {
1812                           b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1813                           /*
1814                            * Send DHCP packets to the ipv4 stack, or we won't
1815                            * be able to use dhcp client on the outside interface
1816                            */
1817                           if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP
1818                               || (udp0->dst_port
1819                                   != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
1820                             next0 = SNAT_OUT2IN_NEXT_DROP;
1821                           else
1822                             vnet_feature_next
1823                               (vnet_buffer (b0)->sw_if_index[VLIB_RX],
1824                                &next0, b0);
1825                           goto trace0;
1826                         }
1827                       else
1828                         {
1829                           if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
1830                             {
1831                               next0 = SNAT_OUT2IN_NEXT_IN2OUT;
1832                               goto trace0;
1833                             }
1834                           create_bypass_for_fwd(sm, ip0);
1835                           goto trace0;
1836                         }
1837                     }
1838
1839                   /* Create session initiated by host from external network */
1840                   s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1841                                                          thread_index);
1842                   if (!s0)
1843                     {
1844                       b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1845                       next0 = SNAT_OUT2IN_NEXT_DROP;
1846                       goto trace0;
1847                     }
1848                   reass0->sess_index = s0 - per_thread_data->sessions;
1849                   reass0->thread_index = thread_index;
1850                 }
1851               else
1852                 {
1853                   s0 = pool_elt_at_index (per_thread_data->sessions,
1854                                           value0.value);
1855                   reass0->sess_index = value0.value;
1856                 }
1857               nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1858             }
1859           else
1860             {
1861               if (PREDICT_FALSE (reass0->sess_index == (u32) ~0))
1862                 {
1863                   if (nat_ip4_reass_add_fragment (reass0, bi0))
1864                     {
1865                       b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
1866                       next0 = SNAT_OUT2IN_NEXT_DROP;
1867                       goto trace0;
1868                     }
1869                   cached0 = 1;
1870                   goto trace0;
1871                 }
1872               s0 = pool_elt_at_index (per_thread_data->sessions,
1873                                       reass0->sess_index);
1874             }
1875
1876           old_addr0 = ip0->dst_address.as_u32;
1877           ip0->dst_address = s0->in2out.addr;
1878           new_addr0 = ip0->dst_address.as_u32;
1879           vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1880
1881           sum0 = ip0->checksum;
1882           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1883                                  ip4_header_t,
1884                                  dst_address /* changed member */);
1885           ip0->checksum = ip_csum_fold (sum0);
1886
1887           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1888             {
1889               if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1890                 {
1891                   old_port0 = tcp0->dst_port;
1892                   tcp0->dst_port = s0->in2out.port;
1893                   new_port0 = tcp0->dst_port;
1894
1895                   sum0 = tcp0->checksum;
1896                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1897                                          ip4_header_t,
1898                                          dst_address /* changed member */);
1899
1900                   sum0 = ip_csum_update (sum0, old_port0, new_port0,
1901                                          ip4_header_t /* cheat */,
1902                                          length /* changed member */);
1903                   tcp0->checksum = ip_csum_fold(sum0);
1904                 }
1905               else
1906                 {
1907                   old_port0 = udp0->dst_port;
1908                   udp0->dst_port = s0->in2out.port;
1909                   udp0->checksum = 0;
1910                 }
1911             }
1912
1913           /* Accounting */
1914           s0->last_heard = now;
1915           s0->total_pkts++;
1916           s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1917           /* Per-user LRU list maintenance */
1918           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1919                              s0->per_user_index);
1920           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1921                               s0->per_user_list_head_index,
1922                               s0->per_user_index);
1923
1924         trace0:
1925           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1926                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1927             {
1928               nat44_out2in_reass_trace_t *t =
1929                  vlib_add_trace (vm, node, b0, sizeof (*t));
1930               t->cached = cached0;
1931               t->sw_if_index = sw_if_index0;
1932               t->next_index = next0;
1933             }
1934
1935           if (cached0)
1936             {
1937               n_left_to_next++;
1938               to_next--;
1939             }
1940           else
1941             {
1942               pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1943
1944               /* verify speculative enqueue, maybe switch current next frame */
1945               vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1946                                                to_next, n_left_to_next,
1947                                                bi0, next0);
1948             }
1949
1950           if (n_left_from == 0 && vec_len (fragments_to_loopback))
1951             {
1952               from = vlib_frame_vector_args (frame);
1953               u32 len = vec_len (fragments_to_loopback);
1954               if (len <= VLIB_FRAME_SIZE)
1955                 {
1956                   clib_memcpy (from, fragments_to_loopback, sizeof (u32) * len);
1957                   n_left_from = len;
1958                   vec_reset_length (fragments_to_loopback);
1959                 }
1960               else
1961                 {
1962                   clib_memcpy (from,
1963                                fragments_to_loopback + (len - VLIB_FRAME_SIZE),
1964                                sizeof (u32) * VLIB_FRAME_SIZE);
1965                   n_left_from = VLIB_FRAME_SIZE;
1966                   _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1967                 }
1968             }
1969        }
1970
1971       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1972     }
1973
1974   vlib_node_increment_counter (vm, nat44_out2in_reass_node.index,
1975                                SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1976                                pkts_processed);
1977
1978   nat_send_all_to_node (vm, fragments_to_drop, node,
1979                         &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
1980                         SNAT_OUT2IN_NEXT_DROP);
1981
1982   vec_free (fragments_to_drop);
1983   vec_free (fragments_to_loopback);
1984   return frame->n_vectors;
1985 }
1986
1987 VLIB_REGISTER_NODE (nat44_out2in_reass_node) = {
1988   .function = nat44_out2in_reass_node_fn,
1989   .name = "nat44-out2in-reass",
1990   .vector_size = sizeof (u32),
1991   .format_trace = format_nat44_out2in_reass_trace,
1992   .type = VLIB_NODE_TYPE_INTERNAL,
1993
1994   .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1995   .error_strings = snat_out2in_error_strings,
1996
1997   .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1998
1999   /* edit / add dispositions here */
2000   .next_nodes = {
2001     [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
2002     [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2003     [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2004     [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
2005     [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
2006   },
2007 };
2008 VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node,
2009                               nat44_out2in_reass_node_fn);
2010
2011 /**************************/
2012 /*** deterministic mode ***/
2013 /**************************/
2014 static uword
2015 snat_det_out2in_node_fn (vlib_main_t * vm,
2016                          vlib_node_runtime_t * node,
2017                          vlib_frame_t * frame)
2018 {
2019   u32 n_left_from, * from, * to_next;
2020   snat_out2in_next_t next_index;
2021   u32 pkts_processed = 0;
2022   snat_main_t * sm = &snat_main;
2023   u32 thread_index = vlib_get_thread_index ();
2024
2025   from = vlib_frame_vector_args (frame);
2026   n_left_from = frame->n_vectors;
2027   next_index = node->cached_next_index;
2028
2029   while (n_left_from > 0)
2030     {
2031       u32 n_left_to_next;
2032
2033       vlib_get_next_frame (vm, node, next_index,
2034                            to_next, n_left_to_next);
2035
2036       while (n_left_from >= 4 && n_left_to_next >= 2)
2037         {
2038           u32 bi0, bi1;
2039           vlib_buffer_t * b0, * b1;
2040           u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
2041           u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
2042           u32 sw_if_index0, sw_if_index1;
2043           ip4_header_t * ip0, * ip1;
2044           ip_csum_t sum0, sum1;
2045           ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
2046           u16 new_port0, old_port0, old_port1, new_port1;
2047           udp_header_t * udp0, * udp1;
2048           tcp_header_t * tcp0, * tcp1;
2049           u32 proto0, proto1;
2050           snat_det_out_key_t key0, key1;
2051           snat_det_map_t * dm0, * dm1;
2052           snat_det_session_t * ses0 = 0, * ses1 = 0;
2053           u32 rx_fib_index0, rx_fib_index1;
2054           icmp46_header_t * icmp0, * icmp1;
2055
2056           /* Prefetch next iteration. */
2057           {
2058             vlib_buffer_t * p2, * p3;
2059
2060             p2 = vlib_get_buffer (vm, from[2]);
2061             p3 = vlib_get_buffer (vm, from[3]);
2062
2063             vlib_prefetch_buffer_header (p2, LOAD);
2064             vlib_prefetch_buffer_header (p3, LOAD);
2065
2066             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
2067             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
2068           }
2069
2070           /* speculatively enqueue b0 and b1 to the current next frame */
2071           to_next[0] = bi0 = from[0];
2072           to_next[1] = bi1 = from[1];
2073           from += 2;
2074           to_next += 2;
2075           n_left_from -= 2;
2076           n_left_to_next -= 2;
2077
2078           b0 = vlib_get_buffer (vm, bi0);
2079           b1 = vlib_get_buffer (vm, bi1);
2080
2081           ip0 = vlib_buffer_get_current (b0);
2082           udp0 = ip4_next_header (ip0);
2083           tcp0 = (tcp_header_t *) udp0;
2084
2085           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2086
2087           if (PREDICT_FALSE(ip0->ttl == 1))
2088             {
2089               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2090               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2091                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
2092                                            0);
2093               next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
2094               goto trace0;
2095             }
2096
2097           proto0 = ip_proto_to_snat_proto (ip0->protocol);
2098
2099           if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
2100             {
2101               rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2102               icmp0 = (icmp46_header_t *) udp0;
2103
2104               next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2105                                   rx_fib_index0, node, next0, thread_index,
2106                                   &ses0, &dm0);
2107               goto trace0;
2108             }
2109
2110           key0.ext_host_addr = ip0->src_address;
2111           key0.ext_host_port = tcp0->src;
2112           key0.out_port = tcp0->dst;
2113
2114           dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
2115           if (PREDICT_FALSE(!dm0))
2116             {
2117               clib_warning("unknown dst address:  %U",
2118                            format_ip4_address, &ip0->dst_address);
2119               next0 = SNAT_OUT2IN_NEXT_DROP;
2120               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2121               goto trace0;
2122             }
2123
2124           snat_det_reverse(dm0, &ip0->dst_address,
2125                            clib_net_to_host_u16(tcp0->dst), &new_addr0);
2126
2127           ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
2128           if (PREDICT_FALSE(!ses0))
2129             {
2130               clib_warning("no match src %U:%d dst %U:%d for user %U",
2131                            format_ip4_address, &ip0->src_address,
2132                            clib_net_to_host_u16 (tcp0->src),
2133                            format_ip4_address, &ip0->dst_address,
2134                            clib_net_to_host_u16 (tcp0->dst),
2135                            format_ip4_address, &new_addr0);
2136               next0 = SNAT_OUT2IN_NEXT_DROP;
2137               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2138               goto trace0;
2139             }
2140           new_port0 = ses0->in_port;
2141
2142           old_addr0 = ip0->dst_address;
2143           ip0->dst_address = new_addr0;
2144           vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
2145
2146           sum0 = ip0->checksum;
2147           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2148                                  ip4_header_t,
2149                                  dst_address /* changed member */);
2150           ip0->checksum = ip_csum_fold (sum0);
2151
2152           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2153             {
2154               if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
2155                 ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
2156               else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
2157                 snat_det_ses_close(dm0, ses0);
2158
2159               old_port0 = tcp0->dst;
2160               tcp0->dst = new_port0;
2161
2162               sum0 = tcp0->checksum;
2163               sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2164                                      ip4_header_t,
2165                                      dst_address /* changed member */);
2166
2167               sum0 = ip_csum_update (sum0, old_port0, new_port0,
2168                                      ip4_header_t /* cheat */,
2169                                      length /* changed member */);
2170               tcp0->checksum = ip_csum_fold(sum0);
2171             }
2172           else
2173             {
2174               old_port0 = udp0->dst_port;
2175               udp0->dst_port = new_port0;
2176               udp0->checksum = 0;
2177             }
2178
2179         trace0:
2180
2181           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2182                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2183             {
2184               snat_out2in_trace_t *t =
2185                  vlib_add_trace (vm, node, b0, sizeof (*t));
2186               t->sw_if_index = sw_if_index0;
2187               t->next_index = next0;
2188               t->session_index = ~0;
2189               if (ses0)
2190                 t->session_index = ses0 - dm0->sessions;
2191             }
2192
2193           pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2194
2195           b1 = vlib_get_buffer (vm, bi1);
2196
2197           ip1 = vlib_buffer_get_current (b1);
2198           udp1 = ip4_next_header (ip1);
2199           tcp1 = (tcp_header_t *) udp1;
2200
2201           sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
2202
2203           if (PREDICT_FALSE(ip1->ttl == 1))
2204             {
2205               vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2206               icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
2207                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
2208                                            0);
2209               next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
2210               goto trace1;
2211             }
2212
2213           proto1 = ip_proto_to_snat_proto (ip1->protocol);
2214
2215           if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP))
2216             {
2217               rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1);
2218               icmp1 = (icmp46_header_t *) udp1;
2219
2220               next1 = icmp_out2in(sm, b1, ip1, icmp1, sw_if_index1,
2221                                   rx_fib_index1, node, next1, thread_index,
2222                                   &ses1, &dm1);
2223               goto trace1;
2224             }
2225
2226           key1.ext_host_addr = ip1->src_address;
2227           key1.ext_host_port = tcp1->src;
2228           key1.out_port = tcp1->dst;
2229
2230           dm1 = snat_det_map_by_out(sm, &ip1->dst_address);
2231           if (PREDICT_FALSE(!dm1))
2232             {
2233               clib_warning("unknown dst address:  %U",
2234                            format_ip4_address, &ip1->dst_address);
2235               next1 = SNAT_OUT2IN_NEXT_DROP;
2236               b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2237               goto trace1;
2238             }
2239
2240           snat_det_reverse(dm1, &ip1->dst_address,
2241                            clib_net_to_host_u16(tcp1->dst), &new_addr1);
2242
2243           ses1 = snat_det_get_ses_by_out (dm1, &new_addr1, key1.as_u64);
2244           if (PREDICT_FALSE(!ses1))
2245             {
2246               clib_warning("no match src %U:%d dst %U:%d for user %U",
2247                            format_ip4_address, &ip1->src_address,
2248                            clib_net_to_host_u16 (tcp1->src),
2249                            format_ip4_address, &ip1->dst_address,
2250                            clib_net_to_host_u16 (tcp1->dst),
2251                            format_ip4_address, &new_addr1);
2252               next1 = SNAT_OUT2IN_NEXT_DROP;
2253               b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2254               goto trace1;
2255             }
2256           new_port1 = ses1->in_port;
2257
2258           old_addr1 = ip1->dst_address;
2259           ip1->dst_address = new_addr1;
2260           vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
2261
2262           sum1 = ip1->checksum;
2263           sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
2264                                  ip4_header_t,
2265                                  dst_address /* changed member */);
2266           ip1->checksum = ip_csum_fold (sum1);
2267
2268           if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
2269             {
2270               if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
2271                 ses1->state = SNAT_SESSION_TCP_CLOSE_WAIT;
2272               else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_LAST_ACK)
2273                 snat_det_ses_close(dm1, ses1);
2274
2275               old_port1 = tcp1->dst;
2276               tcp1->dst = new_port1;
2277
2278               sum1 = tcp1->checksum;
2279               sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
2280                                      ip4_header_t,
2281                                      dst_address /* changed member */);
2282
2283               sum1 = ip_csum_update (sum1, old_port1, new_port1,
2284                                      ip4_header_t /* cheat */,
2285                                      length /* changed member */);
2286               tcp1->checksum = ip_csum_fold(sum1);
2287             }
2288           else
2289             {
2290               old_port1 = udp1->dst_port;
2291               udp1->dst_port = new_port1;
2292               udp1->checksum = 0;
2293             }
2294
2295         trace1:
2296
2297           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2298                             && (b1->flags & VLIB_BUFFER_IS_TRACED)))
2299             {
2300               snat_out2in_trace_t *t =
2301                  vlib_add_trace (vm, node, b1, sizeof (*t));
2302               t->sw_if_index = sw_if_index1;
2303               t->next_index = next1;
2304               t->session_index = ~0;
2305               if (ses1)
2306                 t->session_index = ses1 - dm1->sessions;
2307             }
2308
2309           pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
2310
2311           /* verify speculative enqueues, maybe switch current next frame */
2312           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2313                                            to_next, n_left_to_next,
2314                                            bi0, bi1, next0, next1);
2315          }
2316
2317       while (n_left_from > 0 && n_left_to_next > 0)
2318         {
2319           u32 bi0;
2320           vlib_buffer_t * b0;
2321           u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
2322           u32 sw_if_index0;
2323           ip4_header_t * ip0;
2324           ip_csum_t sum0;
2325           ip4_address_t new_addr0, old_addr0;
2326           u16 new_port0, old_port0;
2327           udp_header_t * udp0;
2328           tcp_header_t * tcp0;
2329           u32 proto0;
2330           snat_det_out_key_t key0;
2331           snat_det_map_t * dm0;
2332           snat_det_session_t * ses0 = 0;
2333           u32 rx_fib_index0;
2334           icmp46_header_t * icmp0;
2335
2336           /* speculatively enqueue b0 to the current next frame */
2337           bi0 = from[0];
2338           to_next[0] = bi0;
2339           from += 1;
2340           to_next += 1;
2341           n_left_from -= 1;
2342           n_left_to_next -= 1;
2343
2344           b0 = vlib_get_buffer (vm, bi0);
2345
2346           ip0 = vlib_buffer_get_current (b0);
2347           udp0 = ip4_next_header (ip0);
2348           tcp0 = (tcp_header_t *) udp0;
2349
2350           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2351
2352           if (PREDICT_FALSE(ip0->ttl == 1))
2353             {
2354               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2355               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2356                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
2357                                            0);
2358               next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
2359               goto trace00;
2360             }
2361
2362           proto0 = ip_proto_to_snat_proto (ip0->protocol);
2363
2364           if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
2365             {
2366               rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2367               icmp0 = (icmp46_header_t *) udp0;
2368
2369               next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2370                                   rx_fib_index0, node, next0, thread_index,
2371                                   &ses0, &dm0);
2372               goto trace00;
2373             }
2374
2375           key0.ext_host_addr = ip0->src_address;
2376           key0.ext_host_port = tcp0->src;
2377           key0.out_port = tcp0->dst;
2378
2379           dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
2380           if (PREDICT_FALSE(!dm0))
2381             {
2382               clib_warning("unknown dst address:  %U",
2383                            format_ip4_address, &ip0->dst_address);
2384               next0 = SNAT_OUT2IN_NEXT_DROP;
2385               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2386               goto trace00;
2387             }
2388
2389           snat_det_reverse(dm0, &ip0->dst_address,
2390                            clib_net_to_host_u16(tcp0->dst), &new_addr0);
2391
2392           ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
2393           if (PREDICT_FALSE(!ses0))
2394             {
2395               clib_warning("no match src %U:%d dst %U:%d for user %U",
2396                            format_ip4_address, &ip0->src_address,
2397                            clib_net_to_host_u16 (tcp0->src),
2398                            format_ip4_address, &ip0->dst_address,
2399                            clib_net_to_host_u16 (tcp0->dst),
2400                            format_ip4_address, &new_addr0);
2401               next0 = SNAT_OUT2IN_NEXT_DROP;
2402               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2403               goto trace00;
2404             }
2405           new_port0 = ses0->in_port;
2406
2407           old_addr0 = ip0->dst_address;
2408           ip0->dst_address = new_addr0;
2409           vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
2410
2411           sum0 = ip0->checksum;
2412           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2413                                  ip4_header_t,
2414                                  dst_address /* changed member */);
2415           ip0->checksum = ip_csum_fold (sum0);
2416
2417           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2418             {
2419               if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
2420                 ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
2421               else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
2422                 snat_det_ses_close(dm0, ses0);
2423
2424               old_port0 = tcp0->dst;
2425               tcp0->dst = new_port0;
2426
2427               sum0 = tcp0->checksum;
2428               sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2429                                      ip4_header_t,
2430                                      dst_address /* changed member */);
2431
2432               sum0 = ip_csum_update (sum0, old_port0, new_port0,
2433                                      ip4_header_t /* cheat */,
2434                                      length /* changed member */);
2435               tcp0->checksum = ip_csum_fold(sum0);
2436             }
2437           else
2438             {
2439               old_port0 = udp0->dst_port;
2440               udp0->dst_port = new_port0;
2441               udp0->checksum = 0;
2442             }
2443
2444         trace00:
2445
2446           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2447                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2448             {
2449               snat_out2in_trace_t *t =
2450                  vlib_add_trace (vm, node, b0, sizeof (*t));
2451               t->sw_if_index = sw_if_index0;
2452               t->next_index = next0;
2453               t->session_index = ~0;
2454               if (ses0)
2455                 t->session_index = ses0 - dm0->sessions;
2456             }
2457
2458           pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2459
2460           /* verify speculative enqueue, maybe switch current next frame */
2461           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2462                                            to_next, n_left_to_next,
2463                                            bi0, next0);
2464         }
2465
2466       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2467     }
2468
2469   vlib_node_increment_counter (vm, snat_det_out2in_node.index,
2470                                SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
2471                                pkts_processed);
2472   return frame->n_vectors;
2473 }
2474
2475 VLIB_REGISTER_NODE (snat_det_out2in_node) = {
2476   .function = snat_det_out2in_node_fn,
2477   .name = "nat44-det-out2in",
2478   .vector_size = sizeof (u32),
2479   .format_trace = format_snat_out2in_trace,
2480   .type = VLIB_NODE_TYPE_INTERNAL,
2481
2482   .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2483   .error_strings = snat_out2in_error_strings,
2484
2485   .runtime_data_bytes = sizeof (snat_runtime_t),
2486
2487   .n_next_nodes = SNAT_OUT2IN_N_NEXT,
2488
2489   /* edit / add dispositions here */
2490   .next_nodes = {
2491     [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
2492     [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2493     [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2494     [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
2495     [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
2496   },
2497 };
2498 VLIB_NODE_FUNCTION_MULTIARCH (snat_det_out2in_node, snat_det_out2in_node_fn);
2499
2500 /**
2501  * Get address and port values to be used for ICMP packet translation
2502  * and create session if needed
2503  *
2504  * @param[in,out] sm             NAT main
2505  * @param[in,out] node           NAT node runtime
2506  * @param[in] thread_index       thread index
2507  * @param[in,out] b0             buffer containing packet to be translated
2508  * @param[out] p_proto           protocol used for matching
2509  * @param[out] p_value           address and port after NAT translation
2510  * @param[out] p_dont_translate  if packet should not be translated
2511  * @param d                      optional parameter
2512  * @param e                      optional parameter
2513  */
2514 u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node,
2515                           u32 thread_index, vlib_buffer_t *b0,
2516                           ip4_header_t *ip0, u8 *p_proto,
2517                           snat_session_key_t *p_value,
2518                           u8 *p_dont_translate, void *d, void *e)
2519 {
2520   icmp46_header_t *icmp0;
2521   u32 sw_if_index0;
2522   u8 protocol;
2523   snat_det_out_key_t key0;
2524   u8 dont_translate = 0;
2525   u32 next0 = ~0;
2526   icmp_echo_header_t *echo0, *inner_echo0 = 0;
2527   ip4_header_t *inner_ip0;
2528   void *l4_header = 0;
2529   icmp46_header_t *inner_icmp0;
2530   snat_det_map_t * dm0 = 0;
2531   ip4_address_t new_addr0 = {{0}};
2532   snat_det_session_t * ses0 = 0;
2533   ip4_address_t out_addr;
2534
2535   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
2536   echo0 = (icmp_echo_header_t *)(icmp0+1);
2537   sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2538
2539   if (!icmp_is_error_message (icmp0))
2540     {
2541       protocol = SNAT_PROTOCOL_ICMP;
2542       key0.ext_host_addr = ip0->src_address;
2543       key0.ext_host_port = 0;
2544       key0.out_port = echo0->identifier;
2545       out_addr = ip0->dst_address;
2546     }
2547   else
2548     {
2549       inner_ip0 = (ip4_header_t *)(echo0+1);
2550       l4_header = ip4_next_header (inner_ip0);
2551       protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
2552       key0.ext_host_addr = inner_ip0->dst_address;
2553       out_addr = inner_ip0->src_address;
2554       switch (protocol)
2555         {
2556         case SNAT_PROTOCOL_ICMP:
2557           inner_icmp0 = (icmp46_header_t*)l4_header;
2558           inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
2559           key0.ext_host_port = 0;
2560           key0.out_port = inner_echo0->identifier;
2561           break;
2562         case SNAT_PROTOCOL_UDP:
2563         case SNAT_PROTOCOL_TCP:
2564           key0.ext_host_port = ((tcp_udp_header_t*)l4_header)->dst_port;
2565           key0.out_port = ((tcp_udp_header_t*)l4_header)->src_port;
2566           break;
2567         default:
2568           b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
2569           next0 = SNAT_OUT2IN_NEXT_DROP;
2570           goto out;
2571         }
2572     }
2573
2574   dm0 = snat_det_map_by_out(sm, &out_addr);
2575   if (PREDICT_FALSE(!dm0))
2576     {
2577       /* Don't NAT packet aimed at the intfc address */
2578       if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
2579                                           ip0->dst_address.as_u32)))
2580         {
2581           dont_translate = 1;
2582           goto out;
2583         }
2584       clib_warning("unknown dst address:  %U",
2585                    format_ip4_address, &ip0->dst_address);
2586       goto out;
2587     }
2588
2589   snat_det_reverse(dm0, &ip0->dst_address,
2590                    clib_net_to_host_u16(key0.out_port), &new_addr0);
2591
2592   ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
2593   if (PREDICT_FALSE(!ses0))
2594     {
2595       /* Don't NAT packet aimed at the intfc address */
2596       if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
2597                                           ip0->dst_address.as_u32)))
2598         {
2599           dont_translate = 1;
2600           goto out;
2601         }
2602       clib_warning("no match src %U:%d dst %U:%d for user %U",
2603                    format_ip4_address, &key0.ext_host_addr,
2604                    clib_net_to_host_u16 (key0.ext_host_port),
2605                    format_ip4_address, &out_addr,
2606                    clib_net_to_host_u16 (key0.out_port),
2607                    format_ip4_address, &new_addr0);
2608       b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2609       next0 = SNAT_OUT2IN_NEXT_DROP;
2610       goto out;
2611     }
2612
2613   if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
2614                     !icmp_is_error_message (icmp0)))
2615     {
2616       b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
2617       next0 = SNAT_OUT2IN_NEXT_DROP;
2618       goto out;
2619     }
2620
2621   goto out;
2622
2623 out:
2624   *p_proto = protocol;
2625   if (ses0)
2626     {
2627       p_value->addr = new_addr0;
2628       p_value->fib_index = sm->inside_fib_index;
2629       p_value->port = ses0->in_port;
2630     }
2631   *p_dont_translate = dont_translate;
2632   if (d)
2633     *(snat_det_session_t**)d = ses0;
2634   if (e)
2635     *(snat_det_map_t**)e = dm0;
2636   return next0;
2637 }
2638
2639 /**********************/
2640 /*** worker handoff ***/
2641 /**********************/
2642 static uword
2643 snat_out2in_worker_handoff_fn (vlib_main_t * vm,
2644                                vlib_node_runtime_t * node,
2645                                vlib_frame_t * frame)
2646 {
2647   snat_main_t *sm = &snat_main;
2648   vlib_thread_main_t *tm = vlib_get_thread_main ();
2649   u32 n_left_from, *from, *to_next = 0;
2650   static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
2651   static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
2652     = 0;
2653   vlib_frame_queue_elt_t *hf = 0;
2654   vlib_frame_t *f = 0;
2655   int i;
2656   u32 n_left_to_next_worker = 0, *to_next_worker = 0;
2657   u32 next_worker_index = 0;
2658   u32 current_worker_index = ~0;
2659   u32 thread_index = vlib_get_thread_index ();
2660
2661   ASSERT (vec_len (sm->workers));
2662
2663   if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0))
2664     {
2665       vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
2666
2667       vec_validate_init_empty (congested_handoff_queue_by_worker_index,
2668                                sm->first_worker_index + sm->num_workers - 1,
2669                                (vlib_frame_queue_t *) (~0));
2670     }
2671
2672   from = vlib_frame_vector_args (frame);
2673   n_left_from = frame->n_vectors;
2674
2675   while (n_left_from > 0)
2676     {
2677       u32 bi0;
2678       vlib_buffer_t *b0;
2679       u32 sw_if_index0;
2680       u32 rx_fib_index0;
2681       ip4_header_t * ip0;
2682       u8 do_handoff;
2683
2684       bi0 = from[0];
2685       from += 1;
2686       n_left_from -= 1;
2687
2688       b0 = vlib_get_buffer (vm, bi0);
2689
2690       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
2691       rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2692
2693       ip0 = vlib_buffer_get_current (b0);
2694
2695       next_worker_index = sm->worker_out2in_cb(ip0, rx_fib_index0);
2696
2697       if (PREDICT_FALSE (next_worker_index != thread_index))
2698         {
2699           do_handoff = 1;
2700
2701           if (next_worker_index != current_worker_index)
2702             {
2703               if (hf)
2704                 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
2705
2706               hf = vlib_get_worker_handoff_queue_elt (sm->fq_out2in_index,
2707                                                       next_worker_index,
2708                                                       handoff_queue_elt_by_worker_index);
2709
2710               n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors;
2711               to_next_worker = &hf->buffer_index[hf->n_vectors];
2712               current_worker_index = next_worker_index;
2713             }
2714
2715           /* enqueue to correct worker thread */
2716           to_next_worker[0] = bi0;
2717           to_next_worker++;
2718           n_left_to_next_worker--;
2719
2720           if (n_left_to_next_worker == 0)
2721             {
2722               hf->n_vectors = VLIB_FRAME_SIZE;
2723               vlib_put_frame_queue_elt (hf);
2724               current_worker_index = ~0;
2725               handoff_queue_elt_by_worker_index[next_worker_index] = 0;
2726               hf = 0;
2727             }
2728         }
2729       else
2730         {
2731           do_handoff = 0;
2732           /* if this is 1st frame */
2733           if (!f)
2734             {
2735               f = vlib_get_frame_to_node (vm, sm->out2in_node_index);
2736               to_next = vlib_frame_vector_args (f);
2737             }
2738
2739           to_next[0] = bi0;
2740           to_next += 1;
2741           f->n_vectors++;
2742         }
2743
2744       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
2745                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2746         {
2747           snat_out2in_worker_handoff_trace_t *t =
2748             vlib_add_trace (vm, node, b0, sizeof (*t));
2749           t->next_worker_index = next_worker_index;
2750           t->do_handoff = do_handoff;
2751         }
2752     }
2753
2754   if (f)
2755     vlib_put_frame_to_node (vm, sm->out2in_node_index, f);
2756
2757   if (hf)
2758     hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
2759
2760   /* Ship frames to the worker nodes */
2761   for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++)
2762     {
2763       if (handoff_queue_elt_by_worker_index[i])
2764         {
2765           hf = handoff_queue_elt_by_worker_index[i];
2766           /*
2767            * It works better to let the handoff node
2768            * rate-adapt, always ship the handoff queue element.
2769            */
2770           if (1 || hf->n_vectors == hf->last_n_vectors)
2771             {
2772               vlib_put_frame_queue_elt (hf);
2773               handoff_queue_elt_by_worker_index[i] = 0;
2774             }
2775           else
2776             hf->last_n_vectors = hf->n_vectors;
2777         }
2778       congested_handoff_queue_by_worker_index[i] =
2779         (vlib_frame_queue_t *) (~0);
2780     }
2781   hf = 0;
2782   current_worker_index = ~0;
2783   return frame->n_vectors;
2784 }
2785
2786 VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node) = {
2787   .function = snat_out2in_worker_handoff_fn,
2788   .name = "nat44-out2in-worker-handoff",
2789   .vector_size = sizeof (u32),
2790   .format_trace = format_snat_out2in_worker_handoff_trace,
2791   .type = VLIB_NODE_TYPE_INTERNAL,
2792
2793   .n_next_nodes = 1,
2794
2795   .next_nodes = {
2796     [0] = "error-drop",
2797   },
2798 };
2799
2800 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_worker_handoff_node, snat_out2in_worker_handoff_fn);
2801
2802 static uword
2803 snat_out2in_fast_node_fn (vlib_main_t * vm,
2804                           vlib_node_runtime_t * node,
2805                           vlib_frame_t * frame)
2806 {
2807   u32 n_left_from, * from, * to_next;
2808   snat_out2in_next_t next_index;
2809   u32 pkts_processed = 0;
2810   snat_main_t * sm = &snat_main;
2811
2812   from = vlib_frame_vector_args (frame);
2813   n_left_from = frame->n_vectors;
2814   next_index = node->cached_next_index;
2815
2816   while (n_left_from > 0)
2817     {
2818       u32 n_left_to_next;
2819
2820       vlib_get_next_frame (vm, node, next_index,
2821                            to_next, n_left_to_next);
2822
2823       while (n_left_from > 0 && n_left_to_next > 0)
2824         {
2825           u32 bi0;
2826           vlib_buffer_t * b0;
2827           u32 next0 = SNAT_OUT2IN_NEXT_DROP;
2828           u32 sw_if_index0;
2829           ip4_header_t * ip0;
2830           ip_csum_t sum0;
2831           u32 new_addr0, old_addr0;
2832           u16 new_port0, old_port0;
2833           udp_header_t * udp0;
2834           tcp_header_t * tcp0;
2835           icmp46_header_t * icmp0;
2836           snat_session_key_t key0, sm0;
2837           u32 proto0;
2838           u32 rx_fib_index0;
2839
2840           /* speculatively enqueue b0 to the current next frame */
2841           bi0 = from[0];
2842           to_next[0] = bi0;
2843           from += 1;
2844           to_next += 1;
2845           n_left_from -= 1;
2846           n_left_to_next -= 1;
2847
2848           b0 = vlib_get_buffer (vm, bi0);
2849
2850           ip0 = vlib_buffer_get_current (b0);
2851           udp0 = ip4_next_header (ip0);
2852           tcp0 = (tcp_header_t *) udp0;
2853           icmp0 = (icmp46_header_t *) udp0;
2854
2855           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2856           rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2857
2858           vnet_feature_next (sw_if_index0, &next0, b0);
2859
2860           if (PREDICT_FALSE(ip0->ttl == 1))
2861             {
2862               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2863               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2864                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
2865                                            0);
2866               next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
2867               goto trace00;
2868             }
2869
2870           proto0 = ip_proto_to_snat_proto (ip0->protocol);
2871
2872           if (PREDICT_FALSE (proto0 == ~0))
2873               goto trace00;
2874
2875           if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2876             {
2877               next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2878                                   rx_fib_index0, node, next0, ~0, 0, 0);
2879               goto trace00;
2880             }
2881
2882           key0.addr = ip0->dst_address;
2883           key0.port = udp0->dst_port;
2884           key0.fib_index = rx_fib_index0;
2885
2886           if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
2887             {
2888               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2889               goto trace00;
2890             }
2891
2892           new_addr0 = sm0.addr.as_u32;
2893           new_port0 = sm0.port;
2894           vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
2895           old_addr0 = ip0->dst_address.as_u32;
2896           ip0->dst_address.as_u32 = new_addr0;
2897
2898           sum0 = ip0->checksum;
2899           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2900                                  ip4_header_t,
2901                                  dst_address /* changed member */);
2902           ip0->checksum = ip_csum_fold (sum0);
2903
2904           if (PREDICT_FALSE(new_port0 != udp0->dst_port))
2905             {
2906                if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2907                 {
2908                   old_port0 = tcp0->dst_port;
2909                   tcp0->dst_port = new_port0;
2910
2911                   sum0 = tcp0->checksum;
2912                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2913                                          ip4_header_t,
2914                                          dst_address /* changed member */);
2915
2916                   sum0 = ip_csum_update (sum0, old_port0, new_port0,
2917                                          ip4_header_t /* cheat */,
2918                                          length /* changed member */);
2919                   tcp0->checksum = ip_csum_fold(sum0);
2920                 }
2921               else
2922                 {
2923                   old_port0 = udp0->dst_port;
2924                   udp0->dst_port = new_port0;
2925                   udp0->checksum = 0;
2926                 }
2927             }
2928           else
2929             {
2930               if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2931                 {
2932                   sum0 = tcp0->checksum;
2933                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2934                                          ip4_header_t,
2935                                          dst_address /* changed member */);
2936
2937                   tcp0->checksum = ip_csum_fold(sum0);
2938                 }
2939             }
2940
2941         trace00:
2942
2943           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2944                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2945             {
2946               snat_out2in_trace_t *t =
2947                  vlib_add_trace (vm, node, b0, sizeof (*t));
2948               t->sw_if_index = sw_if_index0;
2949               t->next_index = next0;
2950             }
2951
2952           pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2953
2954           /* verify speculative enqueue, maybe switch current next frame */
2955           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2956                                            to_next, n_left_to_next,
2957                                            bi0, next0);
2958         }
2959
2960       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2961     }
2962
2963   vlib_node_increment_counter (vm, snat_out2in_fast_node.index,
2964                                SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
2965                                pkts_processed);
2966   return frame->n_vectors;
2967 }
2968
2969 VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
2970   .function = snat_out2in_fast_node_fn,
2971   .name = "nat44-out2in-fast",
2972   .vector_size = sizeof (u32),
2973   .format_trace = format_snat_out2in_fast_trace,
2974   .type = VLIB_NODE_TYPE_INTERNAL,
2975
2976   .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2977   .error_strings = snat_out2in_error_strings,
2978
2979   .runtime_data_bytes = sizeof (snat_runtime_t),
2980
2981   .n_next_nodes = SNAT_OUT2IN_N_NEXT,
2982
2983   /* edit / add dispositions here */
2984   .next_nodes = {
2985     [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2986     [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
2987     [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2988     [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
2989     [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
2990   },
2991 };
2992 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node, snat_out2in_fast_node_fn);