NAT44: interface output feature and dst NAT (VPP-1200)
[vpp.git] / src / plugins / nat / in2out.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/ethernet/ethernet.h>
23 #include <vnet/fib/ip4_fib.h>
24 #include <nat/nat.h>
25 #include <nat/nat_ipfix_logging.h>
26 #include <nat/nat_det.h>
27 #include <nat/nat_reass.h>
28
29 #include <vppinfra/hash.h>
30 #include <vppinfra/error.h>
31 #include <vppinfra/elog.h>
32
33 typedef struct {
34   u32 sw_if_index;
35   u32 next_index;
36   u32 session_index;
37   u32 is_slow_path;
38 } snat_in2out_trace_t;
39
40 typedef struct {
41   u32 next_worker_index;
42   u8 do_handoff;
43 } snat_in2out_worker_handoff_trace_t;
44
45 /* packet trace format function */
46 static u8 * format_snat_in2out_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_in2out_trace_t * t = va_arg (*args, snat_in2out_trace_t *);
51   char * tag;
52
53   tag = t->is_slow_path ? "NAT44_IN2OUT_SLOW_PATH" : "NAT44_IN2OUT_FAST_PATH";
54
55   s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
56               t->sw_if_index, t->next_index, t->session_index);
57
58   return s;
59 }
60
61 static u8 * format_snat_in2out_fast_trace (u8 * s, va_list * args)
62 {
63   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
64   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
65   snat_in2out_trace_t * t = va_arg (*args, snat_in2out_trace_t *);
66
67   s = format (s, "NAT44_IN2OUT_FAST: sw_if_index %d, next index %d",
68               t->sw_if_index, t->next_index);
69
70   return s;
71 }
72
73 static u8 * format_snat_in2out_worker_handoff_trace (u8 * s, va_list * args)
74 {
75   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
76   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
77   snat_in2out_worker_handoff_trace_t * t =
78     va_arg (*args, snat_in2out_worker_handoff_trace_t *);
79   char * m;
80
81   m = t->do_handoff ? "next worker" : "same worker";
82   s = format (s, "NAT44_IN2OUT_WORKER_HANDOFF: %s %d", m, t->next_worker_index);
83
84   return s;
85 }
86
87 typedef struct {
88   u32 sw_if_index;
89   u32 next_index;
90   u8 cached;
91 } nat44_in2out_reass_trace_t;
92
93 static u8 * format_nat44_in2out_reass_trace (u8 * s, va_list * args)
94 {
95   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
96   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
97   nat44_in2out_reass_trace_t * t = va_arg (*args, nat44_in2out_reass_trace_t *);
98
99   s = format (s, "NAT44_IN2OUT_REASS: sw_if_index %d, next index %d, status %s",
100               t->sw_if_index, t->next_index,
101               t->cached ? "cached" : "translated");
102
103   return s;
104 }
105
106 vlib_node_registration_t snat_in2out_node;
107 vlib_node_registration_t snat_in2out_slowpath_node;
108 vlib_node_registration_t snat_in2out_fast_node;
109 vlib_node_registration_t snat_in2out_worker_handoff_node;
110 vlib_node_registration_t snat_det_in2out_node;
111 vlib_node_registration_t snat_in2out_output_node;
112 vlib_node_registration_t snat_in2out_output_slowpath_node;
113 vlib_node_registration_t snat_in2out_output_worker_handoff_node;
114 vlib_node_registration_t snat_hairpin_dst_node;
115 vlib_node_registration_t snat_hairpin_src_node;
116 vlib_node_registration_t nat44_hairpinning_node;
117 vlib_node_registration_t nat44_in2out_reass_node;
118
119
120 #define foreach_snat_in2out_error                       \
121 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol")         \
122 _(IN2OUT_PACKETS, "Good in2out packets processed")      \
123 _(OUT_OF_PORTS, "Out of ports")                         \
124 _(BAD_OUTSIDE_FIB, "Outside VRF ID not found")          \
125 _(BAD_ICMP_TYPE, "unsupported ICMP type")               \
126 _(NO_TRANSLATION, "No translation")                     \
127 _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded")   \
128 _(DROP_FRAGMENT, "Drop fragment")                       \
129 _(MAX_REASS, "Maximum reassemblies exceeded")           \
130 _(MAX_FRAG, "Maximum fragments per reassembly exceeded")
131
132 typedef enum {
133 #define _(sym,str) SNAT_IN2OUT_ERROR_##sym,
134   foreach_snat_in2out_error
135 #undef _
136   SNAT_IN2OUT_N_ERROR,
137 } snat_in2out_error_t;
138
139 static char * snat_in2out_error_strings[] = {
140 #define _(sym,string) string,
141   foreach_snat_in2out_error
142 #undef _
143 };
144
145 typedef enum {
146   SNAT_IN2OUT_NEXT_LOOKUP,
147   SNAT_IN2OUT_NEXT_DROP,
148   SNAT_IN2OUT_NEXT_ICMP_ERROR,
149   SNAT_IN2OUT_NEXT_SLOW_PATH,
150   SNAT_IN2OUT_NEXT_REASS,
151   SNAT_IN2OUT_N_NEXT,
152 } snat_in2out_next_t;
153
154 typedef enum {
155   SNAT_HAIRPIN_SRC_NEXT_DROP,
156   SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT,
157   SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH,
158   SNAT_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT,
159   SNAT_HAIRPIN_SRC_N_NEXT,
160 } snat_hairpin_next_t;
161
162 /**
163  * @brief Check if packet should be translated
164  *
165  * Packets aimed at outside interface and external address with active session
166  * should be translated.
167  *
168  * @param sm            NAT main
169  * @param rt            NAT runtime data
170  * @param sw_if_index0  index of the inside interface
171  * @param ip0           IPv4 header
172  * @param proto0        NAT protocol
173  * @param rx_fib_index0 RX FIB index
174  *
175  * @returns 0 if packet should be translated otherwise 1
176  */
177 static inline int
178 snat_not_translate_fast (snat_main_t * sm, vlib_node_runtime_t *node,
179                          u32 sw_if_index0, ip4_header_t * ip0, u32 proto0,
180                          u32 rx_fib_index0)
181 {
182   if (sm->out2in_dpo)
183     return 0;
184
185   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
186   fib_prefix_t pfx = {
187     .fp_proto = FIB_PROTOCOL_IP4,
188     .fp_len = 32,
189     .fp_addr = {
190         .ip4.as_u32 = ip0->dst_address.as_u32,
191     },
192   };
193
194   /* Don't NAT packet aimed at the intfc address */
195   if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
196                                       ip0->dst_address.as_u32)))
197     return 1;
198
199   fei = fib_table_lookup (rx_fib_index0, &pfx);
200   if (FIB_NODE_INDEX_INVALID != fei)
201     {
202       u32 sw_if_index = fib_entry_get_resolving_interface (fei);
203       if (sw_if_index == ~0)
204         {
205           fei = fib_table_lookup (sm->outside_fib_index, &pfx);
206           if (FIB_NODE_INDEX_INVALID != fei)
207             sw_if_index = fib_entry_get_resolving_interface (fei);
208         }
209       snat_interface_t *i;
210       pool_foreach (i, sm->interfaces,
211       ({
212         /* NAT packet aimed at outside interface */
213         if ((nat_interface_is_outside(i)) && (sw_if_index == i->sw_if_index))
214           return 0;
215       }));
216     }
217
218   return 1;
219 }
220
221 static inline int
222 snat_not_translate (snat_main_t * sm, vlib_node_runtime_t *node,
223                     u32 sw_if_index0, ip4_header_t * ip0, u32 proto0,
224                     u32 rx_fib_index0, u32 thread_index)
225 {
226   udp_header_t * udp0 = ip4_next_header (ip0);
227   snat_session_key_t key0, sm0;
228   clib_bihash_kv_8_8_t kv0, value0;
229
230   key0.addr = ip0->dst_address;
231   key0.port = udp0->dst_port;
232   key0.protocol = proto0;
233   key0.fib_index = sm->outside_fib_index;
234   kv0.key = key0.as_u64;
235
236   /* NAT packet aimed at external address if */
237   /* has active sessions */
238   if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
239                               &value0))
240     {
241       /* or is static mappings */
242       if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
243         return 0;
244     }
245   else
246     return 0;
247
248   if (sm->forwarding_enabled)
249     return 1;
250
251   return snat_not_translate_fast(sm, node, sw_if_index0, ip0, proto0,
252                                  rx_fib_index0);
253 }
254
255 static inline int
256 nat_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip0,
257                                   u32 proto0, u16 src_port, u16 dst_port,
258                                   u32 thread_index, u32 sw_if_index)
259 {
260   snat_session_key_t key0;
261   clib_bihash_kv_8_8_t kv0, value0;
262   snat_interface_t *i;
263
264   /* src NAT check */
265   key0.addr = ip0->src_address;
266   key0.port = src_port;
267   key0.protocol = proto0;
268   key0.fib_index = sm->outside_fib_index;
269   kv0.key = key0.as_u64;
270
271   if (!clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
272                                &value0))
273     return 1;
274
275   /* dst NAT check */
276   key0.addr = ip0->dst_address;
277   key0.port = dst_port;
278   key0.protocol = proto0;
279   key0.fib_index = sm->inside_fib_index;
280   kv0.key = key0.as_u64;
281   if (!clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0,
282                                &value0))
283   {
284     /* hairpinning */
285     pool_foreach (i, sm->output_feature_interfaces,
286     ({
287       if ((nat_interface_is_inside(i)) && (sw_if_index == i->sw_if_index))
288         return 0;
289     }));
290     return 1;
291   }
292
293   return 0;
294 }
295
296 static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
297                       ip4_header_t * ip0,
298                       u32 rx_fib_index0,
299                       snat_session_key_t * key0,
300                       snat_session_t ** sessionp,
301                       vlib_node_runtime_t * node,
302                       u32 next0,
303                       u32 thread_index)
304 {
305   snat_user_t *u;
306   snat_session_t *s;
307   clib_bihash_kv_8_8_t kv0;
308   snat_session_key_t key1;
309   u32 address_index = ~0;
310   u32 outside_fib_index;
311   uword * p;
312   udp_header_t * udp0 = ip4_next_header (ip0);
313
314   if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
315     {
316       b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
317       nat_ipfix_logging_max_sessions(sm->max_translations);
318       return SNAT_IN2OUT_NEXT_DROP;
319     }
320
321   p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->outside_vrf_id);
322   if (! p)
323     {
324       b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_OUTSIDE_FIB];
325       return SNAT_IN2OUT_NEXT_DROP;
326     }
327   outside_fib_index = p[0];
328
329   key1.protocol = key0->protocol;
330
331   u = nat_user_get_or_create (sm, &ip0->src_address, rx_fib_index0,
332                               thread_index);
333   if (!u)
334     {
335       clib_warning ("create NAT user failed");
336       return SNAT_IN2OUT_NEXT_DROP;
337     }
338
339   /* First try to match static mapping by local address and port */
340   if (snat_static_mapping_match (sm, *key0, &key1, 0, 0, 0))
341     {
342       /* Try to create dynamic translation */
343       if (snat_alloc_outside_address_and_port (sm->addresses, rx_fib_index0,
344                                                thread_index, &key1,
345                                                &address_index,
346                                                sm->port_per_thread,
347                                                sm->per_thread_data[thread_index].snat_thread_index))
348         {
349           b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
350           return SNAT_IN2OUT_NEXT_DROP;
351         }
352       u->nsessions++;
353     }
354   else
355     {
356       u->nstaticsessions++;
357     }
358
359   s = nat_session_alloc_or_recycle (sm, u, thread_index);
360   if (!s)
361     {
362       clib_warning ("create NAT session failed");
363       return SNAT_IN2OUT_NEXT_DROP;
364     }
365
366   if (address_index == ~0)
367     s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
368   s->outside_address_index = address_index;
369   s->in2out = *key0;
370   s->out2in = key1;
371   s->out2in.protocol = key0->protocol;
372   s->out2in.fib_index = outside_fib_index;
373   s->ext_host_addr.as_u32 = ip0->dst_address.as_u32;
374   s->ext_host_port = udp0->dst_port;
375   *sessionp = s;
376
377   /* Add to translation hashes */
378   kv0.key = s->in2out.as_u64;
379   kv0.value = s - sm->per_thread_data[thread_index].sessions;
380   if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0,
381                                1 /* is_add */))
382       clib_warning ("in2out key add failed");
383
384   kv0.key = s->out2in.as_u64;
385   kv0.value = s - sm->per_thread_data[thread_index].sessions;
386
387   if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
388                                1 /* is_add */))
389       clib_warning ("out2in key add failed");
390
391   /* log NAT event */
392   snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32,
393                                       s->out2in.addr.as_u32,
394                                       s->in2out.protocol,
395                                       s->in2out.port,
396                                       s->out2in.port,
397                                       s->in2out.fib_index);
398   return next0;
399 }
400
401 static_always_inline
402 snat_in2out_error_t icmp_get_key(ip4_header_t *ip0,
403                                  snat_session_key_t *p_key0)
404 {
405   icmp46_header_t *icmp0;
406   snat_session_key_t key0;
407   icmp_echo_header_t *echo0, *inner_echo0 = 0;
408   ip4_header_t *inner_ip0 = 0;
409   void *l4_header = 0;
410   icmp46_header_t *inner_icmp0;
411
412   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
413   echo0 = (icmp_echo_header_t *)(icmp0+1);
414
415   if (!icmp_is_error_message (icmp0))
416     {
417       key0.protocol = SNAT_PROTOCOL_ICMP;
418       key0.addr = ip0->src_address;
419       key0.port = echo0->identifier;
420     }
421   else
422     {
423       inner_ip0 = (ip4_header_t *)(echo0+1);
424       l4_header = ip4_next_header (inner_ip0);
425       key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
426       key0.addr = inner_ip0->dst_address;
427       switch (key0.protocol)
428         {
429         case SNAT_PROTOCOL_ICMP:
430           inner_icmp0 = (icmp46_header_t*)l4_header;
431           inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
432           key0.port = inner_echo0->identifier;
433           break;
434         case SNAT_PROTOCOL_UDP:
435         case SNAT_PROTOCOL_TCP:
436           key0.port = ((tcp_udp_header_t*)l4_header)->dst_port;
437           break;
438         default:
439           return SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL;
440         }
441     }
442   *p_key0 = key0;
443   return -1; /* success */
444 }
445
446 static_always_inline int
447 icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0)
448 {
449   icmp46_header_t *icmp0;
450   nat_ed_ses_key_t key0;
451   icmp_echo_header_t *echo0, *inner_echo0 = 0;
452   ip4_header_t *inner_ip0 = 0;
453   void *l4_header = 0;
454   icmp46_header_t *inner_icmp0;
455
456   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
457   echo0 = (icmp_echo_header_t *)(icmp0+1);
458
459   if (!icmp_is_error_message (icmp0))
460     {
461       key0.proto = IP_PROTOCOL_ICMP;
462       key0.l_addr = ip0->src_address;
463       key0.r_addr = ip0->dst_address;
464       key0.l_port = key0.r_port = echo0->identifier;
465     }
466   else
467     {
468       inner_ip0 = (ip4_header_t *)(echo0+1);
469       l4_header = ip4_next_header (inner_ip0);
470       key0.proto = inner_ip0->protocol;
471       key0.r_addr = inner_ip0->src_address;
472       key0.l_addr = inner_ip0->dst_address;
473       switch (ip_proto_to_snat_proto (inner_ip0->protocol))
474         {
475         case SNAT_PROTOCOL_ICMP:
476           inner_icmp0 = (icmp46_header_t*)l4_header;
477           inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
478           key0.r_port = key0.l_port = inner_echo0->identifier;
479           break;
480         case SNAT_PROTOCOL_UDP:
481         case SNAT_PROTOCOL_TCP:
482           key0.l_port = ((tcp_udp_header_t*)l4_header)->dst_port;
483           key0.r_port = ((tcp_udp_header_t*)l4_header)->src_port;
484           break;
485         default:
486           return SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL;
487         }
488     }
489   *p_key0 = key0;
490   return 0;
491 }
492
493 static inline int
494 nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip)
495 {
496   nat_ed_ses_key_t key;
497   clib_bihash_kv_16_8_t kv, value;
498   udp_header_t *udp;
499
500   if (!sm->forwarding_enabled)
501     return 0;
502
503   if (ip->protocol == IP_PROTOCOL_ICMP)
504     {
505       if (icmp_get_ed_key (ip, &key))
506         return 0;
507     }
508   else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
509     {
510       udp = ip4_next_header(ip);
511       key.l_addr = ip->src_address;
512       key.r_addr = ip->dst_address;
513       key.proto = ip->protocol;
514       key.r_port = udp->dst_port;
515       key.l_port = udp->src_port;
516     }
517   else
518     {
519       key.l_addr = ip->src_address;
520       key.r_addr = ip->dst_address;
521       key.proto = ip->protocol;
522       key.l_port = key.r_port = 0;
523     }
524   key.fib_index = 0;
525   kv.key[0] = key.as_u64[0];
526   kv.key[1] = key.as_u64[1];
527
528   if (!clib_bihash_search_16_8 (&sm->in2out_ed, &kv, &value))
529     return value.value == ~0ULL;
530
531   return 0;
532 }
533
534 /**
535  * Get address and port values to be used for ICMP packet translation
536  * and create session if needed
537  *
538  * @param[in,out] sm             NAT main
539  * @param[in,out] node           NAT node runtime
540  * @param[in] thread_index       thread index
541  * @param[in,out] b0             buffer containing packet to be translated
542  * @param[out] p_proto           protocol used for matching
543  * @param[out] p_value           address and port after NAT translation
544  * @param[out] p_dont_translate  if packet should not be translated
545  * @param d                      optional parameter
546  * @param e                      optional parameter
547  */
548 u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node,
549                            u32 thread_index, vlib_buffer_t *b0,
550                            ip4_header_t *ip0, u8 *p_proto,
551                            snat_session_key_t *p_value,
552                            u8 *p_dont_translate, void *d, void *e)
553 {
554   icmp46_header_t *icmp0;
555   u32 sw_if_index0;
556   u32 rx_fib_index0;
557   snat_session_key_t key0;
558   snat_session_t *s0 = 0;
559   u8 dont_translate = 0;
560   clib_bihash_kv_8_8_t kv0, value0;
561   u32 next0 = ~0;
562   int err;
563
564   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
565   sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
566   rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
567
568   err = icmp_get_key (ip0, &key0);
569   if (err != -1)
570     {
571       b0->error = node->errors[err];
572       next0 = SNAT_IN2OUT_NEXT_DROP;
573       goto out;
574     }
575   key0.fib_index = rx_fib_index0;
576
577   kv0.key = key0.as_u64;
578
579   if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0,
580                               &value0))
581     {
582       if (vnet_buffer(b0)->sw_if_index[VLIB_TX] != ~0)
583         {
584           if (PREDICT_FALSE(nat_not_translate_output_feature(sm,
585               ip0, SNAT_PROTOCOL_ICMP, key0.port, key0.port, thread_index, sw_if_index0)))
586             {
587               dont_translate = 1;
588               goto out;
589             }
590         }
591       else
592         {
593           if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0,
594               ip0, SNAT_PROTOCOL_ICMP, rx_fib_index0, thread_index)))
595             {
596               dont_translate = 1;
597               goto out;
598             }
599         }
600
601       if (PREDICT_FALSE(icmp_is_error_message (icmp0)))
602         {
603           b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
604           next0 = SNAT_IN2OUT_NEXT_DROP;
605           goto out;
606         }
607
608       next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
609                          &s0, node, next0, thread_index);
610
611       if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
612         goto out;
613     }
614   else
615     {
616       if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request &&
617                         icmp0->type != ICMP4_echo_reply &&
618                         !icmp_is_error_message (icmp0)))
619         {
620           b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
621           next0 = SNAT_IN2OUT_NEXT_DROP;
622           goto out;
623         }
624
625       if (PREDICT_FALSE (value0.value == ~0ULL))
626         {
627           nat_ed_ses_key_t key;
628           clib_bihash_kv_16_8_t s_kv, s_value;
629
630           key.as_u64[0] = 0;
631           key.as_u64[1] = 0;
632           if (icmp_get_ed_key (ip0, &key))
633             {
634               b0->error = node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
635               next0 = SNAT_IN2OUT_NEXT_DROP;
636               goto out;
637             }
638           key.fib_index = rx_fib_index0;
639           s_kv.key[0] = key.as_u64[0];
640           s_kv.key[1] = key.as_u64[1];
641           if (!clib_bihash_search_16_8 (&sm->in2out_ed, &s_kv, &s_value))
642             s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
643                                     s_value.value);
644           else
645            {
646               next0 = SNAT_IN2OUT_NEXT_DROP;
647               goto out;
648            }
649         }
650       else
651         s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
652                                 value0.value);
653     }
654
655 out:
656   *p_proto = key0.protocol;
657   if (s0)
658     *p_value = s0->out2in;
659   *p_dont_translate = dont_translate;
660   if (d)
661     *(snat_session_t**)d = s0;
662   return next0;
663 }
664
665 /**
666  * Get address and port values to be used for ICMP packet translation
667  *
668  * @param[in] sm                 NAT main
669  * @param[in,out] node           NAT node runtime
670  * @param[in] thread_index       thread index
671  * @param[in,out] b0             buffer containing packet to be translated
672  * @param[out] p_proto           protocol used for matching
673  * @param[out] p_value           address and port after NAT translation
674  * @param[out] p_dont_translate  if packet should not be translated
675  * @param d                      optional parameter
676  * @param e                      optional parameter
677  */
678 u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node,
679                            u32 thread_index, vlib_buffer_t *b0,
680                            ip4_header_t *ip0, u8 *p_proto,
681                            snat_session_key_t *p_value,
682                            u8 *p_dont_translate, void *d, void *e)
683 {
684   icmp46_header_t *icmp0;
685   u32 sw_if_index0;
686   u32 rx_fib_index0;
687   snat_session_key_t key0;
688   snat_session_key_t sm0;
689   u8 dont_translate = 0;
690   u8 is_addr_only;
691   u32 next0 = ~0;
692   int err;
693
694   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
695   sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
696   rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
697
698   err = icmp_get_key (ip0, &key0);
699   if (err != -1)
700     {
701       b0->error = node->errors[err];
702       next0 = SNAT_IN2OUT_NEXT_DROP;
703       goto out2;
704     }
705   key0.fib_index = rx_fib_index0;
706
707   if (snat_static_mapping_match(sm, key0, &sm0, 0, &is_addr_only, 0))
708     {
709       if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0,
710           IP_PROTOCOL_ICMP, rx_fib_index0)))
711         {
712           dont_translate = 1;
713           goto out;
714         }
715
716       if (icmp_is_error_message (icmp0))
717         {
718           next0 = SNAT_IN2OUT_NEXT_DROP;
719           goto out;
720         }
721
722       b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
723       next0 = SNAT_IN2OUT_NEXT_DROP;
724       goto out;
725     }
726
727   if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request &&
728                     (icmp0->type != ICMP4_echo_reply || !is_addr_only) &&
729                     !icmp_is_error_message (icmp0)))
730     {
731       b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
732       next0 = SNAT_IN2OUT_NEXT_DROP;
733       goto out;
734     }
735
736 out:
737   *p_value = sm0;
738 out2:
739   *p_proto = key0.protocol;
740   *p_dont_translate = dont_translate;
741   return next0;
742 }
743
744 static inline u32 icmp_in2out (snat_main_t *sm,
745                                vlib_buffer_t * b0,
746                                ip4_header_t * ip0,
747                                icmp46_header_t * icmp0,
748                                u32 sw_if_index0,
749                                u32 rx_fib_index0,
750                                vlib_node_runtime_t * node,
751                                u32 next0,
752                                u32 thread_index,
753                                void *d,
754                                void *e)
755 {
756   snat_session_key_t sm0;
757   u8 protocol;
758   icmp_echo_header_t *echo0, *inner_echo0 = 0;
759   ip4_header_t *inner_ip0;
760   void *l4_header = 0;
761   icmp46_header_t *inner_icmp0;
762   u8 dont_translate;
763   u32 new_addr0, old_addr0;
764   u16 old_id0, new_id0;
765   ip_csum_t sum0;
766   u16 checksum0;
767   u32 next0_tmp;
768
769   echo0 = (icmp_echo_header_t *)(icmp0+1);
770
771   next0_tmp = sm->icmp_match_in2out_cb(sm, node, thread_index, b0, ip0,
772                                        &protocol, &sm0, &dont_translate, d, e);
773   if (next0_tmp != ~0)
774     next0 = next0_tmp;
775   if (next0 == SNAT_IN2OUT_NEXT_DROP || dont_translate)
776     goto out;
777
778   sum0 = ip_incremental_checksum (0, icmp0,
779                                   ntohs(ip0->length) - ip4_header_bytes (ip0));
780   checksum0 = ~ip_csum_fold (sum0);
781   if (PREDICT_FALSE(checksum0 != 0 && checksum0 != 0xffff))
782     {
783       next0 = SNAT_IN2OUT_NEXT_DROP;
784       goto out;
785     }
786
787   old_addr0 = ip0->src_address.as_u32;
788   new_addr0 = ip0->src_address.as_u32 = sm0.addr.as_u32;
789   if (vnet_buffer(b0)->sw_if_index[VLIB_TX] == ~0)
790     vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
791
792   sum0 = ip0->checksum;
793   sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
794                          src_address /* changed member */);
795   ip0->checksum = ip_csum_fold (sum0);
796
797   if (!icmp_is_error_message (icmp0))
798     {
799       new_id0 = sm0.port;
800       if (PREDICT_FALSE(new_id0 != echo0->identifier))
801         {
802           old_id0 = echo0->identifier;
803           new_id0 = sm0.port;
804           echo0->identifier = new_id0;
805
806           sum0 = icmp0->checksum;
807           sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
808                                  identifier);
809           icmp0->checksum = ip_csum_fold (sum0);
810         }
811     }
812   else
813     {
814       inner_ip0 = (ip4_header_t *)(echo0+1);
815       l4_header = ip4_next_header (inner_ip0);
816
817       if (!ip4_header_checksum_is_valid (inner_ip0))
818         {
819           next0 = SNAT_IN2OUT_NEXT_DROP;
820           goto out;
821         }
822
823       old_addr0 = inner_ip0->dst_address.as_u32;
824       inner_ip0->dst_address = sm0.addr;
825       new_addr0 = inner_ip0->dst_address.as_u32;
826
827       sum0 = icmp0->checksum;
828       sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
829                              dst_address /* changed member */);
830       icmp0->checksum = ip_csum_fold (sum0);
831
832       switch (protocol)
833         {
834           case SNAT_PROTOCOL_ICMP:
835             inner_icmp0 = (icmp46_header_t*)l4_header;
836             inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
837
838             old_id0 = inner_echo0->identifier;
839             new_id0 = sm0.port;
840             inner_echo0->identifier = new_id0;
841
842             sum0 = icmp0->checksum;
843             sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
844                                    identifier);
845             icmp0->checksum = ip_csum_fold (sum0);
846             break;
847           case SNAT_PROTOCOL_UDP:
848           case SNAT_PROTOCOL_TCP:
849             old_id0 = ((tcp_udp_header_t*)l4_header)->dst_port;
850             new_id0 = sm0.port;
851             ((tcp_udp_header_t*)l4_header)->dst_port = new_id0;
852
853             sum0 = icmp0->checksum;
854             sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
855                                    dst_port);
856             icmp0->checksum = ip_csum_fold (sum0);
857             break;
858           default:
859             ASSERT(0);
860         }
861     }
862
863 out:
864   return next0;
865 }
866
867 /**
868  * @brief Hairpinning
869  *
870  * Hairpinning allows two endpoints on the internal side of the NAT to
871  * communicate even if they only use each other's external IP addresses
872  * and ports.
873  *
874  * @param sm     NAT main.
875  * @param b0     Vlib buffer.
876  * @param ip0    IP header.
877  * @param udp0   UDP header.
878  * @param tcp0   TCP header.
879  * @param proto0 NAT protocol.
880  */
881 static inline int
882 snat_hairpinning (snat_main_t *sm,
883                   vlib_buffer_t * b0,
884                   ip4_header_t * ip0,
885                   udp_header_t * udp0,
886                   tcp_header_t * tcp0,
887                   u32 proto0)
888 {
889   snat_session_key_t key0, sm0;
890   snat_session_t * s0;
891   clib_bihash_kv_8_8_t kv0, value0;
892   ip_csum_t sum0;
893   u32 new_dst_addr0 = 0, old_dst_addr0, ti = 0, si;
894   u16 new_dst_port0, old_dst_port0;
895
896   key0.addr = ip0->dst_address;
897   key0.port = udp0->dst_port;
898   key0.protocol = proto0;
899   key0.fib_index = sm->outside_fib_index;
900   kv0.key = key0.as_u64;
901
902   /* Check if destination is static mappings */
903   if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
904     {
905       new_dst_addr0 = sm0.addr.as_u32;
906       new_dst_port0 = sm0.port;
907       vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
908     }
909   /* or active session */
910   else
911     {
912       if (sm->num_workers > 1)
913         ti = (clib_net_to_host_u16 (udp0->dst_port) - 1024) / sm->port_per_thread;
914       else
915         ti = sm->num_workers;
916
917       if (!clib_bihash_search_8_8 (&sm->per_thread_data[ti].out2in, &kv0, &value0))
918         {
919           si = value0.value;
920
921           s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si);
922           new_dst_addr0 = s0->in2out.addr.as_u32;
923           new_dst_port0 = s0->in2out.port;
924           vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
925         }
926     }
927
928   /* Destination is behind the same NAT, use internal address and port */
929   if (new_dst_addr0)
930     {
931       old_dst_addr0 = ip0->dst_address.as_u32;
932       ip0->dst_address.as_u32 = new_dst_addr0;
933       sum0 = ip0->checksum;
934       sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
935                              ip4_header_t, dst_address);
936       ip0->checksum = ip_csum_fold (sum0);
937
938       old_dst_port0 = tcp0->dst;
939       if (PREDICT_TRUE(new_dst_port0 != old_dst_port0))
940         {
941           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
942             {
943               tcp0->dst = new_dst_port0;
944               sum0 = tcp0->checksum;
945               sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
946                                      ip4_header_t, dst_address);
947               sum0 = ip_csum_update (sum0, old_dst_port0, new_dst_port0,
948                                      ip4_header_t /* cheat */, length);
949               tcp0->checksum = ip_csum_fold(sum0);
950             }
951           else
952             {
953               udp0->dst_port = new_dst_port0;
954               udp0->checksum = 0;
955             }
956         }
957       else
958         {
959           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
960             {
961               sum0 = tcp0->checksum;
962               sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
963                                      ip4_header_t, dst_address);
964               tcp0->checksum = ip_csum_fold(sum0);
965             }
966         }
967       return 1;
968     }
969   return 0;
970 }
971
972 static inline void
973 snat_icmp_hairpinning (snat_main_t *sm,
974                        vlib_buffer_t * b0,
975                        ip4_header_t * ip0,
976                        icmp46_header_t * icmp0)
977 {
978   snat_session_key_t key0, sm0;
979   clib_bihash_kv_8_8_t kv0, value0;
980   u32 new_dst_addr0 = 0, old_dst_addr0, si, ti = 0;
981   ip_csum_t sum0;
982   snat_session_t *s0;
983
984   if (!icmp_is_error_message (icmp0))
985     {
986       icmp_echo_header_t *echo0 = (icmp_echo_header_t *)(icmp0+1);
987       u16 icmp_id0 = echo0->identifier;
988       key0.addr = ip0->dst_address;
989       key0.port = icmp_id0;
990       key0.protocol = SNAT_PROTOCOL_ICMP;
991       key0.fib_index = sm->outside_fib_index;
992       kv0.key = key0.as_u64;
993
994       if (sm->num_workers > 1)
995         ti = (clib_net_to_host_u16 (icmp_id0) - 1024) / sm->port_per_thread;
996       else
997         ti = sm->num_workers;
998
999       /* Check if destination is in active sessions */
1000       if (clib_bihash_search_8_8 (&sm->per_thread_data[ti].out2in, &kv0,
1001                                   &value0))
1002         {
1003           /* or static mappings */
1004           if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
1005             {
1006               new_dst_addr0 = sm0.addr.as_u32;
1007               vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
1008             }
1009         }
1010       else
1011         {
1012           si = value0.value;
1013
1014           s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si);
1015           new_dst_addr0 = s0->in2out.addr.as_u32;
1016           vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1017           echo0->identifier = s0->in2out.port;
1018           sum0 = icmp0->checksum;
1019           sum0 = ip_csum_update (sum0, icmp_id0, s0->in2out.port,
1020                                  icmp_echo_header_t, identifier);
1021           icmp0->checksum = ip_csum_fold (sum0);
1022         }
1023
1024       /* Destination is behind the same NAT, use internal address and port */
1025       if (new_dst_addr0)
1026         {
1027           old_dst_addr0 = ip0->dst_address.as_u32;
1028           ip0->dst_address.as_u32 = new_dst_addr0;
1029           sum0 = ip0->checksum;
1030           sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
1031                                  ip4_header_t, dst_address);
1032           ip0->checksum = ip_csum_fold (sum0);
1033         }
1034     }
1035
1036 }
1037
1038 static inline u32 icmp_in2out_slow_path (snat_main_t *sm,
1039                                          vlib_buffer_t * b0,
1040                                          ip4_header_t * ip0,
1041                                          icmp46_header_t * icmp0,
1042                                          u32 sw_if_index0,
1043                                          u32 rx_fib_index0,
1044                                          vlib_node_runtime_t * node,
1045                                          u32 next0,
1046                                          f64 now,
1047                                          u32 thread_index,
1048                                          snat_session_t ** p_s0)
1049 {
1050   next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1051                       next0, thread_index, p_s0, 0);
1052   snat_session_t * s0 = *p_s0;
1053   if (PREDICT_TRUE(next0 != SNAT_IN2OUT_NEXT_DROP && s0))
1054     {
1055       /* Hairpinning */
1056       if (vnet_buffer(b0)->sw_if_index[VLIB_TX] == 0)
1057         snat_icmp_hairpinning(sm, b0, ip0, icmp0);
1058       /* Accounting */
1059       s0->last_heard = now;
1060       s0->total_pkts++;
1061       s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0);
1062       /* Per-user LRU list maintenance */
1063       clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1064                          s0->per_user_index);
1065       clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1066                           s0->per_user_list_head_index,
1067                           s0->per_user_index);
1068     }
1069   return next0;
1070 }
1071 static inline void
1072 snat_hairpinning_unknown_proto (snat_main_t *sm,
1073                                 vlib_buffer_t * b,
1074                                 ip4_header_t * ip)
1075 {
1076   u32 old_addr, new_addr = 0, ti = 0;
1077   clib_bihash_kv_8_8_t kv, value;
1078   clib_bihash_kv_16_8_t s_kv, s_value;
1079   nat_ed_ses_key_t key;
1080   snat_session_key_t m_key;
1081   snat_static_mapping_t *m;
1082   ip_csum_t sum;
1083   snat_session_t *s;
1084
1085   old_addr = ip->dst_address.as_u32;
1086   key.l_addr.as_u32 = ip->dst_address.as_u32;
1087   key.r_addr.as_u32 = ip->src_address.as_u32;
1088   key.fib_index = sm->outside_fib_index;
1089   key.proto = ip->protocol;
1090   key.r_port = 0;
1091   key.l_port = 0;
1092   s_kv.key[0] = key.as_u64[0];
1093   s_kv.key[1] = key.as_u64[1];
1094   if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
1095     {
1096       m_key.addr = ip->dst_address;
1097       m_key.fib_index = sm->outside_fib_index;
1098       m_key.port = 0;
1099       m_key.protocol = 0;
1100       kv.key = m_key.as_u64;
1101       if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1102         return;
1103
1104       m = pool_elt_at_index (sm->static_mappings, value.value);
1105       if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0)
1106         vnet_buffer(b)->sw_if_index[VLIB_TX] = m->fib_index;
1107       new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
1108     }
1109   else
1110     {
1111       if (sm->num_workers > 1)
1112         ti = sm->worker_out2in_cb (ip, sm->outside_fib_index);
1113       else
1114         ti = sm->num_workers;
1115
1116       s = pool_elt_at_index (sm->per_thread_data[ti].sessions, s_value.value);
1117       if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0)
1118         vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
1119       new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
1120     }
1121   sum = ip->checksum;
1122   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
1123   ip->checksum = ip_csum_fold (sum);
1124 }
1125
1126 static snat_session_t *
1127 snat_in2out_unknown_proto (snat_main_t *sm,
1128                            vlib_buffer_t * b,
1129                            ip4_header_t * ip,
1130                            u32 rx_fib_index,
1131                            u32 thread_index,
1132                            f64 now,
1133                            vlib_main_t * vm,
1134                            vlib_node_runtime_t * node)
1135 {
1136   clib_bihash_kv_8_8_t kv, value;
1137   clib_bihash_kv_16_8_t s_kv, s_value;
1138   snat_static_mapping_t *m;
1139   snat_session_key_t m_key;
1140   u32 old_addr, new_addr = 0;
1141   ip_csum_t sum;
1142   snat_user_t *u;
1143   dlist_elt_t *head, *elt;
1144   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1145   u32 elt_index, head_index, ses_index;
1146   snat_session_t * s;
1147   nat_ed_ses_key_t key;
1148   u32 address_index = ~0;
1149   int i;
1150   u8 is_sm = 0;
1151
1152   old_addr = ip->src_address.as_u32;
1153
1154   key.l_addr = ip->src_address;
1155   key.r_addr = ip->dst_address;
1156   key.fib_index = rx_fib_index;
1157   key.proto = ip->protocol;
1158   key.l_port = 0;
1159   key.r_port = 0;
1160   s_kv.key[0] = key.as_u64[0];
1161   s_kv.key[1] = key.as_u64[1];
1162
1163   if (!clib_bihash_search_16_8 (&sm->in2out_ed, &s_kv, &s_value))
1164     {
1165       s = pool_elt_at_index (tsm->sessions, s_value.value);
1166       new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
1167     }
1168   else
1169     {
1170       if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
1171         {
1172           b->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
1173           nat_ipfix_logging_max_sessions(sm->max_translations);
1174           return 0;
1175         }
1176
1177       u = nat_user_get_or_create (sm, &ip->src_address, rx_fib_index,
1178                                   thread_index);
1179       if (!u)
1180         {
1181           clib_warning ("create NAT user failed");
1182           return 0;
1183         }
1184
1185       m_key.addr = ip->src_address;
1186       m_key.port = 0;
1187       m_key.protocol = 0;
1188       m_key.fib_index = rx_fib_index;
1189       kv.key = m_key.as_u64;
1190
1191       /* Try to find static mapping first */
1192       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
1193         {
1194           m = pool_elt_at_index (sm->static_mappings, value.value);
1195           new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
1196           is_sm = 1;
1197           goto create_ses;
1198         }
1199       /* Fallback to 3-tuple key */
1200       else
1201         {
1202           /* Choose same out address as for TCP/UDP session to same destination */
1203           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1204             {
1205               head_index = u->sessions_per_user_list_head_index;
1206               head = pool_elt_at_index (tsm->list_pool, head_index);
1207               elt_index = head->next;
1208               elt = pool_elt_at_index (tsm->list_pool, elt_index);
1209               ses_index = elt->value;
1210               while (ses_index != ~0)
1211                 {
1212                   s =  pool_elt_at_index (tsm->sessions, ses_index);
1213                   elt_index = elt->next;
1214                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
1215                   ses_index = elt->value;
1216
1217                   if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32)
1218                     {
1219                       new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
1220                       address_index = s->outside_address_index;
1221
1222                       key.fib_index = sm->outside_fib_index;
1223                       key.l_addr.as_u32 = new_addr;
1224                       s_kv.key[0] = key.as_u64[0];
1225                       s_kv.key[1] = key.as_u64[1];
1226                       if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
1227                         break;
1228
1229                       goto create_ses;
1230                     }
1231                 }
1232             }
1233           key.fib_index = sm->outside_fib_index;
1234           for (i = 0; i < vec_len (sm->addresses); i++)
1235             {
1236               key.l_addr.as_u32 = sm->addresses[i].addr.as_u32;
1237               s_kv.key[0] = key.as_u64[0];
1238               s_kv.key[1] = key.as_u64[1];
1239               if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
1240                 {
1241                   new_addr = ip->src_address.as_u32 = key.l_addr.as_u32;
1242                   address_index = i;
1243                   goto create_ses;
1244                 }
1245             }
1246           return 0;
1247         }
1248
1249 create_ses:
1250       s = nat_session_alloc_or_recycle (sm, u, thread_index);
1251       if (!s)
1252         {
1253           clib_warning ("create NAT session failed");
1254           return 0;
1255         }
1256
1257       s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
1258       s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
1259       s->outside_address_index = address_index;
1260       s->out2in.addr.as_u32 = new_addr;
1261       s->out2in.fib_index = sm->outside_fib_index;
1262       s->in2out.addr.as_u32 = old_addr;
1263       s->in2out.fib_index = rx_fib_index;
1264       s->in2out.port = s->out2in.port = ip->protocol;
1265       if (is_sm)
1266         {
1267           u->nstaticsessions++;
1268           s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
1269         }
1270       else
1271         {
1272           u->nsessions++;
1273         }
1274
1275       /* Add to lookup tables */
1276       key.l_addr.as_u32 = old_addr;
1277       key.r_addr = ip->dst_address;
1278       key.proto = ip->protocol;
1279       key.fib_index = rx_fib_index;
1280       s_kv.key[0] = key.as_u64[0];
1281       s_kv.key[1] = key.as_u64[1];
1282       s_kv.value = s - tsm->sessions;
1283       if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
1284         clib_warning ("in2out key add failed");
1285
1286       key.l_addr.as_u32 = new_addr;
1287       key.fib_index = sm->outside_fib_index;
1288       s_kv.key[0] = key.as_u64[0];
1289       s_kv.key[1] = key.as_u64[1];
1290       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
1291         clib_warning ("out2in key add failed");
1292   }
1293
1294   /* Update IP checksum */
1295   sum = ip->checksum;
1296   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
1297   ip->checksum = ip_csum_fold (sum);
1298
1299   /* Accounting */
1300   s->last_heard = now;
1301   s->total_pkts++;
1302   s->total_bytes += vlib_buffer_length_in_chain (vm, b);
1303   /* Per-user LRU list maintenance */
1304   clib_dlist_remove (tsm->list_pool, s->per_user_index);
1305   clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
1306                       s->per_user_index);
1307
1308   /* Hairpinning */
1309   if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0)
1310     snat_hairpinning_unknown_proto(sm, b, ip);
1311
1312   if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0)
1313     vnet_buffer(b)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
1314
1315   return s;
1316 }
1317
1318 static snat_session_t *
1319 snat_in2out_lb (snat_main_t *sm,
1320                 vlib_buffer_t * b,
1321                 ip4_header_t * ip,
1322                 u32 rx_fib_index,
1323                 u32 thread_index,
1324                 f64 now,
1325                 vlib_main_t * vm,
1326                 vlib_node_runtime_t * node)
1327 {
1328   nat_ed_ses_key_t key;
1329   clib_bihash_kv_16_8_t s_kv, s_value;
1330   udp_header_t *udp = ip4_next_header (ip);
1331   tcp_header_t *tcp = (tcp_header_t *) udp;
1332   snat_session_t *s = 0;
1333   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1334   u32 old_addr, new_addr;
1335   u16 new_port, old_port;
1336   ip_csum_t sum;
1337   u32 proto = ip_proto_to_snat_proto (ip->protocol);
1338   snat_session_key_t e_key, l_key;
1339   snat_user_t *u;
1340
1341   old_addr = ip->src_address.as_u32;
1342
1343   key.l_addr = ip->src_address;
1344   key.r_addr = ip->dst_address;
1345   key.fib_index = rx_fib_index;
1346   key.proto = ip->protocol;
1347   key.r_port = udp->dst_port;
1348   key.l_port = udp->src_port;
1349   s_kv.key[0] = key.as_u64[0];
1350   s_kv.key[1] = key.as_u64[1];
1351
1352   if (!clib_bihash_search_16_8 (&sm->in2out_ed, &s_kv, &s_value))
1353     {
1354       if (s_value.value == ~0ULL)
1355         return 0;
1356       s = pool_elt_at_index (tsm->sessions, s_value.value);
1357     }
1358   else
1359     {
1360       if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
1361         {
1362           b->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
1363           nat_ipfix_logging_max_sessions(sm->max_translations);
1364           return 0;
1365         }
1366
1367       l_key.addr = ip->src_address;
1368       l_key.port = udp->src_port;
1369       l_key.protocol = proto;
1370       l_key.fib_index = rx_fib_index;
1371       if (snat_static_mapping_match(sm, l_key, &e_key, 0, 0, 0))
1372         return 0;
1373
1374       u = nat_user_get_or_create (sm, &ip->src_address, rx_fib_index,
1375                                   thread_index);
1376       if (!u)
1377         {
1378           clib_warning ("create NAT user failed");
1379           return 0;
1380         }
1381
1382       s = nat_session_alloc_or_recycle (sm, u, thread_index);
1383       if (!s)
1384         {
1385           clib_warning ("create NAT session failed");
1386           return 0;
1387         }
1388
1389       s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
1390       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
1391       s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
1392       s->outside_address_index = ~0;
1393       s->in2out = l_key;
1394       s->out2in = e_key;
1395       s->out2in.protocol = l_key.protocol;
1396       u->nstaticsessions++;
1397
1398       /* Add to lookup tables */
1399       s_kv.value = s - tsm->sessions;
1400       if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
1401         clib_warning ("in2out-ed key add failed");
1402
1403       key.l_addr = e_key.addr;
1404       key.fib_index = e_key.fib_index;
1405       key.l_port = e_key.port;
1406       s_kv.key[0] = key.as_u64[0];
1407       s_kv.key[1] = key.as_u64[1];
1408       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
1409         clib_warning ("out2in-ed key add failed");
1410     }
1411
1412   new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
1413
1414   /* Update IP checksum */
1415   sum = ip->checksum;
1416   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
1417   if (is_twice_nat_session (s))
1418     sum = ip_csum_update (sum, ip->dst_address.as_u32,
1419                           s->ext_host_addr.as_u32, ip4_header_t, dst_address);
1420   ip->checksum = ip_csum_fold (sum);
1421
1422   if (PREDICT_TRUE(proto == SNAT_PROTOCOL_TCP))
1423     {
1424       old_port = tcp->src_port;
1425       tcp->src_port = s->out2in.port;
1426       new_port = tcp->src_port;
1427
1428       sum = tcp->checksum;
1429       sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
1430       sum = ip_csum_update (sum, old_port, new_port, ip4_header_t, length);
1431       if (is_twice_nat_session (s))
1432         {
1433           sum = ip_csum_update (sum, ip->dst_address.as_u32,
1434                                 s->ext_host_addr.as_u32, ip4_header_t,
1435                                 dst_address);
1436           sum = ip_csum_update (sum, tcp->dst_port, s->ext_host_port,
1437                                 ip4_header_t, length);
1438           tcp->dst_port = s->ext_host_port;
1439           ip->dst_address.as_u32 = s->ext_host_addr.as_u32;
1440         }
1441       tcp->checksum = ip_csum_fold(sum);
1442     }
1443   else
1444     {
1445       udp->src_port = s->out2in.port;
1446       if (is_twice_nat_session (s))
1447         {
1448           udp->dst_port = s->ext_host_port;
1449           ip->dst_address.as_u32 = s->ext_host_addr.as_u32;
1450         }
1451       udp->checksum = 0;
1452     }
1453
1454   if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0)
1455     vnet_buffer(b)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
1456
1457   /* Accounting */
1458   s->last_heard = now;
1459   s->total_pkts++;
1460   s->total_bytes += vlib_buffer_length_in_chain (vm, b);
1461   /* Per-user LRU list maintenance */
1462   clib_dlist_remove (tsm->list_pool, s->per_user_index);
1463   clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
1464                       s->per_user_index);
1465   return s;
1466 }
1467
1468 static inline uword
1469 snat_in2out_node_fn_inline (vlib_main_t * vm,
1470                             vlib_node_runtime_t * node,
1471                             vlib_frame_t * frame, int is_slow_path,
1472                             int is_output_feature)
1473 {
1474   u32 n_left_from, * from, * to_next;
1475   snat_in2out_next_t next_index;
1476   u32 pkts_processed = 0;
1477   snat_main_t * sm = &snat_main;
1478   f64 now = vlib_time_now (vm);
1479   u32 stats_node_index;
1480   u32 thread_index = vlib_get_thread_index ();
1481
1482   stats_node_index = is_slow_path ? snat_in2out_slowpath_node.index :
1483     snat_in2out_node.index;
1484
1485   from = vlib_frame_vector_args (frame);
1486   n_left_from = frame->n_vectors;
1487   next_index = node->cached_next_index;
1488
1489   while (n_left_from > 0)
1490     {
1491       u32 n_left_to_next;
1492
1493       vlib_get_next_frame (vm, node, next_index,
1494                            to_next, n_left_to_next);
1495
1496       while (n_left_from >= 4 && n_left_to_next >= 2)
1497         {
1498           u32 bi0, bi1;
1499           vlib_buffer_t * b0, * b1;
1500           u32 next0, next1;
1501           u32 sw_if_index0, sw_if_index1;
1502           ip4_header_t * ip0, * ip1;
1503           ip_csum_t sum0, sum1;
1504           u32 new_addr0, old_addr0, new_addr1, old_addr1;
1505           u16 old_port0, new_port0, old_port1, new_port1;
1506           udp_header_t * udp0, * udp1;
1507           tcp_header_t * tcp0, * tcp1;
1508           icmp46_header_t * icmp0, * icmp1;
1509           snat_session_key_t key0, key1;
1510           u32 rx_fib_index0, rx_fib_index1;
1511           u32 proto0, proto1;
1512           snat_session_t * s0 = 0, * s1 = 0;
1513           clib_bihash_kv_8_8_t kv0, value0, kv1, value1;
1514           u32 iph_offset0 = 0, iph_offset1 = 0;
1515
1516           /* Prefetch next iteration. */
1517           {
1518             vlib_buffer_t * p2, * p3;
1519
1520             p2 = vlib_get_buffer (vm, from[2]);
1521             p3 = vlib_get_buffer (vm, from[3]);
1522
1523             vlib_prefetch_buffer_header (p2, LOAD);
1524             vlib_prefetch_buffer_header (p3, LOAD);
1525
1526             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
1527             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
1528           }
1529
1530           /* speculatively enqueue b0 and b1 to the current next frame */
1531           to_next[0] = bi0 = from[0];
1532           to_next[1] = bi1 = from[1];
1533           from += 2;
1534           to_next += 2;
1535           n_left_from -= 2;
1536           n_left_to_next -= 2;
1537
1538           b0 = vlib_get_buffer (vm, bi0);
1539           b1 = vlib_get_buffer (vm, bi1);
1540
1541           if (is_output_feature)
1542             iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1543
1544           ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1545                  iph_offset0);
1546
1547           udp0 = ip4_next_header (ip0);
1548           tcp0 = (tcp_header_t *) udp0;
1549           icmp0 = (icmp46_header_t *) udp0;
1550
1551           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1552           rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1553                                    sw_if_index0);
1554
1555           next0 = next1 = SNAT_IN2OUT_NEXT_LOOKUP;
1556
1557           if (PREDICT_FALSE(ip0->ttl == 1))
1558             {
1559               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1560               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1561                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1562                                            0);
1563               next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
1564               goto trace00;
1565             }
1566
1567           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1568
1569           /* Next configured feature, probably ip4-lookup */
1570           if (is_slow_path)
1571             {
1572               if (PREDICT_FALSE (proto0 == ~0))
1573                 {
1574                   s0 = snat_in2out_unknown_proto (sm, b0, ip0, rx_fib_index0,
1575                                                   thread_index, now, vm, node);
1576                   if (!s0)
1577                     next0 = SNAT_IN2OUT_NEXT_DROP;
1578                   goto trace00;
1579                 }
1580
1581               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1582                 {
1583                   next0 = icmp_in2out_slow_path
1584                     (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
1585                      node, next0, now, thread_index, &s0);
1586                   goto trace00;
1587                 }
1588             }
1589           else
1590             {
1591               if (is_output_feature)
1592                 {
1593                   if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip0)))
1594                     goto trace00;
1595                 }
1596
1597               if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP))
1598                 {
1599                   next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1600                   goto trace00;
1601                 }
1602
1603               if (ip4_is_fragment (ip0))
1604                 {
1605                   next0 = SNAT_IN2OUT_NEXT_REASS;
1606                   goto trace00;
1607                 }
1608             }
1609
1610           key0.addr = ip0->src_address;
1611           key0.port = udp0->src_port;
1612           key0.protocol = proto0;
1613           key0.fib_index = rx_fib_index0;
1614
1615           kv0.key = key0.as_u64;
1616
1617           if (PREDICT_FALSE (clib_bihash_search_8_8 (
1618               &sm->per_thread_data[thread_index].in2out, &kv0, &value0) != 0))
1619             {
1620               if (is_slow_path)
1621                 {
1622                   if (is_output_feature)
1623                     {
1624                       if (PREDICT_FALSE(nat_not_translate_output_feature(sm,
1625                           ip0, proto0, udp0->src_port, udp0->dst_port, thread_index, sw_if_index0)))
1626                         goto trace00;
1627                     }
1628                   else
1629                     {
1630                       if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0,
1631                           ip0, proto0, rx_fib_index0, thread_index)))
1632                         goto trace00;
1633                     }
1634
1635                   next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
1636                                      &s0, node, next0, thread_index);
1637                   if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
1638                     goto trace00;
1639                 }
1640               else
1641                 {
1642                   next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1643                   goto trace00;
1644                 }
1645             }
1646           else
1647             {
1648               if (PREDICT_FALSE (value0.value == ~0ULL))
1649                 {
1650                   if (is_slow_path)
1651                     {
1652                       s0 = snat_in2out_lb(sm, b0, ip0, rx_fib_index0,
1653                                           thread_index, now, vm, node);
1654                       if (!s0 && !sm->forwarding_enabled)
1655                         next0 = SNAT_IN2OUT_NEXT_DROP;
1656                       goto trace00;
1657                     }
1658                   else
1659                     {
1660                       next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1661                       goto trace00;
1662                     }
1663                 }
1664               else
1665                 {
1666                   s0 = pool_elt_at_index (
1667                     sm->per_thread_data[thread_index].sessions,
1668                     value0.value);
1669                 }
1670             }
1671
1672           b0->flags |= VNET_BUFFER_F_IS_NATED;
1673
1674           old_addr0 = ip0->src_address.as_u32;
1675           ip0->src_address = s0->out2in.addr;
1676           new_addr0 = ip0->src_address.as_u32;
1677           if (!is_output_feature)
1678             vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1679
1680           sum0 = ip0->checksum;
1681           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1682                                  ip4_header_t,
1683                                  src_address /* changed member */);
1684           ip0->checksum = ip_csum_fold (sum0);
1685
1686           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1687             {
1688               old_port0 = tcp0->src_port;
1689               tcp0->src_port = s0->out2in.port;
1690               new_port0 = tcp0->src_port;
1691
1692               sum0 = tcp0->checksum;
1693               sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1694                                      ip4_header_t,
1695                                      dst_address /* changed member */);
1696               sum0 = ip_csum_update (sum0, old_port0, new_port0,
1697                                      ip4_header_t /* cheat */,
1698                                      length /* changed member */);
1699               tcp0->checksum = ip_csum_fold(sum0);
1700             }
1701           else
1702             {
1703               old_port0 = udp0->src_port;
1704               udp0->src_port = s0->out2in.port;
1705               udp0->checksum = 0;
1706             }
1707
1708           /* Accounting */
1709           s0->last_heard = now;
1710           s0->total_pkts++;
1711           s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1712           /* Per-user LRU list maintenance */
1713           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1714                              s0->per_user_index);
1715           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1716                               s0->per_user_list_head_index,
1717                               s0->per_user_index);
1718         trace00:
1719
1720           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1721                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1722             {
1723               snat_in2out_trace_t *t =
1724                  vlib_add_trace (vm, node, b0, sizeof (*t));
1725               t->is_slow_path = is_slow_path;
1726               t->sw_if_index = sw_if_index0;
1727               t->next_index = next0;
1728                   t->session_index = ~0;
1729               if (s0)
1730                 t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1731             }
1732
1733           pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
1734
1735           if (is_output_feature)
1736             iph_offset1 = vnet_buffer (b1)->ip.save_rewrite_length;
1737
1738           ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) +
1739                  iph_offset1);
1740
1741           udp1 = ip4_next_header (ip1);
1742           tcp1 = (tcp_header_t *) udp1;
1743           icmp1 = (icmp46_header_t *) udp1;
1744
1745           sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1746           rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1747                                    sw_if_index1);
1748
1749           if (PREDICT_FALSE(ip1->ttl == 1))
1750             {
1751               vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1752               icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1753                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1754                                            0);
1755               next1 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
1756               goto trace01;
1757             }
1758
1759           proto1 = ip_proto_to_snat_proto (ip1->protocol);
1760
1761           /* Next configured feature, probably ip4-lookup */
1762           if (is_slow_path)
1763             {
1764               if (PREDICT_FALSE (proto1 == ~0))
1765                 {
1766                   s1 = snat_in2out_unknown_proto (sm, b1, ip1, rx_fib_index1,
1767                                                   thread_index, now, vm, node);
1768                   if (!s1)
1769                     next1 = SNAT_IN2OUT_NEXT_DROP;
1770                   goto trace01;
1771                 }
1772
1773               if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1774                 {
1775                   next1 = icmp_in2out_slow_path
1776                     (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1777                      next1, now, thread_index, &s1);
1778                   goto trace01;
1779                 }
1780             }
1781           else
1782             {
1783               if (is_output_feature)
1784                 {
1785                   if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip1)))
1786                     goto trace01;
1787                 }
1788
1789               if (PREDICT_FALSE (proto1 == ~0 || proto1 == SNAT_PROTOCOL_ICMP))
1790                 {
1791                   next1 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1792                   goto trace01;
1793                 }
1794
1795               if (ip4_is_fragment (ip1))
1796                 {
1797                   next1 = SNAT_IN2OUT_NEXT_REASS;
1798                   goto trace01;
1799                 }
1800             }
1801
1802           key1.addr = ip1->src_address;
1803           key1.port = udp1->src_port;
1804           key1.protocol = proto1;
1805           key1.fib_index = rx_fib_index1;
1806
1807           kv1.key = key1.as_u64;
1808
1809             if (PREDICT_FALSE(clib_bihash_search_8_8 (
1810                 &sm->per_thread_data[thread_index].in2out, &kv1, &value1) != 0))
1811             {
1812               if (is_slow_path)
1813                 {
1814                   if (is_output_feature)
1815                     {
1816                       if (PREDICT_FALSE(nat_not_translate_output_feature(sm,
1817                           ip1, proto1, udp1->src_port, udp1->dst_port, thread_index, sw_if_index1)))
1818                         goto trace01;
1819                     }
1820                   else
1821                     {
1822                       if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index1,
1823                           ip1, proto1, rx_fib_index1, thread_index)))
1824                         goto trace01;
1825                     }
1826
1827                   next1 = slow_path (sm, b1, ip1, rx_fib_index1, &key1,
1828                                      &s1, node, next1, thread_index);
1829                   if (PREDICT_FALSE (next1 == SNAT_IN2OUT_NEXT_DROP))
1830                     goto trace01;
1831                 }
1832               else
1833                 {
1834                   next1 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1835                   goto trace01;
1836                 }
1837             }
1838           else
1839             {
1840               if (PREDICT_FALSE (value1.value == ~0ULL))
1841                 {
1842                   if (is_slow_path)
1843                     {
1844                       s1 = snat_in2out_lb(sm, b1, ip1, rx_fib_index1,
1845                                           thread_index, now, vm, node);
1846                       if (!s1 && !sm->forwarding_enabled)
1847                         next1 = SNAT_IN2OUT_NEXT_DROP;
1848                       goto trace01;
1849                     }
1850                   else
1851                     {
1852                       next1 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1853                       goto trace01;
1854                     }
1855                 }
1856               else
1857                 {
1858                   s1 = pool_elt_at_index (
1859                     sm->per_thread_data[thread_index].sessions,
1860                     value1.value);
1861                 }
1862             }
1863
1864           b1->flags |= VNET_BUFFER_F_IS_NATED;
1865
1866           old_addr1 = ip1->src_address.as_u32;
1867           ip1->src_address = s1->out2in.addr;
1868           new_addr1 = ip1->src_address.as_u32;
1869           if (!is_output_feature)
1870             vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index;
1871
1872           sum1 = ip1->checksum;
1873           sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1874                                  ip4_header_t,
1875                                  src_address /* changed member */);
1876           ip1->checksum = ip_csum_fold (sum1);
1877
1878           if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1879             {
1880               old_port1 = tcp1->src_port;
1881               tcp1->src_port = s1->out2in.port;
1882               new_port1 = tcp1->src_port;
1883
1884               sum1 = tcp1->checksum;
1885               sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1886                                      ip4_header_t,
1887                                      dst_address /* changed member */);
1888               sum1 = ip_csum_update (sum1, old_port1, new_port1,
1889                                      ip4_header_t /* cheat */,
1890                                      length /* changed member */);
1891               tcp1->checksum = ip_csum_fold(sum1);
1892             }
1893           else
1894             {
1895               old_port1 = udp1->src_port;
1896               udp1->src_port = s1->out2in.port;
1897               udp1->checksum = 0;
1898             }
1899
1900           /* Accounting */
1901           s1->last_heard = now;
1902           s1->total_pkts++;
1903           s1->total_bytes += vlib_buffer_length_in_chain (vm, b1);
1904           /* Per-user LRU list maintenance */
1905           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1906                              s1->per_user_index);
1907           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1908                               s1->per_user_list_head_index,
1909                               s1->per_user_index);
1910         trace01:
1911
1912           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1913                             && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1914             {
1915               snat_in2out_trace_t *t =
1916                  vlib_add_trace (vm, node, b1, sizeof (*t));
1917               t->sw_if_index = sw_if_index1;
1918               t->next_index = next1;
1919               t->session_index = ~0;
1920               if (s1)
1921                 t->session_index = s1 - sm->per_thread_data[thread_index].sessions;
1922             }
1923
1924           pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP;
1925
1926           /* verify speculative enqueues, maybe switch current next frame */
1927           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1928                                            to_next, n_left_to_next,
1929                                            bi0, bi1, next0, next1);
1930         }
1931
1932       while (n_left_from > 0 && n_left_to_next > 0)
1933         {
1934           u32 bi0;
1935           vlib_buffer_t * b0;
1936           u32 next0;
1937           u32 sw_if_index0;
1938           ip4_header_t * ip0;
1939           ip_csum_t sum0;
1940           u32 new_addr0, old_addr0;
1941           u16 old_port0, new_port0;
1942           udp_header_t * udp0;
1943           tcp_header_t * tcp0;
1944           icmp46_header_t * icmp0;
1945           snat_session_key_t key0;
1946           u32 rx_fib_index0;
1947           u32 proto0;
1948           snat_session_t * s0 = 0;
1949           clib_bihash_kv_8_8_t kv0, value0;
1950           u32 iph_offset0 = 0;
1951
1952           /* speculatively enqueue b0 to the current next frame */
1953           bi0 = from[0];
1954           to_next[0] = bi0;
1955           from += 1;
1956           to_next += 1;
1957           n_left_from -= 1;
1958           n_left_to_next -= 1;
1959
1960           b0 = vlib_get_buffer (vm, bi0);
1961           next0 = SNAT_IN2OUT_NEXT_LOOKUP;
1962
1963           if (is_output_feature)
1964             iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1965
1966           ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1967                  iph_offset0);
1968
1969           udp0 = ip4_next_header (ip0);
1970           tcp0 = (tcp_header_t *) udp0;
1971           icmp0 = (icmp46_header_t *) udp0;
1972
1973           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1974           rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1975                                    sw_if_index0);
1976
1977           if (PREDICT_FALSE(ip0->ttl == 1))
1978             {
1979               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1980               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1981                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1982                                            0);
1983               next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
1984               goto trace0;
1985             }
1986
1987           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1988
1989           /* Next configured feature, probably ip4-lookup */
1990           if (is_slow_path)
1991             {
1992               if (PREDICT_FALSE (proto0 == ~0))
1993                 {
1994                   s0 = snat_in2out_unknown_proto (sm, b0, ip0, rx_fib_index0,
1995                                                   thread_index, now, vm, node);
1996                   if (!s0)
1997                     next0 = SNAT_IN2OUT_NEXT_DROP;
1998                   goto trace0;
1999                 }
2000
2001               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2002                 {
2003                   next0 = icmp_in2out_slow_path
2004                     (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
2005                      next0, now, thread_index, &s0);
2006                   goto trace0;
2007                 }
2008             }
2009           else
2010             {
2011                if (is_output_feature)
2012                 {
2013                   if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip0)))
2014                     goto trace0;
2015                 }
2016
2017               if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP))
2018                 {
2019                   next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
2020                   goto trace0;
2021                 }
2022
2023               if (ip4_is_fragment (ip0))
2024                 {
2025                   next0 = SNAT_IN2OUT_NEXT_REASS;
2026                   goto trace0;
2027                 }
2028             }
2029
2030           key0.addr = ip0->src_address;
2031           key0.port = udp0->src_port;
2032           key0.protocol = proto0;
2033           key0.fib_index = rx_fib_index0;
2034
2035           kv0.key = key0.as_u64;
2036
2037           if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out,
2038                                       &kv0, &value0))
2039             {
2040               if (is_slow_path)
2041                 {
2042                   if (is_output_feature)
2043                     {
2044                       if (PREDICT_FALSE(nat_not_translate_output_feature(sm,
2045                           ip0, proto0, udp0->src_port, udp0->dst_port, thread_index, sw_if_index0)))
2046                         goto trace0;
2047                     }
2048                   else
2049                     {
2050                       if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0,
2051                           ip0, proto0, rx_fib_index0, thread_index)))
2052                         goto trace0;
2053                     }
2054
2055                   next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
2056                                      &s0, node, next0, thread_index);
2057
2058                   if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
2059                     goto trace0;
2060                 }
2061               else
2062                 {
2063                   next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
2064                   goto trace0;
2065                 }
2066             }
2067           else
2068             {
2069               if (PREDICT_FALSE (value0.value == ~0ULL))
2070                 {
2071                   if (is_slow_path)
2072                     {
2073                       s0 = snat_in2out_lb(sm, b0, ip0, rx_fib_index0,
2074                                           thread_index, now, vm, node);
2075                       if (!s0 && !sm->forwarding_enabled)
2076                         next0 = SNAT_IN2OUT_NEXT_DROP;
2077                       goto trace0;
2078                     }
2079                   else
2080                     {
2081                       next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
2082                       goto trace0;
2083                     }
2084                 }
2085               else
2086                 {
2087                   s0 = pool_elt_at_index (
2088                     sm->per_thread_data[thread_index].sessions,
2089                     value0.value);
2090                 }
2091             }
2092
2093           b0->flags |= VNET_BUFFER_F_IS_NATED;
2094
2095           old_addr0 = ip0->src_address.as_u32;
2096           ip0->src_address = s0->out2in.addr;
2097           new_addr0 = ip0->src_address.as_u32;
2098           if (!is_output_feature)
2099             vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
2100
2101           sum0 = ip0->checksum;
2102           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2103                                  ip4_header_t,
2104                                  src_address /* changed member */);
2105           ip0->checksum = ip_csum_fold (sum0);
2106
2107           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2108             {
2109               old_port0 = tcp0->src_port;
2110               tcp0->src_port = s0->out2in.port;
2111               new_port0 = tcp0->src_port;
2112
2113               sum0 = tcp0->checksum;
2114               sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2115                                      ip4_header_t,
2116                                      dst_address /* changed member */);
2117               sum0 = ip_csum_update (sum0, old_port0, new_port0,
2118                                      ip4_header_t /* cheat */,
2119                                      length /* changed member */);
2120               tcp0->checksum = ip_csum_fold(sum0);
2121             }
2122           else
2123             {
2124               old_port0 = udp0->src_port;
2125               udp0->src_port = s0->out2in.port;
2126               udp0->checksum = 0;
2127             }
2128
2129           /* Accounting */
2130           s0->last_heard = now;
2131           s0->total_pkts++;
2132           s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
2133           /* Per-user LRU list maintenance */
2134           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
2135                              s0->per_user_index);
2136           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
2137                               s0->per_user_list_head_index,
2138                               s0->per_user_index);
2139
2140         trace0:
2141           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2142                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2143             {
2144               snat_in2out_trace_t *t =
2145                  vlib_add_trace (vm, node, b0, sizeof (*t));
2146               t->is_slow_path = is_slow_path;
2147               t->sw_if_index = sw_if_index0;
2148               t->next_index = next0;
2149                   t->session_index = ~0;
2150               if (s0)
2151                 t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
2152             }
2153
2154           pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
2155
2156           /* verify speculative enqueue, maybe switch current next frame */
2157           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2158                                            to_next, n_left_to_next,
2159                                            bi0, next0);
2160         }
2161
2162       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2163     }
2164
2165   vlib_node_increment_counter (vm, stats_node_index,
2166                                SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
2167                                pkts_processed);
2168   return frame->n_vectors;
2169 }
2170
2171 static uword
2172 snat_in2out_fast_path_fn (vlib_main_t * vm,
2173                           vlib_node_runtime_t * node,
2174                           vlib_frame_t * frame)
2175 {
2176   return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */, 0);
2177 }
2178
2179 VLIB_REGISTER_NODE (snat_in2out_node) = {
2180   .function = snat_in2out_fast_path_fn,
2181   .name = "nat44-in2out",
2182   .vector_size = sizeof (u32),
2183   .format_trace = format_snat_in2out_trace,
2184   .type = VLIB_NODE_TYPE_INTERNAL,
2185
2186   .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2187   .error_strings = snat_in2out_error_strings,
2188
2189   .runtime_data_bytes = sizeof (snat_runtime_t),
2190
2191   .n_next_nodes = SNAT_IN2OUT_N_NEXT,
2192
2193   /* edit / add dispositions here */
2194   .next_nodes = {
2195     [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2196     [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2197     [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2198     [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2199     [SNAT_IN2OUT_NEXT_REASS] = "nat44-in2out-reass",
2200   },
2201 };
2202
2203 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_node, snat_in2out_fast_path_fn);
2204
2205 static uword
2206 snat_in2out_output_fast_path_fn (vlib_main_t * vm,
2207                                  vlib_node_runtime_t * node,
2208                                  vlib_frame_t * frame)
2209 {
2210   return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */, 1);
2211 }
2212
2213 VLIB_REGISTER_NODE (snat_in2out_output_node) = {
2214   .function = snat_in2out_output_fast_path_fn,
2215   .name = "nat44-in2out-output",
2216   .vector_size = sizeof (u32),
2217   .format_trace = format_snat_in2out_trace,
2218   .type = VLIB_NODE_TYPE_INTERNAL,
2219
2220   .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2221   .error_strings = snat_in2out_error_strings,
2222
2223   .runtime_data_bytes = sizeof (snat_runtime_t),
2224
2225   .n_next_nodes = SNAT_IN2OUT_N_NEXT,
2226
2227   /* edit / add dispositions here */
2228   .next_nodes = {
2229     [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2230     [SNAT_IN2OUT_NEXT_LOOKUP] = "interface-output",
2231     [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-output-slowpath",
2232     [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2233     [SNAT_IN2OUT_NEXT_REASS] = "nat44-in2out-reass",
2234   },
2235 };
2236
2237 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_output_node,
2238                               snat_in2out_output_fast_path_fn);
2239
2240 static uword
2241 snat_in2out_slow_path_fn (vlib_main_t * vm,
2242                           vlib_node_runtime_t * node,
2243                           vlib_frame_t * frame)
2244 {
2245   return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */, 0);
2246 }
2247
2248 VLIB_REGISTER_NODE (snat_in2out_slowpath_node) = {
2249   .function = snat_in2out_slow_path_fn,
2250   .name = "nat44-in2out-slowpath",
2251   .vector_size = sizeof (u32),
2252   .format_trace = format_snat_in2out_trace,
2253   .type = VLIB_NODE_TYPE_INTERNAL,
2254
2255   .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2256   .error_strings = snat_in2out_error_strings,
2257
2258   .runtime_data_bytes = sizeof (snat_runtime_t),
2259
2260   .n_next_nodes = SNAT_IN2OUT_N_NEXT,
2261
2262   /* edit / add dispositions here */
2263   .next_nodes = {
2264     [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2265     [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2266     [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2267     [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2268     [SNAT_IN2OUT_NEXT_REASS] = "nat44-in2out-reass",
2269   },
2270 };
2271
2272 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_slowpath_node,
2273                               snat_in2out_slow_path_fn);
2274
2275 static uword
2276 snat_in2out_output_slow_path_fn (vlib_main_t * vm,
2277                                  vlib_node_runtime_t * node,
2278                                  vlib_frame_t * frame)
2279 {
2280   return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */, 1);
2281 }
2282
2283 VLIB_REGISTER_NODE (snat_in2out_output_slowpath_node) = {
2284   .function = snat_in2out_output_slow_path_fn,
2285   .name = "nat44-in2out-output-slowpath",
2286   .vector_size = sizeof (u32),
2287   .format_trace = format_snat_in2out_trace,
2288   .type = VLIB_NODE_TYPE_INTERNAL,
2289
2290   .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2291   .error_strings = snat_in2out_error_strings,
2292
2293   .runtime_data_bytes = sizeof (snat_runtime_t),
2294
2295   .n_next_nodes = SNAT_IN2OUT_N_NEXT,
2296
2297   /* edit / add dispositions here */
2298   .next_nodes = {
2299     [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2300     [SNAT_IN2OUT_NEXT_LOOKUP] = "interface-output",
2301     [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-output-slowpath",
2302     [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2303     [SNAT_IN2OUT_NEXT_REASS] = "nat44-in2out-reass",
2304   },
2305 };
2306
2307 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_output_slowpath_node,
2308                               snat_in2out_output_slow_path_fn);
2309
2310 extern vnet_feature_arc_registration_t vnet_feat_arc_ip4_local;
2311
2312 static uword
2313 nat44_hairpinning_fn (vlib_main_t * vm,
2314                       vlib_node_runtime_t * node,
2315                       vlib_frame_t * frame)
2316 {
2317   u32 n_left_from, * from, * to_next;
2318   snat_in2out_next_t next_index;
2319   u32 pkts_processed = 0;
2320   snat_main_t * sm = &snat_main;
2321   vnet_feature_main_t *fm = &feature_main;
2322   u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
2323   vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index];
2324
2325   from = vlib_frame_vector_args (frame);
2326   n_left_from = frame->n_vectors;
2327   next_index = node->cached_next_index;
2328
2329   while (n_left_from > 0)
2330     {
2331       u32 n_left_to_next;
2332
2333       vlib_get_next_frame (vm, node, next_index,
2334                            to_next, n_left_to_next);
2335
2336       while (n_left_from > 0 && n_left_to_next > 0)
2337         {
2338           u32 bi0;
2339           vlib_buffer_t * b0;
2340           u32 next0;
2341           ip4_header_t * ip0;
2342           u32 proto0;
2343           udp_header_t * udp0;
2344           tcp_header_t * tcp0;
2345
2346           /* speculatively enqueue b0 to the current next frame */
2347           bi0 = from[0];
2348           to_next[0] = bi0;
2349           from += 1;
2350           to_next += 1;
2351           n_left_from -= 1;
2352           n_left_to_next -= 1;
2353
2354           b0 = vlib_get_buffer (vm, bi0);
2355           ip0 = vlib_buffer_get_current (b0);
2356           udp0 = ip4_next_header (ip0);
2357           tcp0 = (tcp_header_t *) udp0;
2358
2359           proto0 = ip_proto_to_snat_proto (ip0->protocol);
2360
2361           vnet_get_config_data (&cm->config_main, &b0->current_config_index,
2362                                 &next0, 0);
2363
2364           if (snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0))
2365             next0 = SNAT_IN2OUT_NEXT_LOOKUP;
2366
2367           pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
2368
2369           /* verify speculative enqueue, maybe switch current next frame */
2370           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2371                                            to_next, n_left_to_next,
2372                                            bi0, next0);
2373          }
2374
2375       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2376     }
2377
2378   vlib_node_increment_counter (vm, nat44_hairpinning_node.index,
2379                                SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
2380                                pkts_processed);
2381   return frame->n_vectors;
2382 }
2383
2384 VLIB_REGISTER_NODE (nat44_hairpinning_node) = {
2385   .function = nat44_hairpinning_fn,
2386   .name = "nat44-hairpinning",
2387   .vector_size = sizeof (u32),
2388   .type = VLIB_NODE_TYPE_INTERNAL,
2389   .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2390   .error_strings = snat_in2out_error_strings,
2391   .n_next_nodes = 2,
2392   .next_nodes = {
2393     [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2394     [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2395   },
2396 };
2397
2398 VLIB_NODE_FUNCTION_MULTIARCH (nat44_hairpinning_node,
2399                               nat44_hairpinning_fn);
2400
2401 static inline void
2402 nat44_reass_hairpinning (snat_main_t *sm,
2403                          vlib_buffer_t * b0,
2404                          ip4_header_t * ip0,
2405                          u16 sport,
2406                          u16 dport,
2407                          u32 proto0)
2408 {
2409   snat_session_key_t key0, sm0;
2410   snat_session_t * s0;
2411   clib_bihash_kv_8_8_t kv0, value0;
2412   ip_csum_t sum0;
2413   u32 new_dst_addr0 = 0, old_dst_addr0, ti = 0, si;
2414   u16 new_dst_port0, old_dst_port0;
2415   udp_header_t * udp0;
2416   tcp_header_t * tcp0;
2417
2418   key0.addr = ip0->dst_address;
2419   key0.port = dport;
2420   key0.protocol = proto0;
2421   key0.fib_index = sm->outside_fib_index;
2422   kv0.key = key0.as_u64;
2423
2424   udp0 = ip4_next_header (ip0);
2425
2426   /* Check if destination is static mappings */
2427   if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
2428     {
2429       new_dst_addr0 = sm0.addr.as_u32;
2430       new_dst_port0 = sm0.port;
2431       vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
2432     }
2433   /* or active sessions */
2434   else
2435     {
2436       if (sm->num_workers > 1)
2437         ti = (clib_net_to_host_u16 (udp0->dst_port) - 1024) / sm->port_per_thread;
2438       else
2439         ti = sm->num_workers;
2440
2441       if (!clib_bihash_search_8_8 (&sm->per_thread_data[ti].out2in, &kv0, &value0))
2442         {
2443           si = value0.value;
2444           s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si);
2445           new_dst_addr0 = s0->in2out.addr.as_u32;
2446           new_dst_port0 = s0->in2out.port;
2447           vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
2448         }
2449     }
2450
2451   /* Destination is behind the same NAT, use internal address and port */
2452   if (new_dst_addr0)
2453     {
2454       old_dst_addr0 = ip0->dst_address.as_u32;
2455       ip0->dst_address.as_u32 = new_dst_addr0;
2456       sum0 = ip0->checksum;
2457       sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
2458                              ip4_header_t, dst_address);
2459       ip0->checksum = ip_csum_fold (sum0);
2460
2461       old_dst_port0 = dport;
2462       if (PREDICT_TRUE(new_dst_port0 != old_dst_port0 &&
2463                        ip4_is_first_fragment (ip0)))
2464         {
2465           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2466             {
2467               tcp0 = ip4_next_header (ip0);
2468               tcp0->dst = new_dst_port0;
2469               sum0 = tcp0->checksum;
2470               sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
2471                                      ip4_header_t, dst_address);
2472               sum0 = ip_csum_update (sum0, old_dst_port0, new_dst_port0,
2473                                      ip4_header_t /* cheat */, length);
2474               tcp0->checksum = ip_csum_fold(sum0);
2475             }
2476           else
2477             {
2478               udp0->dst_port = new_dst_port0;
2479               udp0->checksum = 0;
2480             }
2481         }
2482       else
2483         {
2484           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2485             {
2486               tcp0 = ip4_next_header (ip0);
2487               sum0 = tcp0->checksum;
2488               sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
2489                                      ip4_header_t, dst_address);
2490               tcp0->checksum = ip_csum_fold(sum0);
2491             }
2492         }
2493     }
2494 }
2495
2496 static uword
2497 nat44_in2out_reass_node_fn (vlib_main_t * vm,
2498                             vlib_node_runtime_t * node,
2499                             vlib_frame_t * frame)
2500 {
2501   u32 n_left_from, *from, *to_next;
2502   snat_in2out_next_t next_index;
2503   u32 pkts_processed = 0;
2504   snat_main_t *sm = &snat_main;
2505   f64 now = vlib_time_now (vm);
2506   u32 thread_index = vlib_get_thread_index ();
2507   snat_main_per_thread_data_t *per_thread_data =
2508     &sm->per_thread_data[thread_index];
2509   u32 *fragments_to_drop = 0;
2510   u32 *fragments_to_loopback = 0;
2511
2512   from = vlib_frame_vector_args (frame);
2513   n_left_from = frame->n_vectors;
2514   next_index = node->cached_next_index;
2515
2516   while (n_left_from > 0)
2517     {
2518       u32 n_left_to_next;
2519
2520       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2521
2522       while (n_left_from > 0 && n_left_to_next > 0)
2523        {
2524           u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
2525           vlib_buffer_t *b0;
2526           u32 next0;
2527           u8 cached0 = 0;
2528           ip4_header_t *ip0;
2529           nat_reass_ip4_t *reass0;
2530           udp_header_t * udp0;
2531           tcp_header_t * tcp0;
2532           snat_session_key_t key0;
2533           clib_bihash_kv_8_8_t kv0, value0;
2534           snat_session_t * s0 = 0;
2535           u16 old_port0, new_port0;
2536           ip_csum_t sum0;
2537
2538           /* speculatively enqueue b0 to the current next frame */
2539           bi0 = from[0];
2540           to_next[0] = bi0;
2541           from += 1;
2542           to_next += 1;
2543           n_left_from -= 1;
2544           n_left_to_next -= 1;
2545
2546           b0 = vlib_get_buffer (vm, bi0);
2547           next0 = SNAT_IN2OUT_NEXT_LOOKUP;
2548
2549           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2550           rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2551                                                                sw_if_index0);
2552
2553           if (PREDICT_FALSE (nat_reass_is_drop_frag(0)))
2554             {
2555               next0 = SNAT_IN2OUT_NEXT_DROP;
2556               b0->error = node->errors[SNAT_IN2OUT_ERROR_DROP_FRAGMENT];
2557               goto trace0;
2558             }
2559
2560           ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
2561           udp0 = ip4_next_header (ip0);
2562           tcp0 = (tcp_header_t *) udp0;
2563           proto0 = ip_proto_to_snat_proto (ip0->protocol);
2564
2565           reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
2566                                                  ip0->dst_address,
2567                                                  ip0->fragment_id,
2568                                                  ip0->protocol,
2569                                                  1,
2570                                                  &fragments_to_drop);
2571
2572           if (PREDICT_FALSE (!reass0))
2573             {
2574               next0 = SNAT_IN2OUT_NEXT_DROP;
2575               b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_REASS];
2576               goto trace0;
2577             }
2578
2579           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
2580             {
2581               key0.addr = ip0->src_address;
2582               key0.port = udp0->src_port;
2583               key0.protocol = proto0;
2584               key0.fib_index = rx_fib_index0;
2585               kv0.key = key0.as_u64;
2586
2587               if (clib_bihash_search_8_8 (&per_thread_data->in2out, &kv0, &value0))
2588                 {
2589                   if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0,
2590                       ip0, proto0, rx_fib_index0, thread_index)))
2591                     goto trace0;
2592
2593                   next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
2594                                      &s0, node, next0, thread_index);
2595
2596                   if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
2597                     goto trace0;
2598
2599                   reass0->sess_index = s0 - per_thread_data->sessions;
2600                 }
2601               else
2602                 {
2603                   s0 = pool_elt_at_index (per_thread_data->sessions,
2604                                           value0.value);
2605                   reass0->sess_index = value0.value;
2606                 }
2607               nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
2608             }
2609           else
2610             {
2611               if (PREDICT_FALSE (reass0->sess_index == (u32) ~0))
2612                 {
2613                   if (nat_ip4_reass_add_fragment (reass0, bi0))
2614                     {
2615                       b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_FRAG];
2616                       next0 = SNAT_IN2OUT_NEXT_DROP;
2617                       goto trace0;
2618                     }
2619                   cached0 = 1;
2620                   goto trace0;
2621                 }
2622               s0 = pool_elt_at_index (per_thread_data->sessions,
2623                                       reass0->sess_index);
2624             }
2625
2626           old_addr0 = ip0->src_address.as_u32;
2627           ip0->src_address = s0->out2in.addr;
2628           new_addr0 = ip0->src_address.as_u32;
2629           vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
2630
2631           sum0 = ip0->checksum;
2632           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2633                                  ip4_header_t,
2634                                  src_address /* changed member */);
2635           ip0->checksum = ip_csum_fold (sum0);
2636
2637           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
2638             {
2639               if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2640                 {
2641                   old_port0 = tcp0->src_port;
2642                   tcp0->src_port = s0->out2in.port;
2643                   new_port0 = tcp0->src_port;
2644
2645                   sum0 = tcp0->checksum;
2646                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2647                                          ip4_header_t,
2648                                          dst_address /* changed member */);
2649                   sum0 = ip_csum_update (sum0, old_port0, new_port0,
2650                                          ip4_header_t /* cheat */,
2651                                          length /* changed member */);
2652                   tcp0->checksum = ip_csum_fold(sum0);
2653                 }
2654               else
2655                 {
2656                   old_port0 = udp0->src_port;
2657                   udp0->src_port = s0->out2in.port;
2658                   udp0->checksum = 0;
2659                 }
2660             }
2661
2662           /* Hairpinning */
2663           nat44_reass_hairpinning (sm, b0, ip0, s0->out2in.port,
2664                                    s0->ext_host_port, proto0);
2665
2666           /* Accounting */
2667           s0->last_heard = now;
2668           s0->total_pkts++;
2669           s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
2670           /* Per-user LRU list maintenance */
2671           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
2672                              s0->per_user_index);
2673           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
2674                               s0->per_user_list_head_index,
2675                               s0->per_user_index);
2676
2677         trace0:
2678           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2679                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2680             {
2681               nat44_in2out_reass_trace_t *t =
2682                  vlib_add_trace (vm, node, b0, sizeof (*t));
2683               t->cached = cached0;
2684               t->sw_if_index = sw_if_index0;
2685               t->next_index = next0;
2686             }
2687
2688           if (cached0)
2689             {
2690               n_left_to_next++;
2691               to_next--;
2692             }
2693           else
2694             {
2695               pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
2696
2697               /* verify speculative enqueue, maybe switch current next frame */
2698               vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2699                                                to_next, n_left_to_next,
2700                                                bi0, next0);
2701             }
2702
2703           if (n_left_from == 0 && vec_len (fragments_to_loopback))
2704             {
2705               from = vlib_frame_vector_args (frame);
2706               u32 len = vec_len (fragments_to_loopback);
2707               if (len <= VLIB_FRAME_SIZE)
2708                 {
2709                   clib_memcpy (from, fragments_to_loopback, sizeof (u32) * len);
2710                   n_left_from = len;
2711                   vec_reset_length (fragments_to_loopback);
2712                 }
2713               else
2714                 {
2715                   clib_memcpy (from,
2716                                fragments_to_loopback + (len - VLIB_FRAME_SIZE),
2717                                sizeof (u32) * VLIB_FRAME_SIZE);
2718                   n_left_from = VLIB_FRAME_SIZE;
2719                   _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
2720                 }
2721             }
2722        }
2723
2724       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2725     }
2726
2727   vlib_node_increment_counter (vm, nat44_in2out_reass_node.index,
2728                                SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
2729                                pkts_processed);
2730
2731   nat_send_all_to_node (vm, fragments_to_drop, node,
2732                         &node->errors[SNAT_IN2OUT_ERROR_DROP_FRAGMENT],
2733                         SNAT_IN2OUT_NEXT_DROP);
2734
2735   vec_free (fragments_to_drop);
2736   vec_free (fragments_to_loopback);
2737   return frame->n_vectors;
2738 }
2739
2740 VLIB_REGISTER_NODE (nat44_in2out_reass_node) = {
2741   .function = nat44_in2out_reass_node_fn,
2742   .name = "nat44-in2out-reass",
2743   .vector_size = sizeof (u32),
2744   .format_trace = format_nat44_in2out_reass_trace,
2745   .type = VLIB_NODE_TYPE_INTERNAL,
2746
2747   .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2748   .error_strings = snat_in2out_error_strings,
2749
2750   .n_next_nodes = SNAT_IN2OUT_N_NEXT,
2751   .next_nodes = {
2752     [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2753     [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2754     [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2755     [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2756     [SNAT_IN2OUT_NEXT_REASS] = "nat44-in2out-reass",
2757   },
2758 };
2759
2760 VLIB_NODE_FUNCTION_MULTIARCH (nat44_in2out_reass_node,
2761                               nat44_in2out_reass_node_fn);
2762
2763 /**************************/
2764 /*** deterministic mode ***/
2765 /**************************/
2766 static uword
2767 snat_det_in2out_node_fn (vlib_main_t * vm,
2768                          vlib_node_runtime_t * node,
2769                          vlib_frame_t * frame)
2770 {
2771   u32 n_left_from, * from, * to_next;
2772   snat_in2out_next_t next_index;
2773   u32 pkts_processed = 0;
2774   snat_main_t * sm = &snat_main;
2775   u32 now = (u32) vlib_time_now (vm);
2776   u32 thread_index = vlib_get_thread_index ();
2777
2778   from = vlib_frame_vector_args (frame);
2779   n_left_from = frame->n_vectors;
2780   next_index = node->cached_next_index;
2781
2782   while (n_left_from > 0)
2783     {
2784       u32 n_left_to_next;
2785
2786       vlib_get_next_frame (vm, node, next_index,
2787                            to_next, n_left_to_next);
2788
2789       while (n_left_from >= 4 && n_left_to_next >= 2)
2790         {
2791           u32 bi0, bi1;
2792           vlib_buffer_t * b0, * b1;
2793           u32 next0, next1;
2794           u32 sw_if_index0, sw_if_index1;
2795           ip4_header_t * ip0, * ip1;
2796           ip_csum_t sum0, sum1;
2797           ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
2798           u16 old_port0, new_port0, lo_port0, i0;
2799           u16 old_port1, new_port1, lo_port1, i1;
2800           udp_header_t * udp0, * udp1;
2801           tcp_header_t * tcp0, * tcp1;
2802           u32 proto0, proto1;
2803           snat_det_out_key_t key0, key1;
2804           snat_det_map_t * dm0, * dm1;
2805           snat_det_session_t * ses0 = 0, * ses1 = 0;
2806           u32 rx_fib_index0, rx_fib_index1;
2807           icmp46_header_t * icmp0, * icmp1;
2808
2809           /* Prefetch next iteration. */
2810           {
2811             vlib_buffer_t * p2, * p3;
2812
2813             p2 = vlib_get_buffer (vm, from[2]);
2814             p3 = vlib_get_buffer (vm, from[3]);
2815
2816             vlib_prefetch_buffer_header (p2, LOAD);
2817             vlib_prefetch_buffer_header (p3, LOAD);
2818
2819             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
2820             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
2821           }
2822
2823           /* speculatively enqueue b0 and b1 to the current next frame */
2824           to_next[0] = bi0 = from[0];
2825           to_next[1] = bi1 = from[1];
2826           from += 2;
2827           to_next += 2;
2828           n_left_from -= 2;
2829           n_left_to_next -= 2;
2830
2831           b0 = vlib_get_buffer (vm, bi0);
2832           b1 = vlib_get_buffer (vm, bi1);
2833
2834           next0 = SNAT_IN2OUT_NEXT_LOOKUP;
2835           next1 = SNAT_IN2OUT_NEXT_LOOKUP;
2836
2837           ip0 = vlib_buffer_get_current (b0);
2838           udp0 = ip4_next_header (ip0);
2839           tcp0 = (tcp_header_t *) udp0;
2840
2841           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2842
2843           if (PREDICT_FALSE(ip0->ttl == 1))
2844             {
2845               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2846               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2847                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
2848                                            0);
2849               next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
2850               goto trace0;
2851             }
2852
2853           proto0 = ip_proto_to_snat_proto (ip0->protocol);
2854
2855           if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
2856             {
2857               rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2858               icmp0 = (icmp46_header_t *) udp0;
2859
2860               next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0,
2861                                   rx_fib_index0, node, next0, thread_index,
2862                                   &ses0, &dm0);
2863               goto trace0;
2864             }
2865
2866           dm0 = snat_det_map_by_user(sm, &ip0->src_address);
2867           if (PREDICT_FALSE(!dm0))
2868             {
2869               clib_warning("no match for internal host %U",
2870                            format_ip4_address, &ip0->src_address);
2871               next0 = SNAT_IN2OUT_NEXT_DROP;
2872               b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
2873               goto trace0;
2874             }
2875
2876           snat_det_forward(dm0, &ip0->src_address, &new_addr0, &lo_port0);
2877
2878           key0.ext_host_addr = ip0->dst_address;
2879           key0.ext_host_port = tcp0->dst;
2880
2881           ses0 = snat_det_find_ses_by_in(dm0, &ip0->src_address, tcp0->src, key0);
2882           if (PREDICT_FALSE(!ses0))
2883             {
2884               for (i0 = 0; i0 < dm0->ports_per_host; i0++)
2885                 {
2886                   key0.out_port = clib_host_to_net_u16 (lo_port0 +
2887                     ((i0 + clib_net_to_host_u16 (tcp0->src)) % dm0->ports_per_host));
2888
2889                   if (snat_det_get_ses_by_out (dm0, &ip0->src_address, key0.as_u64))
2890                     continue;
2891
2892                   ses0 = snat_det_ses_create(dm0, &ip0->src_address, tcp0->src, &key0);
2893                   break;
2894                 }
2895               if (PREDICT_FALSE(!ses0))
2896                 {
2897                   /* too many sessions for user, send ICMP error packet */
2898
2899                   vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2900                   icmp4_error_set_vnet_buffer (b0, ICMP4_destination_unreachable,
2901                                                ICMP4_destination_unreachable_destination_unreachable_host,
2902                                                0);
2903                   next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
2904                   goto trace0;
2905                 }
2906             }
2907
2908           new_port0 = ses0->out.out_port;
2909
2910           old_addr0.as_u32 = ip0->src_address.as_u32;
2911           ip0->src_address.as_u32 = new_addr0.as_u32;
2912           vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
2913
2914           sum0 = ip0->checksum;
2915           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2916                                  ip4_header_t,
2917                                  src_address /* changed member */);
2918           ip0->checksum = ip_csum_fold (sum0);
2919
2920           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2921             {
2922               if (tcp0->flags & TCP_FLAG_SYN)
2923                 ses0->state = SNAT_SESSION_TCP_SYN_SENT;
2924               else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
2925                 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
2926               else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
2927                 ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
2928               else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
2929                 snat_det_ses_close(dm0, ses0);
2930               else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
2931                 ses0->state = SNAT_SESSION_TCP_LAST_ACK;
2932               else if (tcp0->flags == 0 && ses0->state == SNAT_SESSION_UNKNOWN)
2933                 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
2934
2935               old_port0 = tcp0->src;
2936               tcp0->src = new_port0;
2937
2938               sum0 = tcp0->checksum;
2939               sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2940                                      ip4_header_t,
2941                                      dst_address /* changed member */);
2942               sum0 = ip_csum_update (sum0, old_port0, new_port0,
2943                                      ip4_header_t /* cheat */,
2944                                      length /* changed member */);
2945               tcp0->checksum = ip_csum_fold(sum0);
2946             }
2947           else
2948             {
2949               ses0->state = SNAT_SESSION_UDP_ACTIVE;
2950               old_port0 = udp0->src_port;
2951               udp0->src_port = new_port0;
2952               udp0->checksum = 0;
2953             }
2954
2955           switch(ses0->state)
2956             {
2957             case SNAT_SESSION_UDP_ACTIVE:
2958                 ses0->expire = now + sm->udp_timeout;
2959                 break;
2960             case SNAT_SESSION_TCP_SYN_SENT:
2961             case SNAT_SESSION_TCP_FIN_WAIT:
2962             case SNAT_SESSION_TCP_CLOSE_WAIT:
2963             case SNAT_SESSION_TCP_LAST_ACK:
2964                 ses0->expire = now + sm->tcp_transitory_timeout;
2965                 break;
2966             case SNAT_SESSION_TCP_ESTABLISHED:
2967                 ses0->expire = now + sm->tcp_established_timeout;
2968                 break;
2969             }
2970
2971         trace0:
2972           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2973                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2974             {
2975               snat_in2out_trace_t *t =
2976                  vlib_add_trace (vm, node, b0, sizeof (*t));
2977               t->is_slow_path = 0;
2978               t->sw_if_index = sw_if_index0;
2979               t->next_index = next0;
2980               t->session_index = ~0;
2981               if (ses0)
2982                 t->session_index = ses0 - dm0->sessions;
2983             }
2984
2985           pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
2986
2987           ip1 = vlib_buffer_get_current (b1);
2988           udp1 = ip4_next_header (ip1);
2989           tcp1 = (tcp_header_t *) udp1;
2990
2991           sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
2992
2993           if (PREDICT_FALSE(ip1->ttl == 1))
2994             {
2995               vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2996               icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
2997                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
2998                                            0);
2999               next1 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
3000               goto trace1;
3001             }
3002
3003           proto1 = ip_proto_to_snat_proto (ip1->protocol);
3004
3005           if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP))
3006             {
3007               rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1);
3008               icmp1 = (icmp46_header_t *) udp1;
3009
3010               next1 = icmp_in2out(sm, b1, ip1, icmp1, sw_if_index1,
3011                                   rx_fib_index1, node, next1, thread_index,
3012                                   &ses1, &dm1);
3013               goto trace1;
3014             }
3015
3016           dm1 = snat_det_map_by_user(sm, &ip1->src_address);
3017           if (PREDICT_FALSE(!dm1))
3018             {
3019               clib_warning("no match for internal host %U",
3020                            format_ip4_address, &ip0->src_address);
3021               next1 = SNAT_IN2OUT_NEXT_DROP;
3022               b1->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
3023               goto trace1;
3024             }
3025
3026           snat_det_forward(dm1, &ip1->src_address, &new_addr1, &lo_port1);
3027
3028           key1.ext_host_addr = ip1->dst_address;
3029           key1.ext_host_port = tcp1->dst;
3030
3031           ses1 = snat_det_find_ses_by_in(dm1, &ip1->src_address, tcp1->src, key1);
3032           if (PREDICT_FALSE(!ses1))
3033             {
3034               for (i1 = 0; i1 < dm1->ports_per_host; i1++)
3035                 {
3036                   key1.out_port = clib_host_to_net_u16 (lo_port1 +
3037                     ((i1 + clib_net_to_host_u16 (tcp1->src)) % dm1->ports_per_host));
3038
3039                   if (snat_det_get_ses_by_out (dm1, &ip1->src_address, key1.as_u64))
3040                     continue;
3041
3042                   ses1 = snat_det_ses_create(dm1, &ip1->src_address, tcp1->src, &key1);
3043                   break;
3044                 }
3045               if (PREDICT_FALSE(!ses1))
3046                 {
3047                   /* too many sessions for user, send ICMP error packet */
3048
3049                   vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
3050                   icmp4_error_set_vnet_buffer (b1, ICMP4_destination_unreachable,
3051                                                ICMP4_destination_unreachable_destination_unreachable_host,
3052                                                0);
3053                   next1 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
3054                   goto trace1;
3055                 }
3056             }
3057
3058           new_port1 = ses1->out.out_port;
3059
3060           old_addr1.as_u32 = ip1->src_address.as_u32;
3061           ip1->src_address.as_u32 = new_addr1.as_u32;
3062           vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
3063
3064           sum1 = ip1->checksum;
3065           sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
3066                                  ip4_header_t,
3067                                  src_address /* changed member */);
3068           ip1->checksum = ip_csum_fold (sum1);
3069
3070           if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
3071             {
3072               if (tcp1->flags & TCP_FLAG_SYN)
3073                 ses1->state = SNAT_SESSION_TCP_SYN_SENT;
3074               else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_SYN_SENT)
3075                 ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
3076               else if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
3077                 ses1->state = SNAT_SESSION_TCP_FIN_WAIT;
3078               else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_FIN_WAIT)
3079                 snat_det_ses_close(dm1, ses1);
3080               else if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_CLOSE_WAIT)
3081                 ses1->state = SNAT_SESSION_TCP_LAST_ACK;
3082               else if (tcp1->flags == 0 && ses1->state == SNAT_SESSION_UNKNOWN)
3083                 ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
3084
3085               old_port1 = tcp1->src;
3086               tcp1->src = new_port1;
3087
3088               sum1 = tcp1->checksum;
3089               sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
3090                                      ip4_header_t,
3091                                      dst_address /* changed member */);
3092               sum1 = ip_csum_update (sum1, old_port1, new_port1,
3093                                      ip4_header_t /* cheat */,
3094                                      length /* changed member */);
3095               tcp1->checksum = ip_csum_fold(sum1);
3096             }
3097           else
3098             {
3099               ses1->state = SNAT_SESSION_UDP_ACTIVE;
3100               old_port1 = udp1->src_port;
3101               udp1->src_port = new_port1;
3102               udp1->checksum = 0;
3103             }
3104
3105           switch(ses1->state)
3106             {
3107             case SNAT_SESSION_UDP_ACTIVE:
3108                 ses1->expire = now + sm->udp_timeout;
3109                 break;
3110             case SNAT_SESSION_TCP_SYN_SENT:
3111             case SNAT_SESSION_TCP_FIN_WAIT:
3112             case SNAT_SESSION_TCP_CLOSE_WAIT:
3113             case SNAT_SESSION_TCP_LAST_ACK:
3114                 ses1->expire = now + sm->tcp_transitory_timeout;
3115                 break;
3116             case SNAT_SESSION_TCP_ESTABLISHED:
3117                 ses1->expire = now + sm->tcp_established_timeout;
3118                 break;
3119             }
3120
3121         trace1:
3122           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
3123                             && (b1->flags & VLIB_BUFFER_IS_TRACED)))
3124             {
3125               snat_in2out_trace_t *t =
3126                  vlib_add_trace (vm, node, b1, sizeof (*t));
3127               t->is_slow_path = 0;
3128               t->sw_if_index = sw_if_index1;
3129               t->next_index = next1;
3130               t->session_index = ~0;
3131               if (ses1)
3132                 t->session_index = ses1 - dm1->sessions;
3133             }
3134
3135           pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP;
3136
3137           /* verify speculative enqueues, maybe switch current next frame */
3138           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
3139                                            to_next, n_left_to_next,
3140                                            bi0, bi1, next0, next1);
3141          }
3142
3143       while (n_left_from > 0 && n_left_to_next > 0)
3144         {
3145           u32 bi0;
3146           vlib_buffer_t * b0;
3147           u32 next0;
3148           u32 sw_if_index0;
3149           ip4_header_t * ip0;
3150           ip_csum_t sum0;
3151           ip4_address_t new_addr0, old_addr0;
3152           u16 old_port0, new_port0, lo_port0, i0;
3153           udp_header_t * udp0;
3154           tcp_header_t * tcp0;
3155           u32 proto0;
3156           snat_det_out_key_t key0;
3157           snat_det_map_t * dm0;
3158           snat_det_session_t * ses0 = 0;
3159           u32 rx_fib_index0;
3160           icmp46_header_t * icmp0;
3161
3162           /* speculatively enqueue b0 to the current next frame */
3163           bi0 = from[0];
3164           to_next[0] = bi0;
3165           from += 1;
3166           to_next += 1;
3167           n_left_from -= 1;
3168           n_left_to_next -= 1;
3169
3170           b0 = vlib_get_buffer (vm, bi0);
3171           next0 = SNAT_IN2OUT_NEXT_LOOKUP;
3172
3173           ip0 = vlib_buffer_get_current (b0);
3174           udp0 = ip4_next_header (ip0);
3175           tcp0 = (tcp_header_t *) udp0;
3176
3177           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
3178
3179           if (PREDICT_FALSE(ip0->ttl == 1))
3180             {
3181               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
3182               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
3183                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
3184                                            0);
3185               next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
3186               goto trace00;
3187             }
3188
3189           proto0 = ip_proto_to_snat_proto (ip0->protocol);
3190
3191           if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
3192             {
3193               rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
3194               icmp0 = (icmp46_header_t *) udp0;
3195
3196               next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0,
3197                                   rx_fib_index0, node, next0, thread_index,
3198                                   &ses0, &dm0);
3199               goto trace00;
3200             }
3201
3202           dm0 = snat_det_map_by_user(sm, &ip0->src_address);
3203           if (PREDICT_FALSE(!dm0))
3204             {
3205               clib_warning("no match for internal host %U",
3206                            format_ip4_address, &ip0->src_address);
3207               next0 = SNAT_IN2OUT_NEXT_DROP;
3208               b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
3209               goto trace00;
3210             }
3211
3212           snat_det_forward(dm0, &ip0->src_address, &new_addr0, &lo_port0);
3213
3214           key0.ext_host_addr = ip0->dst_address;
3215           key0.ext_host_port = tcp0->dst;
3216
3217           ses0 = snat_det_find_ses_by_in(dm0, &ip0->src_address, tcp0->src, key0);
3218           if (PREDICT_FALSE(!ses0))
3219             {
3220               for (i0 = 0; i0 < dm0->ports_per_host; i0++)
3221                 {
3222                   key0.out_port = clib_host_to_net_u16 (lo_port0 +
3223                     ((i0 + clib_net_to_host_u16 (tcp0->src)) % dm0->ports_per_host));
3224
3225                   if (snat_det_get_ses_by_out (dm0, &ip0->src_address, key0.as_u64))
3226                     continue;
3227
3228                   ses0 = snat_det_ses_create(dm0, &ip0->src_address, tcp0->src, &key0);
3229                   break;
3230                 }
3231               if (PREDICT_FALSE(!ses0))
3232                 {
3233                   /* too many sessions for user, send ICMP error packet */
3234
3235                   vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
3236                   icmp4_error_set_vnet_buffer (b0, ICMP4_destination_unreachable,
3237                                                ICMP4_destination_unreachable_destination_unreachable_host,
3238                                                0);
3239                   next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
3240                   goto trace00;
3241                 }
3242             }
3243
3244           new_port0 = ses0->out.out_port;
3245
3246           old_addr0.as_u32 = ip0->src_address.as_u32;
3247           ip0->src_address.as_u32 = new_addr0.as_u32;
3248           vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
3249
3250           sum0 = ip0->checksum;
3251           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
3252                                  ip4_header_t,
3253                                  src_address /* changed member */);
3254           ip0->checksum = ip_csum_fold (sum0);
3255
3256           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
3257             {
3258               if (tcp0->flags & TCP_FLAG_SYN)
3259                 ses0->state = SNAT_SESSION_TCP_SYN_SENT;
3260               else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
3261                 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
3262               else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
3263                 ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
3264               else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
3265                 snat_det_ses_close(dm0, ses0);
3266               else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
3267                 ses0->state = SNAT_SESSION_TCP_LAST_ACK;
3268               else if (tcp0->flags == 0 && ses0->state == SNAT_SESSION_UNKNOWN)
3269                 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
3270
3271               old_port0 = tcp0->src;
3272               tcp0->src = new_port0;
3273
3274               sum0 = tcp0->checksum;
3275               sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
3276                                      ip4_header_t,
3277                                      dst_address /* changed member */);
3278               sum0 = ip_csum_update (sum0, old_port0, new_port0,
3279                                      ip4_header_t /* cheat */,
3280                                      length /* changed member */);
3281               tcp0->checksum = ip_csum_fold(sum0);
3282             }
3283           else
3284             {
3285               ses0->state = SNAT_SESSION_UDP_ACTIVE;
3286               old_port0 = udp0->src_port;
3287               udp0->src_port = new_port0;
3288               udp0->checksum = 0;
3289             }
3290
3291           switch(ses0->state)
3292             {
3293             case SNAT_SESSION_UDP_ACTIVE:
3294                 ses0->expire = now + sm->udp_timeout;
3295                 break;
3296             case SNAT_SESSION_TCP_SYN_SENT:
3297             case SNAT_SESSION_TCP_FIN_WAIT:
3298             case SNAT_SESSION_TCP_CLOSE_WAIT:
3299             case SNAT_SESSION_TCP_LAST_ACK:
3300                 ses0->expire = now + sm->tcp_transitory_timeout;
3301                 break;
3302             case SNAT_SESSION_TCP_ESTABLISHED:
3303                 ses0->expire = now + sm->tcp_established_timeout;
3304                 break;
3305             }
3306
3307         trace00:
3308           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
3309                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
3310             {
3311               snat_in2out_trace_t *t =
3312                  vlib_add_trace (vm, node, b0, sizeof (*t));
3313               t->is_slow_path = 0;
3314               t->sw_if_index = sw_if_index0;
3315               t->next_index = next0;
3316               t->session_index = ~0;
3317               if (ses0)
3318                 t->session_index = ses0 - dm0->sessions;
3319             }
3320
3321           pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
3322
3323           /* verify speculative enqueue, maybe switch current next frame */
3324           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3325                                            to_next, n_left_to_next,
3326                                            bi0, next0);
3327         }
3328
3329       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3330     }
3331
3332   vlib_node_increment_counter (vm, snat_det_in2out_node.index,
3333                                SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
3334                                pkts_processed);
3335   return frame->n_vectors;
3336 }
3337
3338 VLIB_REGISTER_NODE (snat_det_in2out_node) = {
3339   .function = snat_det_in2out_node_fn,
3340   .name = "nat44-det-in2out",
3341   .vector_size = sizeof (u32),
3342   .format_trace = format_snat_in2out_trace,
3343   .type = VLIB_NODE_TYPE_INTERNAL,
3344
3345   .n_errors = ARRAY_LEN(snat_in2out_error_strings),
3346   .error_strings = snat_in2out_error_strings,
3347
3348   .runtime_data_bytes = sizeof (snat_runtime_t),
3349
3350   .n_next_nodes = 3,
3351
3352   /* edit / add dispositions here */
3353   .next_nodes = {
3354     [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
3355     [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
3356     [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
3357   },
3358 };
3359
3360 VLIB_NODE_FUNCTION_MULTIARCH (snat_det_in2out_node, snat_det_in2out_node_fn);
3361
3362 /**
3363  * Get address and port values to be used for ICMP packet translation
3364  * and create session if needed
3365  *
3366  * @param[in,out] sm             NAT main
3367  * @param[in,out] node           NAT node runtime
3368  * @param[in] thread_index       thread index
3369  * @param[in,out] b0             buffer containing packet to be translated
3370  * @param[out] p_proto           protocol used for matching
3371  * @param[out] p_value           address and port after NAT translation
3372  * @param[out] p_dont_translate  if packet should not be translated
3373  * @param d                      optional parameter
3374  * @param e                      optional parameter
3375  */
3376 u32 icmp_match_in2out_det(snat_main_t *sm, vlib_node_runtime_t *node,
3377                           u32 thread_index, vlib_buffer_t *b0,
3378                           ip4_header_t *ip0, u8 *p_proto,
3379                           snat_session_key_t *p_value,
3380                           u8 *p_dont_translate, void *d, void *e)
3381 {
3382   icmp46_header_t *icmp0;
3383   u32 sw_if_index0;
3384   u32 rx_fib_index0;
3385   u8 protocol;
3386   snat_det_out_key_t key0;
3387   u8 dont_translate = 0;
3388   u32 next0 = ~0;
3389   icmp_echo_header_t *echo0, *inner_echo0 = 0;
3390   ip4_header_t *inner_ip0;
3391   void *l4_header = 0;
3392   icmp46_header_t *inner_icmp0;
3393   snat_det_map_t * dm0 = 0;
3394   ip4_address_t new_addr0;
3395   u16 lo_port0, i0;
3396   snat_det_session_t * ses0 = 0;
3397   ip4_address_t in_addr;
3398   u16 in_port;
3399
3400   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
3401   echo0 = (icmp_echo_header_t *)(icmp0+1);
3402   sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
3403   rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
3404
3405   if (!icmp_is_error_message (icmp0))
3406     {
3407       protocol = SNAT_PROTOCOL_ICMP;
3408       in_addr = ip0->src_address;
3409       in_port = echo0->identifier;
3410     }
3411   else
3412     {
3413       inner_ip0 = (ip4_header_t *)(echo0+1);
3414       l4_header = ip4_next_header (inner_ip0);
3415       protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
3416       in_addr = inner_ip0->dst_address;
3417       switch (protocol)
3418         {
3419         case SNAT_PROTOCOL_ICMP:
3420           inner_icmp0 = (icmp46_header_t*)l4_header;
3421           inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
3422           in_port = inner_echo0->identifier;
3423           break;
3424         case SNAT_PROTOCOL_UDP:
3425         case SNAT_PROTOCOL_TCP:
3426           in_port = ((tcp_udp_header_t*)l4_header)->dst_port;
3427           break;
3428         default:
3429           b0->error = node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
3430           next0 = SNAT_IN2OUT_NEXT_DROP;
3431           goto out;
3432         }
3433     }
3434
3435   dm0 = snat_det_map_by_user(sm, &in_addr);
3436   if (PREDICT_FALSE(!dm0))
3437     {
3438       clib_warning("no match for internal host %U",
3439                    format_ip4_address, &in_addr);
3440       if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0,
3441           IP_PROTOCOL_ICMP, rx_fib_index0)))
3442         {
3443           dont_translate = 1;
3444           goto out;
3445         }
3446       next0 = SNAT_IN2OUT_NEXT_DROP;
3447       b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
3448       goto out;
3449     }
3450
3451   snat_det_forward(dm0, &in_addr, &new_addr0, &lo_port0);
3452
3453   key0.ext_host_addr = ip0->dst_address;
3454   key0.ext_host_port = 0;
3455
3456   ses0 = snat_det_find_ses_by_in(dm0, &in_addr, in_port, key0);
3457   if (PREDICT_FALSE(!ses0))
3458     {
3459       if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0,
3460           IP_PROTOCOL_ICMP, rx_fib_index0)))
3461         {
3462           dont_translate = 1;
3463           goto out;
3464         }
3465       if (icmp0->type != ICMP4_echo_request)
3466         {
3467           b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
3468           next0 = SNAT_IN2OUT_NEXT_DROP;
3469           goto out;
3470         }
3471       for (i0 = 0; i0 < dm0->ports_per_host; i0++)
3472         {
3473           key0.out_port = clib_host_to_net_u16 (lo_port0 +
3474             ((i0 + clib_net_to_host_u16 (echo0->identifier)) % dm0->ports_per_host));
3475
3476           if (snat_det_get_ses_by_out (dm0, &in_addr, key0.as_u64))
3477             continue;
3478
3479           ses0 = snat_det_ses_create(dm0, &in_addr, echo0->identifier, &key0);
3480           break;
3481         }
3482       if (PREDICT_FALSE(!ses0))
3483         {
3484           next0 = SNAT_IN2OUT_NEXT_DROP;
3485           b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
3486           goto out;
3487         }
3488     }
3489
3490   if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request &&
3491                     !icmp_is_error_message (icmp0)))
3492     {
3493       b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
3494       next0 = SNAT_IN2OUT_NEXT_DROP;
3495       goto out;
3496     }
3497
3498   u32 now = (u32) vlib_time_now (sm->vlib_main);
3499
3500   ses0->state = SNAT_SESSION_ICMP_ACTIVE;
3501   ses0->expire = now + sm->icmp_timeout;
3502
3503 out:
3504   *p_proto = protocol;
3505   if (ses0)
3506     {
3507       p_value->addr = new_addr0;
3508       p_value->fib_index = sm->outside_fib_index;
3509       p_value->port = ses0->out.out_port;
3510     }
3511   *p_dont_translate = dont_translate;
3512   if (d)
3513     *(snat_det_session_t**)d = ses0;
3514   if (e)
3515     *(snat_det_map_t**)e = dm0;
3516   return next0;
3517 }
3518
3519 /**********************/
3520 /*** worker handoff ***/
3521 /**********************/
3522 static inline uword
3523 snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm,
3524                                       vlib_node_runtime_t * node,
3525                                       vlib_frame_t * frame,
3526                                       u8 is_output)
3527 {
3528   snat_main_t *sm = &snat_main;
3529   vlib_thread_main_t *tm = vlib_get_thread_main ();
3530   u32 n_left_from, *from, *to_next = 0;
3531   static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
3532   static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
3533     = 0;
3534   vlib_frame_queue_elt_t *hf = 0;
3535   vlib_frame_t *f = 0;
3536   int i;
3537   u32 n_left_to_next_worker = 0, *to_next_worker = 0;
3538   u32 next_worker_index = 0;
3539   u32 current_worker_index = ~0;
3540   u32 thread_index = vlib_get_thread_index ();
3541   u32 fq_index;
3542   u32 to_node_index;
3543
3544   ASSERT (vec_len (sm->workers));
3545
3546   if (is_output)
3547     {
3548       fq_index = sm->fq_in2out_output_index;
3549       to_node_index = sm->in2out_output_node_index;
3550     }
3551   else
3552     {
3553       fq_index = sm->fq_in2out_index;
3554       to_node_index = sm->in2out_node_index;
3555     }
3556
3557   if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0))
3558     {
3559       vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
3560
3561       vec_validate_init_empty (congested_handoff_queue_by_worker_index,
3562                                sm->first_worker_index + sm->num_workers - 1,
3563                                (vlib_frame_queue_t *) (~0));
3564     }
3565
3566   from = vlib_frame_vector_args (frame);
3567   n_left_from = frame->n_vectors;
3568
3569   while (n_left_from > 0)
3570     {
3571       u32 bi0;
3572       vlib_buffer_t *b0;
3573       u32 sw_if_index0;
3574       u32 rx_fib_index0;
3575       ip4_header_t * ip0;
3576       u8 do_handoff;
3577
3578       bi0 = from[0];
3579       from += 1;
3580       n_left_from -= 1;
3581
3582       b0 = vlib_get_buffer (vm, bi0);
3583
3584       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
3585       rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
3586
3587       ip0 = vlib_buffer_get_current (b0);
3588
3589       next_worker_index = sm->worker_in2out_cb(ip0, rx_fib_index0);
3590
3591       if (PREDICT_FALSE (next_worker_index != thread_index))
3592         {
3593           do_handoff = 1;
3594
3595           if (next_worker_index != current_worker_index)
3596             {
3597               if (hf)
3598                 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
3599
3600               hf = vlib_get_worker_handoff_queue_elt (fq_index,
3601                                                       next_worker_index,
3602                                                       handoff_queue_elt_by_worker_index);
3603
3604               n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors;
3605               to_next_worker = &hf->buffer_index[hf->n_vectors];
3606               current_worker_index = next_worker_index;
3607             }
3608
3609           /* enqueue to correct worker thread */
3610           to_next_worker[0] = bi0;
3611           to_next_worker++;
3612           n_left_to_next_worker--;
3613
3614           if (n_left_to_next_worker == 0)
3615             {
3616               hf->n_vectors = VLIB_FRAME_SIZE;
3617               vlib_put_frame_queue_elt (hf);
3618               current_worker_index = ~0;
3619               handoff_queue_elt_by_worker_index[next_worker_index] = 0;
3620               hf = 0;
3621             }
3622         }
3623       else
3624         {
3625           do_handoff = 0;
3626           /* if this is 1st frame */
3627           if (!f)
3628             {
3629               f = vlib_get_frame_to_node (vm, to_node_index);
3630               to_next = vlib_frame_vector_args (f);
3631             }
3632
3633           to_next[0] = bi0;
3634           to_next += 1;
3635           f->n_vectors++;
3636         }
3637
3638       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
3639                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
3640         {
3641           snat_in2out_worker_handoff_trace_t *t =
3642             vlib_add_trace (vm, node, b0, sizeof (*t));
3643           t->next_worker_index = next_worker_index;
3644           t->do_handoff = do_handoff;
3645         }
3646     }
3647
3648   if (f)
3649     vlib_put_frame_to_node (vm, to_node_index, f);
3650
3651   if (hf)
3652     hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
3653
3654   /* Ship frames to the worker nodes */
3655   for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++)
3656     {
3657       if (handoff_queue_elt_by_worker_index[i])
3658         {
3659           hf = handoff_queue_elt_by_worker_index[i];
3660           /*
3661            * It works better to let the handoff node
3662            * rate-adapt, always ship the handoff queue element.
3663            */
3664           if (1 || hf->n_vectors == hf->last_n_vectors)
3665             {
3666               vlib_put_frame_queue_elt (hf);
3667               handoff_queue_elt_by_worker_index[i] = 0;
3668             }
3669           else
3670             hf->last_n_vectors = hf->n_vectors;
3671         }
3672       congested_handoff_queue_by_worker_index[i] =
3673         (vlib_frame_queue_t *) (~0);
3674     }
3675   hf = 0;
3676   current_worker_index = ~0;
3677   return frame->n_vectors;
3678 }
3679
3680 static uword
3681 snat_in2out_worker_handoff_fn (vlib_main_t * vm,
3682                                vlib_node_runtime_t * node,
3683                                vlib_frame_t * frame)
3684 {
3685   return snat_in2out_worker_handoff_fn_inline (vm, node, frame, 0);
3686 }
3687
3688 VLIB_REGISTER_NODE (snat_in2out_worker_handoff_node) = {
3689   .function = snat_in2out_worker_handoff_fn,
3690   .name = "nat44-in2out-worker-handoff",
3691   .vector_size = sizeof (u32),
3692   .format_trace = format_snat_in2out_worker_handoff_trace,
3693   .type = VLIB_NODE_TYPE_INTERNAL,
3694
3695   .n_next_nodes = 1,
3696
3697   .next_nodes = {
3698     [0] = "error-drop",
3699   },
3700 };
3701
3702 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_worker_handoff_node,
3703                               snat_in2out_worker_handoff_fn);
3704
3705 static uword
3706 snat_in2out_output_worker_handoff_fn (vlib_main_t * vm,
3707                                       vlib_node_runtime_t * node,
3708                                       vlib_frame_t * frame)
3709 {
3710   return snat_in2out_worker_handoff_fn_inline (vm, node, frame, 1);
3711 }
3712
3713 VLIB_REGISTER_NODE (snat_in2out_output_worker_handoff_node) = {
3714   .function = snat_in2out_output_worker_handoff_fn,
3715   .name = "nat44-in2out-output-worker-handoff",
3716   .vector_size = sizeof (u32),
3717   .format_trace = format_snat_in2out_worker_handoff_trace,
3718   .type = VLIB_NODE_TYPE_INTERNAL,
3719
3720   .n_next_nodes = 1,
3721
3722   .next_nodes = {
3723     [0] = "error-drop",
3724   },
3725 };
3726
3727 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_output_worker_handoff_node,
3728                               snat_in2out_output_worker_handoff_fn);
3729
3730 static_always_inline int
3731 is_hairpinning (snat_main_t *sm, ip4_address_t * dst_addr)
3732 {
3733   snat_address_t * ap;
3734   clib_bihash_kv_8_8_t kv, value;
3735   snat_session_key_t m_key;
3736
3737   vec_foreach (ap, sm->addresses)
3738     {
3739       if (ap->addr.as_u32 == dst_addr->as_u32)
3740         return 1;
3741     }
3742
3743   m_key.addr.as_u32 = dst_addr->as_u32;
3744   m_key.fib_index = sm->outside_fib_index;
3745   m_key.port = 0;
3746   m_key.protocol = 0;
3747   kv.key = m_key.as_u64;
3748   if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
3749     return 1;
3750
3751   return 0;
3752 }
3753
3754 static uword
3755 snat_hairpin_dst_fn (vlib_main_t * vm,
3756                      vlib_node_runtime_t * node,
3757                      vlib_frame_t * frame)
3758 {
3759   u32 n_left_from, * from, * to_next;
3760   snat_in2out_next_t next_index;
3761   u32 pkts_processed = 0;
3762   snat_main_t * sm = &snat_main;
3763
3764   from = vlib_frame_vector_args (frame);
3765   n_left_from = frame->n_vectors;
3766   next_index = node->cached_next_index;
3767
3768   while (n_left_from > 0)
3769     {
3770       u32 n_left_to_next;
3771
3772       vlib_get_next_frame (vm, node, next_index,
3773                            to_next, n_left_to_next);
3774
3775       while (n_left_from > 0 && n_left_to_next > 0)
3776         {
3777           u32 bi0;
3778           vlib_buffer_t * b0;
3779           u32 next0;
3780           ip4_header_t * ip0;
3781           u32 proto0;
3782
3783           /* speculatively enqueue b0 to the current next frame */
3784           bi0 = from[0];
3785           to_next[0] = bi0;
3786           from += 1;
3787           to_next += 1;
3788           n_left_from -= 1;
3789           n_left_to_next -= 1;
3790
3791           b0 = vlib_get_buffer (vm, bi0);
3792           next0 = SNAT_IN2OUT_NEXT_LOOKUP;
3793           ip0 = vlib_buffer_get_current (b0);
3794
3795           proto0 = ip_proto_to_snat_proto (ip0->protocol);
3796
3797           vnet_buffer (b0)->snat.flags = 0;
3798           if (PREDICT_FALSE (is_hairpinning (sm, &ip0->dst_address)))
3799             {
3800               if (proto0 == SNAT_PROTOCOL_TCP || proto0 == SNAT_PROTOCOL_UDP)
3801                 {
3802                   udp_header_t * udp0 = ip4_next_header (ip0);
3803                   tcp_header_t * tcp0 = (tcp_header_t *) udp0;
3804
3805                   snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0);
3806                 }
3807               else if (proto0 == SNAT_PROTOCOL_ICMP)
3808                 {
3809                   icmp46_header_t * icmp0 = ip4_next_header (ip0);
3810
3811                   snat_icmp_hairpinning (sm, b0, ip0, icmp0);
3812                 }
3813               else
3814                 {
3815                   snat_hairpinning_unknown_proto (sm, b0, ip0);
3816                 }
3817
3818               vnet_buffer (b0)->snat.flags = SNAT_FLAG_HAIRPINNING;
3819             }
3820
3821           pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
3822
3823           /* verify speculative enqueue, maybe switch current next frame */
3824           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3825                                            to_next, n_left_to_next,
3826                                            bi0, next0);
3827          }
3828
3829       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3830     }
3831
3832   vlib_node_increment_counter (vm, snat_hairpin_dst_node.index,
3833                                SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
3834                                pkts_processed);
3835   return frame->n_vectors;
3836 }
3837
3838 VLIB_REGISTER_NODE (snat_hairpin_dst_node) = {
3839   .function = snat_hairpin_dst_fn,
3840   .name = "nat44-hairpin-dst",
3841   .vector_size = sizeof (u32),
3842   .type = VLIB_NODE_TYPE_INTERNAL,
3843   .n_errors = ARRAY_LEN(snat_in2out_error_strings),
3844   .error_strings = snat_in2out_error_strings,
3845   .n_next_nodes = 2,
3846   .next_nodes = {
3847     [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
3848     [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
3849   },
3850 };
3851
3852 VLIB_NODE_FUNCTION_MULTIARCH (snat_hairpin_dst_node,
3853                               snat_hairpin_dst_fn);
3854
3855 static uword
3856 snat_hairpin_src_fn (vlib_main_t * vm,
3857                      vlib_node_runtime_t * node,
3858                      vlib_frame_t * frame)
3859 {
3860   u32 n_left_from, * from, * to_next;
3861   snat_in2out_next_t next_index;
3862   u32 pkts_processed = 0;
3863   snat_main_t *sm = &snat_main;
3864
3865   from = vlib_frame_vector_args (frame);
3866   n_left_from = frame->n_vectors;
3867   next_index = node->cached_next_index;
3868
3869   while (n_left_from > 0)
3870     {
3871       u32 n_left_to_next;
3872
3873       vlib_get_next_frame (vm, node, next_index,
3874                            to_next, n_left_to_next);
3875
3876       while (n_left_from > 0 && n_left_to_next > 0)
3877         {
3878           u32 bi0;
3879           vlib_buffer_t * b0;
3880           u32 next0;
3881           snat_interface_t *i;
3882           u32 sw_if_index0;
3883
3884           /* speculatively enqueue b0 to the current next frame */
3885           bi0 = from[0];
3886           to_next[0] = bi0;
3887           from += 1;
3888           to_next += 1;
3889           n_left_from -= 1;
3890           n_left_to_next -= 1;
3891
3892           b0 = vlib_get_buffer (vm, bi0);
3893           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
3894           next0 = SNAT_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT;
3895
3896           pool_foreach (i, sm->output_feature_interfaces,
3897           ({
3898             /* Only packets from NAT inside interface */
3899             if ((nat_interface_is_inside(i)) && (sw_if_index0 == i->sw_if_index))
3900               {
3901                 if (PREDICT_FALSE ((vnet_buffer (b0)->snat.flags) &
3902                                     SNAT_FLAG_HAIRPINNING))
3903                   {
3904                     if (PREDICT_TRUE (sm->num_workers > 1))
3905                       next0 = SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH;
3906                     else
3907                       next0 = SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT;
3908                   }
3909                 break;
3910               }
3911           }));
3912
3913           pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
3914
3915           /* verify speculative enqueue, maybe switch current next frame */
3916           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3917                                            to_next, n_left_to_next,
3918                                            bi0, next0);
3919          }
3920
3921       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3922     }
3923
3924   vlib_node_increment_counter (vm, snat_hairpin_src_node.index,
3925                                SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
3926                                pkts_processed);
3927   return frame->n_vectors;
3928 }
3929
3930 VLIB_REGISTER_NODE (snat_hairpin_src_node) = {
3931   .function = snat_hairpin_src_fn,
3932   .name = "nat44-hairpin-src",
3933   .vector_size = sizeof (u32),
3934   .type = VLIB_NODE_TYPE_INTERNAL,
3935   .n_errors = ARRAY_LEN(snat_in2out_error_strings),
3936   .error_strings = snat_in2out_error_strings,
3937   .n_next_nodes = SNAT_HAIRPIN_SRC_N_NEXT,
3938   .next_nodes = {
3939      [SNAT_HAIRPIN_SRC_NEXT_DROP] = "error-drop",
3940      [SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT] = "nat44-in2out-output",
3941      [SNAT_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT] = "interface-output",
3942      [SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH] = "nat44-in2out-output-worker-handoff",
3943   },
3944 };
3945
3946 VLIB_NODE_FUNCTION_MULTIARCH (snat_hairpin_src_node,
3947                               snat_hairpin_src_fn);
3948
3949 static uword
3950 snat_in2out_fast_static_map_fn (vlib_main_t * vm,
3951                                 vlib_node_runtime_t * node,
3952                                 vlib_frame_t * frame)
3953 {
3954   u32 n_left_from, * from, * to_next;
3955   snat_in2out_next_t next_index;
3956   u32 pkts_processed = 0;
3957   snat_main_t * sm = &snat_main;
3958   u32 stats_node_index;
3959
3960   stats_node_index = snat_in2out_fast_node.index;
3961
3962   from = vlib_frame_vector_args (frame);
3963   n_left_from = frame->n_vectors;
3964   next_index = node->cached_next_index;
3965
3966   while (n_left_from > 0)
3967     {
3968       u32 n_left_to_next;
3969
3970       vlib_get_next_frame (vm, node, next_index,
3971                            to_next, n_left_to_next);
3972
3973       while (n_left_from > 0 && n_left_to_next > 0)
3974         {
3975           u32 bi0;
3976           vlib_buffer_t * b0;
3977           u32 next0;
3978           u32 sw_if_index0;
3979           ip4_header_t * ip0;
3980           ip_csum_t sum0;
3981           u32 new_addr0, old_addr0;
3982           u16 old_port0, new_port0;
3983           udp_header_t * udp0;
3984           tcp_header_t * tcp0;
3985           icmp46_header_t * icmp0;
3986           snat_session_key_t key0, sm0;
3987           u32 proto0;
3988           u32 rx_fib_index0;
3989
3990           /* speculatively enqueue b0 to the current next frame */
3991           bi0 = from[0];
3992           to_next[0] = bi0;
3993           from += 1;
3994           to_next += 1;
3995           n_left_from -= 1;
3996           n_left_to_next -= 1;
3997
3998           b0 = vlib_get_buffer (vm, bi0);
3999           next0 = SNAT_IN2OUT_NEXT_LOOKUP;
4000
4001           ip0 = vlib_buffer_get_current (b0);
4002           udp0 = ip4_next_header (ip0);
4003           tcp0 = (tcp_header_t *) udp0;
4004           icmp0 = (icmp46_header_t *) udp0;
4005
4006           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
4007           rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
4008
4009           if (PREDICT_FALSE(ip0->ttl == 1))
4010             {
4011               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
4012               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
4013                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
4014                                            0);
4015               next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
4016               goto trace0;
4017             }
4018
4019           proto0 = ip_proto_to_snat_proto (ip0->protocol);
4020
4021           if (PREDICT_FALSE (proto0 == ~0))
4022               goto trace0;
4023
4024           if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
4025             {
4026               next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0,
4027                                   rx_fib_index0, node, next0, ~0, 0, 0);
4028               goto trace0;
4029             }
4030
4031           key0.addr = ip0->src_address;
4032           key0.protocol = proto0;
4033           key0.port = udp0->src_port;
4034           key0.fib_index = rx_fib_index0;
4035
4036           if (snat_static_mapping_match(sm, key0, &sm0, 0, 0, 0))
4037             {
4038               b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
4039               next0= SNAT_IN2OUT_NEXT_DROP;
4040               goto trace0;
4041             }
4042
4043           new_addr0 = sm0.addr.as_u32;
4044           new_port0 = sm0.port;
4045           vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
4046           old_addr0 = ip0->src_address.as_u32;
4047           ip0->src_address.as_u32 = new_addr0;
4048
4049           sum0 = ip0->checksum;
4050           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
4051                                  ip4_header_t,
4052                                  src_address /* changed member */);
4053           ip0->checksum = ip_csum_fold (sum0);
4054
4055           if (PREDICT_FALSE(new_port0 != udp0->dst_port))
4056             {
4057               if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
4058                 {
4059                   old_port0 = tcp0->src_port;
4060                   tcp0->src_port = new_port0;
4061
4062                   sum0 = tcp0->checksum;
4063                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
4064                                          ip4_header_t,
4065                                          dst_address /* changed member */);
4066                   sum0 = ip_csum_update (sum0, old_port0, new_port0,
4067                                          ip4_header_t /* cheat */,
4068                                          length /* changed member */);
4069                   tcp0->checksum = ip_csum_fold(sum0);
4070                 }
4071               else
4072                 {
4073                   old_port0 = udp0->src_port;
4074                   udp0->src_port = new_port0;
4075                   udp0->checksum = 0;
4076                 }
4077             }
4078           else
4079             {
4080               if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
4081                 {
4082                   sum0 = tcp0->checksum;
4083                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
4084                                          ip4_header_t,
4085                                          dst_address /* changed member */);
4086                   tcp0->checksum = ip_csum_fold(sum0);
4087                 }
4088             }
4089
4090           /* Hairpinning */
4091           snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0);
4092
4093         trace0:
4094           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
4095                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
4096             {
4097               snat_in2out_trace_t *t =
4098                  vlib_add_trace (vm, node, b0, sizeof (*t));
4099               t->sw_if_index = sw_if_index0;
4100               t->next_index = next0;
4101             }
4102
4103           pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
4104
4105           /* verify speculative enqueue, maybe switch current next frame */
4106           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
4107                                            to_next, n_left_to_next,
4108                                            bi0, next0);
4109         }
4110
4111       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
4112     }
4113
4114   vlib_node_increment_counter (vm, stats_node_index,
4115                                SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
4116                                pkts_processed);
4117   return frame->n_vectors;
4118 }
4119
4120
4121 VLIB_REGISTER_NODE (snat_in2out_fast_node) = {
4122   .function = snat_in2out_fast_static_map_fn,
4123   .name = "nat44-in2out-fast",
4124   .vector_size = sizeof (u32),
4125   .format_trace = format_snat_in2out_fast_trace,
4126   .type = VLIB_NODE_TYPE_INTERNAL,
4127
4128   .n_errors = ARRAY_LEN(snat_in2out_error_strings),
4129   .error_strings = snat_in2out_error_strings,
4130
4131   .runtime_data_bytes = sizeof (snat_runtime_t),
4132
4133   .n_next_nodes = SNAT_IN2OUT_N_NEXT,
4134
4135   /* edit / add dispositions here */
4136   .next_nodes = {
4137     [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
4138     [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
4139     [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
4140     [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
4141     [SNAT_IN2OUT_NEXT_REASS] = "nat44-in2out-reass",
4142   },
4143 };
4144
4145 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_fast_node, snat_in2out_fast_static_map_fn);