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