nat: NAT udp counter & unit test fixes
[vpp.git] / src / plugins / nat / in2out_ed.c
1 /*
2  * Copyright (c) 2018 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  * @file
17  * @brief NAT44 endpoint-dependent inside to outside network translation
18  */
19
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22 #include <vnet/pg/pg.h>
23 #include <vnet/ip/ip.h>
24 #include <vnet/ethernet/ethernet.h>
25 #include <vnet/fib/ip4_fib.h>
26 #include <vppinfra/error.h>
27 #include <nat/nat.h>
28 #include <nat/nat_ipfix_logging.h>
29 #include <nat/nat_reass.h>
30 #include <nat/nat_inlines.h>
31 #include <nat/nat_syslog.h>
32 #include <nat/nat_ha.h>
33
34 static char *nat_in2out_ed_error_strings[] = {
35 #define _(sym,string) string,
36   foreach_nat_in2out_ed_error
37 #undef _
38 };
39
40 typedef enum
41 {
42   NAT_IN2OUT_ED_NEXT_LOOKUP,
43   NAT_IN2OUT_ED_NEXT_DROP,
44   NAT_IN2OUT_ED_NEXT_ICMP_ERROR,
45   NAT_IN2OUT_ED_NEXT_SLOW_PATH,
46   NAT_IN2OUT_ED_NEXT_REASS,
47   NAT_IN2OUT_ED_N_NEXT,
48 } nat_in2out_ed_next_t;
49
50 typedef struct
51 {
52   u32 sw_if_index;
53   u32 next_index;
54   u32 session_index;
55   u32 is_slow_path;
56 } nat_in2out_ed_trace_t;
57
58 static u8 *
59 format_nat_in2out_ed_trace (u8 * s, va_list * args)
60 {
61   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
62   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
63   nat_in2out_ed_trace_t *t = va_arg (*args, nat_in2out_ed_trace_t *);
64   char *tag;
65
66   tag =
67     t->is_slow_path ? "NAT44_IN2OUT_ED_SLOW_PATH" :
68     "NAT44_IN2OUT_ED_FAST_PATH";
69
70   s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
71               t->sw_if_index, t->next_index, t->session_index);
72
73   return s;
74 }
75
76 #ifndef CLIB_MARCH_VARIANT
77 int
78 nat44_i2o_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
79 {
80   snat_main_t *sm = &snat_main;
81   nat44_is_idle_session_ctx_t *ctx = arg;
82   snat_session_t *s;
83   u64 sess_timeout_time;
84   nat_ed_ses_key_t ed_key;
85   clib_bihash_kv_16_8_t ed_kv;
86   int i;
87   snat_address_t *a;
88   snat_session_key_t key;
89   snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
90                                                        ctx->thread_index);
91
92   s = pool_elt_at_index (tsm->sessions, kv->value);
93   sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
94   if (ctx->now >= sess_timeout_time)
95     {
96       if (is_fwd_bypass_session (s))
97         goto delete;
98
99       ed_key.l_addr = s->out2in.addr;
100       ed_key.r_addr = s->ext_host_addr;
101       ed_key.fib_index = s->out2in.fib_index;
102       if (snat_is_unk_proto_session (s))
103         {
104           ed_key.proto = s->in2out.port;
105           ed_key.r_port = 0;
106           ed_key.l_port = 0;
107         }
108       else
109         {
110           ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
111           ed_key.l_port = s->out2in.port;
112           ed_key.r_port = s->ext_host_port;
113         }
114       ed_kv.key[0] = ed_key.as_u64[0];
115       ed_kv.key[1] = ed_key.as_u64[1];
116       if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
117         nat_elog_warn ("out2in_ed key del failed");
118
119       if (snat_is_unk_proto_session (s))
120         goto delete;
121
122       snat_ipfix_logging_nat44_ses_delete (ctx->thread_index,
123                                            s->in2out.addr.as_u32,
124                                            s->out2in.addr.as_u32,
125                                            s->in2out.protocol,
126                                            s->in2out.port,
127                                            s->out2in.port,
128                                            s->in2out.fib_index);
129
130       nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
131                              &s->in2out.addr, s->in2out.port,
132                              &s->ext_host_nat_addr, s->ext_host_nat_port,
133                              &s->out2in.addr, s->out2in.port,
134                              &s->ext_host_addr, s->ext_host_port,
135                              s->in2out.protocol, is_twice_nat_session (s));
136
137       nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
138                    s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
139                    ctx->thread_index);
140
141       if (is_twice_nat_session (s))
142         {
143           for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
144             {
145               key.protocol = s->in2out.protocol;
146               key.port = s->ext_host_nat_port;
147               a = sm->twice_nat_addresses + i;
148               if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
149                 {
150                   snat_free_outside_address_and_port (sm->twice_nat_addresses,
151                                                       ctx->thread_index,
152                                                       &key);
153                   break;
154                 }
155             }
156         }
157
158       if (snat_is_session_static (s))
159         goto delete;
160
161       snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
162                                           &s->out2in);
163     delete:
164       nat44_delete_session (sm, s, ctx->thread_index);
165       return 1;
166     }
167
168   return 0;
169 }
170 #endif
171
172 static inline u32
173 icmp_in2out_ed_slow_path (snat_main_t * sm, vlib_buffer_t * b0,
174                           ip4_header_t * ip0, icmp46_header_t * icmp0,
175                           u32 sw_if_index0, u32 rx_fib_index0,
176                           vlib_node_runtime_t * node, u32 next0, f64 now,
177                           u32 thread_index, snat_session_t ** p_s0)
178 {
179   next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
180                        next0, thread_index, p_s0, 0);
181   snat_session_t *s0 = *p_s0;
182   if (PREDICT_TRUE (next0 != NAT_IN2OUT_ED_NEXT_DROP && s0))
183     {
184       /* Accounting */
185       nat44_session_update_counters (s0, now,
186                                      vlib_buffer_length_in_chain
187                                      (sm->vlib_main, b0), thread_index);
188       /* Per-user LRU list maintenance */
189       nat44_session_update_lru (sm, s0, thread_index);
190     }
191   return next0;
192 }
193
194 static u32
195 slow_path_ed (snat_main_t * sm,
196               vlib_buffer_t * b,
197               u32 rx_fib_index,
198               clib_bihash_kv_16_8_t * kv,
199               snat_session_t ** sessionp,
200               vlib_node_runtime_t * node, u32 next, u32 thread_index, f64 now,
201               tcp_header_t * tcp)
202 {
203   snat_session_t *s = 0;
204   snat_user_t *u;
205   snat_session_key_t key0, key1;
206   lb_nat_type_t lb = 0, is_sm = 0;
207   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
208   nat_ed_ses_key_t *key = (nat_ed_ses_key_t *) kv->key;
209   u32 proto = ip_proto_to_snat_proto (key->proto);
210   nat_outside_fib_t *outside_fib;
211   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
212   u8 identity_nat;
213   fib_prefix_t pfx = {
214     .fp_proto = FIB_PROTOCOL_IP4,
215     .fp_len = 32,
216     .fp_addr = {
217                 .ip4.as_u32 = key->r_addr.as_u32,
218                 },
219   };
220   nat44_is_idle_session_ctx_t ctx;
221
222   if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
223     {
224       b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
225       nat_ipfix_logging_max_sessions (thread_index, sm->max_translations);
226       nat_elog_notice ("maximum sessions exceeded");
227       return NAT_IN2OUT_ED_NEXT_DROP;
228     }
229
230   key0.addr = key->l_addr;
231   key0.port = key->l_port;
232   key1.protocol = key0.protocol = proto;
233   key0.fib_index = rx_fib_index;
234   key1.fib_index = sm->outside_fib_index;
235   /* First try to match static mapping by local address and port */
236   if (snat_static_mapping_match
237       (sm, key0, &key1, 0, 0, 0, &lb, 0, &identity_nat))
238     {
239       /* Try to create dynamic translation */
240       if (snat_alloc_outside_address_and_port (sm->addresses, rx_fib_index,
241                                                thread_index, &key1,
242                                                sm->port_per_thread,
243                                                tsm->snat_thread_index))
244         {
245           nat_elog_notice ("addresses exhausted");
246           b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
247           return NAT_IN2OUT_ED_NEXT_DROP;
248         }
249     }
250   else
251     {
252       if (PREDICT_FALSE (identity_nat))
253         {
254           *sessionp = s;
255           return next;
256         }
257
258       is_sm = 1;
259     }
260
261   if (proto == SNAT_PROTOCOL_TCP)
262     {
263       if (!tcp_is_init (tcp))
264         {
265           b->error = node->errors[NAT_IN2OUT_ED_ERROR_NON_SYN];
266           return NAT_IN2OUT_ED_NEXT_DROP;
267         }
268     }
269
270   u = nat_user_get_or_create (sm, &key->l_addr, rx_fib_index, thread_index);
271   if (!u)
272     {
273       nat_elog_warn ("create NAT user failed");
274       if (!is_sm)
275         snat_free_outside_address_and_port (sm->addresses,
276                                             thread_index, &key1);
277       return NAT_IN2OUT_ED_NEXT_DROP;
278     }
279
280   s = nat_ed_session_alloc (sm, u, thread_index, now);
281   if (!s)
282     {
283       nat44_delete_user_with_no_session (sm, u, thread_index);
284       nat_elog_warn ("create NAT session failed");
285       if (!is_sm)
286         snat_free_outside_address_and_port (sm->addresses,
287                                             thread_index, &key1);
288       return NAT_IN2OUT_ED_NEXT_DROP;
289     }
290
291   user_session_increment (sm, u, is_sm);
292   if (is_sm)
293     s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
294   if (lb)
295     s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
296   s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
297   s->ext_host_addr = key->r_addr;
298   s->ext_host_port = key->r_port;
299   s->in2out = key0;
300   s->out2in = key1;
301   s->out2in.protocol = key0.protocol;
302
303   switch (vec_len (sm->outside_fibs))
304     {
305     case 0:
306       s->out2in.fib_index = sm->outside_fib_index;
307       break;
308     case 1:
309       s->out2in.fib_index = sm->outside_fibs[0].fib_index;
310       break;
311     default:
312       /* *INDENT-OFF* */
313       vec_foreach (outside_fib, sm->outside_fibs)
314        {
315           fei = fib_table_lookup (outside_fib->fib_index, &pfx);
316           if (FIB_NODE_INDEX_INVALID != fei)
317             {
318               if (fib_entry_get_resolving_interface (fei) != ~0)
319                 {
320                   s->out2in.fib_index = outside_fib->fib_index;
321                   break;
322                 }
323             }
324         }
325       /* *INDENT-ON* */
326       break;
327     }
328
329   /* Add to lookup tables */
330   kv->value = s - tsm->sessions;
331   ctx.now = now;
332   ctx.thread_index = thread_index;
333   if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, kv,
334                                                nat44_i2o_ed_is_idle_session_cb,
335                                                &ctx))
336     nat_elog_notice ("in2out-ed key add failed");
337
338   make_ed_kv (kv, &key1.addr, &key->r_addr, key->proto, s->out2in.fib_index,
339               key1.port, key->r_port);
340   kv->value = s - tsm->sessions;
341   if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->out2in_ed, kv,
342                                                nat44_o2i_ed_is_idle_session_cb,
343                                                &ctx))
344     nat_elog_notice ("out2in-ed key add failed");
345
346   *sessionp = s;
347
348   /* log NAT event */
349   snat_ipfix_logging_nat44_ses_create (thread_index,
350                                        s->in2out.addr.as_u32,
351                                        s->out2in.addr.as_u32,
352                                        s->in2out.protocol,
353                                        s->in2out.port,
354                                        s->out2in.port, s->in2out.fib_index);
355
356   nat_syslog_nat44_sadd (s->user_index, s->in2out.fib_index,
357                          &s->in2out.addr, s->in2out.port,
358                          &s->ext_host_nat_addr, s->ext_host_nat_port,
359                          &s->out2in.addr, s->out2in.port,
360                          &s->ext_host_addr, s->ext_host_port,
361                          s->in2out.protocol, 0);
362
363   nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
364                s->out2in.port, &s->ext_host_addr, s->ext_host_port,
365                &s->ext_host_nat_addr, s->ext_host_nat_port,
366                s->in2out.protocol, s->in2out.fib_index, s->flags,
367                thread_index, 0);
368
369   return next;
370 }
371
372 static_always_inline int
373 nat44_ed_not_translate (snat_main_t * sm, vlib_node_runtime_t * node,
374                         u32 sw_if_index, ip4_header_t * ip, u32 proto,
375                         u32 rx_fib_index, u32 thread_index)
376 {
377   udp_header_t *udp = ip4_next_header (ip);
378   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
379   clib_bihash_kv_16_8_t kv, value;
380   snat_session_key_t key0, key1;
381
382   make_ed_kv (&kv, &ip->dst_address, &ip->src_address, ip->protocol,
383               sm->outside_fib_index, udp->dst_port, udp->src_port);
384
385   /* NAT packet aimed at external address if */
386   /* has active sessions */
387   if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
388     {
389       key0.addr = ip->dst_address;
390       key0.port = udp->dst_port;
391       key0.protocol = proto;
392       key0.fib_index = sm->outside_fib_index;
393       /* or is static mappings */
394       if (!snat_static_mapping_match (sm, key0, &key1, 1, 0, 0, 0, 0, 0))
395         return 0;
396     }
397   else
398     return 0;
399
400   if (sm->forwarding_enabled)
401     return 1;
402
403   return snat_not_translate_fast (sm, node, sw_if_index, ip, proto,
404                                   rx_fib_index);
405 }
406
407 static_always_inline int
408 nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
409                                       u32 thread_index, f64 now,
410                                       vlib_main_t * vm, vlib_buffer_t * b)
411 {
412   nat_ed_ses_key_t key;
413   clib_bihash_kv_16_8_t kv, value;
414   udp_header_t *udp;
415   snat_session_t *s = 0;
416   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
417
418   if (!sm->forwarding_enabled)
419     return 0;
420
421   if (ip->protocol == IP_PROTOCOL_ICMP)
422     {
423       key.as_u64[0] = key.as_u64[1] = 0;
424       if (get_icmp_i2o_ed_key (ip, &key))
425         return 0;
426       key.fib_index = 0;
427       kv.key[0] = key.as_u64[0];
428       kv.key[1] = key.as_u64[1];
429     }
430   else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
431     {
432       udp = ip4_next_header (ip);
433       make_ed_kv (&kv, &ip->src_address, &ip->dst_address, ip->protocol, 0,
434                   udp->src_port, udp->dst_port);
435     }
436   else
437     {
438       make_ed_kv (&kv, &ip->src_address, &ip->dst_address, ip->protocol, 0, 0,
439                   0);
440     }
441
442   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
443     {
444       s = pool_elt_at_index (tsm->sessions, value.value);
445       if (is_fwd_bypass_session (s))
446         {
447           if (ip->protocol == IP_PROTOCOL_TCP)
448             {
449               tcp_header_t *tcp = ip4_next_header (ip);
450               if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index))
451                 return 1;
452             }
453           /* Accounting */
454           nat44_session_update_counters (s, now,
455                                          vlib_buffer_length_in_chain (vm, b),
456                                          thread_index);
457           /* Per-user LRU list maintenance */
458           nat44_session_update_lru (sm, s, thread_index);
459           return 1;
460         }
461       else
462         return 0;
463     }
464
465   return 0;
466 }
467
468 static_always_inline int
469 nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip,
470                                        u8 proto, u16 src_port, u16 dst_port,
471                                        u32 thread_index, u32 rx_sw_if_index,
472                                        u32 tx_sw_if_index)
473 {
474   clib_bihash_kv_16_8_t kv, value;
475   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
476   snat_interface_t *i;
477   snat_session_t *s;
478   u32 rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (rx_sw_if_index);
479   u32 tx_fib_index = ip4_fib_table_get_index_for_sw_if_index (tx_sw_if_index);
480
481   /* src NAT check */
482   make_ed_kv (&kv, &ip->src_address, &ip->dst_address, proto, tx_fib_index,
483               src_port, dst_port);
484   if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
485     {
486       s = pool_elt_at_index (tsm->sessions, value.value);
487       if (nat44_is_ses_closed (s))
488         {
489           nat_free_session_data (sm, s, thread_index, 0);
490           nat44_delete_session (sm, s, thread_index);
491         }
492       else
493         s->flags |= SNAT_SESSION_FLAG_OUTPUT_FEATURE;
494       return 1;
495     }
496
497   /* dst NAT check */
498   make_ed_kv (&kv, &ip->dst_address, &ip->src_address, proto, rx_fib_index,
499               dst_port, src_port);
500   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
501     {
502       s = pool_elt_at_index (tsm->sessions, value.value);
503       if (is_fwd_bypass_session (s))
504         return 0;
505
506       /* hairpinning */
507       /* *INDENT-OFF* */
508       pool_foreach (i, sm->output_feature_interfaces,
509       ({
510         if ((nat_interface_is_inside (i)) && (rx_sw_if_index == i->sw_if_index))
511            return 0;
512       }));
513       /* *INDENT-ON* */
514       return 1;
515     }
516
517   return 0;
518 }
519
520 #ifndef CLIB_MARCH_VARIANT
521 u32
522 icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node,
523                       u32 thread_index, vlib_buffer_t * b, ip4_header_t * ip,
524                       u8 * p_proto, snat_session_key_t * p_value,
525                       u8 * p_dont_translate, void *d, void *e)
526 {
527   icmp46_header_t *icmp;
528   u32 sw_if_index;
529   u32 rx_fib_index;
530   nat_ed_ses_key_t key;
531   snat_session_t *s = 0;
532   u8 dont_translate = 0;
533   clib_bihash_kv_16_8_t kv, value;
534   u32 next = ~0;
535   int err;
536   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
537
538   icmp = (icmp46_header_t *) ip4_next_header (ip);
539   sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
540   rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
541
542   key.as_u64[0] = key.as_u64[1] = 0;
543   err = get_icmp_i2o_ed_key (ip, &key);
544   if (err != 0)
545     {
546       b->error = node->errors[err];
547       next = NAT_IN2OUT_ED_NEXT_DROP;
548       goto out;
549     }
550   key.fib_index = rx_fib_index;
551
552   kv.key[0] = key.as_u64[0];
553   kv.key[1] = key.as_u64[1];
554
555   if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
556     {
557       if (vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0)
558         {
559           if (PREDICT_FALSE (nat44_ed_not_translate_output_feature (sm, ip,
560                                                                     key.proto,
561                                                                     key.
562                                                                     l_port,
563                                                                     key.
564                                                                     r_port,
565                                                                     thread_index,
566                                                                     sw_if_index,
567                                                                     vnet_buffer
568                                                                     (b)->
569                                                                     sw_if_index
570                                                                     [VLIB_TX])))
571             {
572               dont_translate = 1;
573               goto out;
574             }
575         }
576       else
577         {
578           if (PREDICT_FALSE (nat44_ed_not_translate (sm, node, sw_if_index,
579                                                      ip, SNAT_PROTOCOL_ICMP,
580                                                      rx_fib_index,
581                                                      thread_index)))
582             {
583               dont_translate = 1;
584               goto out;
585             }
586         }
587
588       if (PREDICT_FALSE (icmp_is_error_message (icmp)))
589         {
590           b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
591           next = NAT_IN2OUT_ED_NEXT_DROP;
592           goto out;
593         }
594
595       next = slow_path_ed (sm, b, rx_fib_index, &kv, &s, node, next,
596                            thread_index, vlib_time_now (sm->vlib_main), 0);
597
598       if (PREDICT_FALSE (next == NAT_IN2OUT_ED_NEXT_DROP))
599         goto out;
600
601       if (!s)
602         {
603           dont_translate = 1;
604           goto out;
605         }
606     }
607   else
608     {
609       if (PREDICT_FALSE (icmp->type != ICMP4_echo_request &&
610                          icmp->type != ICMP4_echo_reply &&
611                          !icmp_is_error_message (icmp)))
612         {
613           b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
614           next = NAT_IN2OUT_ED_NEXT_DROP;
615           goto out;
616         }
617
618       s = pool_elt_at_index (tsm->sessions, value.value);
619     }
620
621   *p_proto = ip_proto_to_snat_proto (key.proto);
622 out:
623   if (s)
624     *p_value = s->out2in;
625   *p_dont_translate = dont_translate;
626   if (d)
627     *(snat_session_t **) d = s;
628   return next;
629 }
630 #endif
631
632 static snat_session_t *
633 nat44_ed_in2out_unknown_proto (snat_main_t * sm,
634                                vlib_buffer_t * b,
635                                ip4_header_t * ip,
636                                u32 rx_fib_index,
637                                u32 thread_index,
638                                f64 now,
639                                vlib_main_t * vm, vlib_node_runtime_t * node)
640 {
641   clib_bihash_kv_8_8_t kv, value;
642   clib_bihash_kv_16_8_t s_kv, s_value;
643   snat_static_mapping_t *m;
644   u32 old_addr, new_addr = 0;
645   ip_csum_t sum;
646   snat_user_t *u;
647   dlist_elt_t *head, *elt;
648   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
649   u32 elt_index, head_index, ses_index;
650   snat_session_t *s;
651   u32 outside_fib_index = sm->outside_fib_index;
652   int i;
653   u8 is_sm = 0;
654   nat_outside_fib_t *outside_fib;
655   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
656   fib_prefix_t pfx = {
657     .fp_proto = FIB_PROTOCOL_IP4,
658     .fp_len = 32,
659     .fp_addr = {
660                 .ip4.as_u32 = ip->dst_address.as_u32,
661                 },
662   };
663
664   switch (vec_len (sm->outside_fibs))
665     {
666     case 0:
667       outside_fib_index = sm->outside_fib_index;
668       break;
669     case 1:
670       outside_fib_index = sm->outside_fibs[0].fib_index;
671       break;
672     default:
673       /* *INDENT-OFF* */
674       vec_foreach (outside_fib, sm->outside_fibs)
675         {
676           fei = fib_table_lookup (outside_fib->fib_index, &pfx);
677           if (FIB_NODE_INDEX_INVALID != fei)
678             {
679               if (fib_entry_get_resolving_interface (fei) != ~0)
680                 {
681                   outside_fib_index = outside_fib->fib_index;
682                   break;
683                 }
684             }
685         }
686       /* *INDENT-ON* */
687       break;
688     }
689   old_addr = ip->src_address.as_u32;
690
691   make_ed_kv (&s_kv, &ip->src_address, &ip->dst_address, ip->protocol,
692               rx_fib_index, 0, 0);
693
694   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &s_kv, &s_value))
695     {
696       s = pool_elt_at_index (tsm->sessions, s_value.value);
697       new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
698     }
699   else
700     {
701       if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
702         {
703           b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
704           nat_ipfix_logging_max_sessions (thread_index, sm->max_translations);
705           nat_elog_notice ("maximum sessions exceeded");
706           return 0;
707         }
708
709       u = nat_user_get_or_create (sm, &ip->src_address, rx_fib_index,
710                                   thread_index);
711       if (!u)
712         {
713           nat_elog_warn ("create NAT user failed");
714           return 0;
715         }
716
717       make_sm_kv (&kv, &ip->src_address, 0, rx_fib_index, 0);
718
719       /* Try to find static mapping first */
720       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
721         {
722           m = pool_elt_at_index (sm->static_mappings, value.value);
723           new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
724           is_sm = 1;
725           goto create_ses;
726         }
727       /* Fallback to 3-tuple key */
728       else
729         {
730           /* Choose same out address as for TCP/UDP session to same destination */
731           head_index = u->sessions_per_user_list_head_index;
732           head = pool_elt_at_index (tsm->list_pool, head_index);
733           elt_index = head->next;
734           if (PREDICT_FALSE (elt_index == ~0))
735             ses_index = ~0;
736           else
737             {
738               elt = pool_elt_at_index (tsm->list_pool, elt_index);
739               ses_index = elt->value;
740             }
741
742           while (ses_index != ~0)
743             {
744               s = pool_elt_at_index (tsm->sessions, ses_index);
745               elt_index = elt->next;
746               elt = pool_elt_at_index (tsm->list_pool, elt_index);
747               ses_index = elt->value;
748
749               if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32)
750                 {
751                   new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
752
753                   make_ed_kv (&s_kv, &s->out2in.addr, &ip->dst_address,
754                               ip->protocol, outside_fib_index, 0, 0);
755                   if (clib_bihash_search_16_8
756                       (&tsm->out2in_ed, &s_kv, &s_value))
757                     goto create_ses;
758
759                   break;
760                 }
761             }
762
763           for (i = 0; i < vec_len (sm->addresses); i++)
764             {
765               make_ed_kv (&s_kv, &sm->addresses[i].addr, &ip->dst_address,
766                           ip->protocol, outside_fib_index, 0, 0);
767               if (clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
768                 {
769                   new_addr = ip->src_address.as_u32 =
770                     sm->addresses[i].addr.as_u32;
771                   goto create_ses;
772                 }
773             }
774           return 0;
775         }
776
777     create_ses:
778       s = nat_ed_session_alloc (sm, u, thread_index, now);
779       if (!s)
780         {
781           nat44_delete_user_with_no_session (sm, u, thread_index);
782           nat_elog_warn ("create NAT session failed");
783           return 0;
784         }
785
786       s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
787       s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
788       s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
789       s->out2in.addr.as_u32 = new_addr;
790       s->out2in.fib_index = outside_fib_index;
791       s->in2out.addr.as_u32 = old_addr;
792       s->in2out.fib_index = rx_fib_index;
793       s->in2out.port = s->out2in.port = ip->protocol;
794       if (is_sm)
795         s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
796       user_session_increment (sm, u, is_sm);
797
798       /* Add to lookup tables */
799       make_ed_kv (&s_kv, &s->in2out.addr, &ip->dst_address, ip->protocol,
800                   rx_fib_index, 0, 0);
801       s_kv.value = s - tsm->sessions;
802       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
803         nat_elog_notice ("in2out key add failed");
804
805       make_ed_kv (&s_kv, &s->out2in.addr, &ip->dst_address, ip->protocol,
806                   outside_fib_index, 0, 0);
807       s_kv.value = s - tsm->sessions;
808       if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1))
809         nat_elog_notice ("out2in key add failed");
810     }
811
812   /* Update IP checksum */
813   sum = ip->checksum;
814   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
815   ip->checksum = ip_csum_fold (sum);
816
817   /* Accounting */
818   nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b),
819                                  thread_index);
820   /* Per-user LRU list maintenance */
821   nat44_session_update_lru (sm, s, thread_index);
822
823   /* Hairpinning */
824   if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
825     nat44_ed_hairpinning_unknown_proto (sm, b, ip);
826
827   if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
828     vnet_buffer (b)->sw_if_index[VLIB_TX] = outside_fib_index;
829
830   return s;
831 }
832
833 static inline uword
834 nat44_ed_in2out_node_fn_inline (vlib_main_t * vm,
835                                 vlib_node_runtime_t * node,
836                                 vlib_frame_t * frame, int is_slow_path,
837                                 int is_output_feature)
838 {
839   u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
840   nat_in2out_ed_next_t next_index;
841   snat_main_t *sm = &snat_main;
842   f64 now = vlib_time_now (vm);
843   u32 thread_index = vm->thread_index;
844   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
845   u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
846     0, fragments = 0;
847
848   stats_node_index = is_slow_path ? sm->ed_in2out_slowpath_node_index :
849     sm->ed_in2out_node_index;
850
851   from = vlib_frame_vector_args (frame);
852   n_left_from = frame->n_vectors;
853   next_index = node->cached_next_index;
854
855   while (n_left_from > 0)
856     {
857       u32 n_left_to_next;
858
859       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
860
861       while (n_left_from >= 4 && n_left_to_next >= 2)
862         {
863           u32 bi0, bi1;
864           vlib_buffer_t *b0, *b1;
865           u32 next0, sw_if_index0, rx_fib_index0, iph_offset0 = 0, proto0,
866             new_addr0, old_addr0;
867           u32 next1, sw_if_index1, rx_fib_index1, iph_offset1 = 0, proto1,
868             new_addr1, old_addr1;
869           u16 old_port0, new_port0, old_port1, new_port1;
870           ip4_header_t *ip0, *ip1;
871           udp_header_t *udp0, *udp1;
872           tcp_header_t *tcp0, *tcp1;
873           icmp46_header_t *icmp0, *icmp1;
874           snat_session_t *s0 = 0, *s1 = 0;
875           clib_bihash_kv_16_8_t kv0, value0, kv1, value1;
876           ip_csum_t sum0, sum1;
877
878           /* Prefetch next iteration. */
879           {
880             vlib_buffer_t *p2, *p3;
881
882             p2 = vlib_get_buffer (vm, from[2]);
883             p3 = vlib_get_buffer (vm, from[3]);
884
885             vlib_prefetch_buffer_header (p2, LOAD);
886             vlib_prefetch_buffer_header (p3, LOAD);
887
888             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
889             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
890           }
891
892           /* speculatively enqueue b0 and b1 to the current next frame */
893           to_next[0] = bi0 = from[0];
894           to_next[1] = bi1 = from[1];
895           from += 2;
896           to_next += 2;
897           n_left_from -= 2;
898           n_left_to_next -= 2;
899
900           b0 = vlib_get_buffer (vm, bi0);
901           b1 = vlib_get_buffer (vm, bi1);
902
903           next0 = NAT_IN2OUT_ED_NEXT_LOOKUP;
904
905           if (is_output_feature)
906             iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
907
908           ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
909                                   iph_offset0);
910
911           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
912           rx_fib_index0 =
913             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
914                                                  sw_if_index0);
915
916           if (PREDICT_FALSE (ip0->ttl == 1))
917             {
918               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
919               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
920                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
921                                            0);
922               next0 = NAT_IN2OUT_ED_NEXT_ICMP_ERROR;
923               goto trace00;
924             }
925
926           udp0 = ip4_next_header (ip0);
927           tcp0 = (tcp_header_t *) udp0;
928           icmp0 = (icmp46_header_t *) udp0;
929           proto0 = ip_proto_to_snat_proto (ip0->protocol);
930
931           if (is_slow_path)
932             {
933               if (PREDICT_FALSE (proto0 == ~0))
934                 {
935                   s0 = nat44_ed_in2out_unknown_proto (sm, b0, ip0,
936                                                       rx_fib_index0,
937                                                       thread_index, now, vm,
938                                                       node);
939                   if (!s0)
940                     next0 = NAT_IN2OUT_ED_NEXT_DROP;
941                   other_packets++;
942                   goto trace00;
943                 }
944
945               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
946                 {
947                   next0 = icmp_in2out_ed_slow_path
948                     (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
949                      next0, now, thread_index, &s0);
950                   icmp_packets++;
951                   goto trace00;
952                 }
953             }
954           else
955             {
956               if (PREDICT_FALSE (proto0 == ~0))
957                 {
958                   next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
959                   goto trace00;
960                 }
961
962               if (ip4_is_fragment (ip0))
963                 {
964                   next0 = NAT_IN2OUT_ED_NEXT_REASS;
965                   fragments++;
966                   goto trace00;
967                 }
968
969               if (is_output_feature)
970                 {
971                   if (PREDICT_FALSE
972                       (nat_not_translate_output_feature_fwd
973                        (sm, ip0, thread_index, now, vm, b0)))
974                     goto trace00;
975                 }
976
977               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
978                 {
979                   next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
980                   goto trace00;
981                 }
982             }
983
984           make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
985                       ip0->protocol, rx_fib_index0, udp0->src_port,
986                       udp0->dst_port);
987
988           if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
989             {
990               if (is_slow_path)
991                 {
992                   if (is_output_feature)
993                     {
994                       if (PREDICT_FALSE
995                           (nat44_ed_not_translate_output_feature
996                            (sm, ip0, ip0->protocol, udp0->src_port,
997                             udp0->dst_port, thread_index, sw_if_index0,
998                             vnet_buffer (b0)->sw_if_index[VLIB_TX])))
999                         goto trace00;
1000                     }
1001                   else
1002                     {
1003                       if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1004                                                                  sw_if_index0,
1005                                                                  ip0, proto0,
1006                                                                  rx_fib_index0,
1007                                                                  thread_index)))
1008                         goto trace00;
1009                     }
1010
1011                   next0 =
1012                     slow_path_ed (sm, b0, rx_fib_index0, &kv0, &s0, node,
1013                                   next0, thread_index, now, tcp0);
1014
1015                   if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
1016                     goto trace00;
1017
1018                   if (PREDICT_FALSE (!s0))
1019                     goto trace00;
1020                 }
1021               else
1022                 {
1023                   next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1024                   goto trace00;
1025                 }
1026             }
1027           else
1028             {
1029               s0 = pool_elt_at_index (tsm->sessions, value0.value);
1030             }
1031
1032           b0->flags |= VNET_BUFFER_F_IS_NATED;
1033
1034           if (!is_output_feature)
1035             vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1036
1037           old_addr0 = ip0->src_address.as_u32;
1038           new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
1039           sum0 = ip0->checksum;
1040           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1041                                  src_address);
1042           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1043             sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1044                                    s0->ext_host_addr.as_u32, ip4_header_t,
1045                                    dst_address);
1046           ip0->checksum = ip_csum_fold (sum0);
1047
1048           old_port0 = udp0->src_port;
1049           new_port0 = udp0->src_port = s0->out2in.port;
1050
1051           if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1052             {
1053               sum0 = tcp0->checksum;
1054               sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1055                                      dst_address);
1056               sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1057                                      length);
1058               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1059                 {
1060                   sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1061                                          s0->ext_host_addr.as_u32,
1062                                          ip4_header_t, dst_address);
1063                   sum0 = ip_csum_update (sum0, tcp0->dst_port,
1064                                          s0->ext_host_port, ip4_header_t,
1065                                          length);
1066                   tcp0->dst_port = s0->ext_host_port;
1067                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1068                 }
1069               mss_clamping (sm, tcp0, &sum0);
1070               tcp0->checksum = ip_csum_fold (sum0);
1071               tcp_packets++;
1072               if (nat44_set_tcp_session_state_i2o
1073                   (sm, s0, tcp0, thread_index))
1074                 goto trace00;
1075             }
1076           else if (udp0->checksum)
1077             {
1078               sum0 = udp0->checksum;
1079               sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1080                                      dst_address);
1081               sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1082                                      length);
1083               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1084                 {
1085                   sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1086                                          s0->ext_host_addr.as_u32,
1087                                          ip4_header_t, dst_address);
1088                   sum0 = ip_csum_update (sum0, tcp0->dst_port,
1089                                          s0->ext_host_port, ip4_header_t,
1090                                          length);
1091                   udp0->dst_port = s0->ext_host_port;
1092                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1093                 }
1094               udp0->checksum = ip_csum_fold (sum0);
1095               udp_packets++;
1096             }
1097           else
1098             {
1099               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1100                 {
1101                   udp0->dst_port = s0->ext_host_port;
1102                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1103                 }
1104               udp_packets++;
1105             }
1106
1107           /* Accounting */
1108           nat44_session_update_counters (s0, now,
1109                                          vlib_buffer_length_in_chain (vm,
1110                                                                       b0),
1111                                          thread_index);
1112           /* Per-user LRU list maintenance */
1113           nat44_session_update_lru (sm, s0, thread_index);
1114
1115         trace00:
1116           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1117                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1118             {
1119               nat_in2out_ed_trace_t *t =
1120                 vlib_add_trace (vm, node, b0, sizeof (*t));
1121               t->is_slow_path = is_slow_path;
1122               t->sw_if_index = sw_if_index0;
1123               t->next_index = next0;
1124               t->session_index = ~0;
1125               if (s0)
1126                 t->session_index = s0 - tsm->sessions;
1127             }
1128
1129           pkts_processed += next0 == NAT_IN2OUT_ED_NEXT_LOOKUP;
1130
1131
1132           next1 = NAT_IN2OUT_ED_NEXT_LOOKUP;
1133
1134           if (is_output_feature)
1135             iph_offset1 = vnet_buffer (b1)->ip.save_rewrite_length;
1136
1137           ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) +
1138                                   iph_offset1);
1139
1140           sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1141           rx_fib_index1 =
1142             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1143                                                  sw_if_index1);
1144
1145           if (PREDICT_FALSE (ip1->ttl == 1))
1146             {
1147               vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1148               icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1149                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1150                                            0);
1151               next1 = NAT_IN2OUT_ED_NEXT_ICMP_ERROR;
1152               goto trace01;
1153             }
1154
1155           udp1 = ip4_next_header (ip1);
1156           tcp1 = (tcp_header_t *) udp1;
1157           icmp1 = (icmp46_header_t *) udp1;
1158           proto1 = ip_proto_to_snat_proto (ip1->protocol);
1159
1160           if (is_slow_path)
1161             {
1162               if (PREDICT_FALSE (proto1 == ~0))
1163                 {
1164                   s1 = nat44_ed_in2out_unknown_proto (sm, b1, ip1,
1165                                                       rx_fib_index1,
1166                                                       thread_index, now, vm,
1167                                                       node);
1168                   if (!s1)
1169                     next1 = NAT_IN2OUT_ED_NEXT_DROP;
1170                   other_packets++;
1171                   goto trace01;
1172                 }
1173
1174               if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1175                 {
1176                   next1 = icmp_in2out_ed_slow_path
1177                     (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1178                      next1, now, thread_index, &s1);
1179                   icmp_packets++;
1180                   goto trace01;
1181                 }
1182             }
1183           else
1184             {
1185               if (PREDICT_FALSE (proto1 == ~0))
1186                 {
1187                   next1 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1188                   goto trace01;
1189                 }
1190
1191               if (ip4_is_fragment (ip1))
1192                 {
1193                   next1 = NAT_IN2OUT_ED_NEXT_REASS;
1194                   fragments++;
1195                   goto trace01;
1196                 }
1197
1198               if (is_output_feature)
1199                 {
1200                   if (PREDICT_FALSE
1201                       (nat_not_translate_output_feature_fwd
1202                        (sm, ip1, thread_index, now, vm, b1)))
1203                     goto trace01;
1204                 }
1205
1206               if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1207                 {
1208                   next1 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1209                   goto trace01;
1210                 }
1211             }
1212
1213           make_ed_kv (&kv1, &ip1->src_address, &ip1->dst_address,
1214                       ip1->protocol, rx_fib_index1, udp1->src_port,
1215                       udp1->dst_port);
1216
1217           if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv1, &value1))
1218             {
1219               if (is_slow_path)
1220                 {
1221                   if (is_output_feature)
1222                     {
1223                       if (PREDICT_FALSE
1224                           (nat44_ed_not_translate_output_feature
1225                            (sm, ip1, ip1->protocol, udp1->src_port,
1226                             udp1->dst_port, thread_index, sw_if_index1,
1227                             vnet_buffer (b1)->sw_if_index[VLIB_TX])))
1228                         goto trace01;
1229                     }
1230                   else
1231                     {
1232                       if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1233                                                                  sw_if_index1,
1234                                                                  ip1, proto1,
1235                                                                  rx_fib_index1,
1236                                                                  thread_index)))
1237                         goto trace01;
1238                     }
1239
1240                   next1 =
1241                     slow_path_ed (sm, b1, rx_fib_index1, &kv1, &s1, node,
1242                                   next1, thread_index, now, tcp1);
1243
1244                   if (PREDICT_FALSE (next1 == NAT_IN2OUT_ED_NEXT_DROP))
1245                     goto trace01;
1246
1247                   if (PREDICT_FALSE (!s1))
1248                     goto trace01;
1249                 }
1250               else
1251                 {
1252                   next1 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1253                   goto trace01;
1254                 }
1255             }
1256           else
1257             {
1258               s1 = pool_elt_at_index (tsm->sessions, value1.value);
1259             }
1260
1261           b1->flags |= VNET_BUFFER_F_IS_NATED;
1262
1263           if (!is_output_feature)
1264             vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index;
1265
1266           old_addr1 = ip1->src_address.as_u32;
1267           new_addr1 = ip1->src_address.as_u32 = s1->out2in.addr.as_u32;
1268           sum1 = ip1->checksum;
1269           sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
1270                                  src_address);
1271           if (PREDICT_FALSE (is_twice_nat_session (s1)))
1272             sum1 = ip_csum_update (sum1, ip1->dst_address.as_u32,
1273                                    s1->ext_host_addr.as_u32, ip4_header_t,
1274                                    dst_address);
1275           ip1->checksum = ip_csum_fold (sum1);
1276
1277           old_port1 = udp1->src_port;
1278           new_port1 = udp1->src_port = s1->out2in.port;
1279
1280           if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
1281             {
1282               sum1 = tcp1->checksum;
1283               sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
1284                                      dst_address);
1285               sum1 = ip_csum_update (sum1, old_port1, new_port1, ip4_header_t,
1286                                      length);
1287               if (PREDICT_FALSE (is_twice_nat_session (s1)))
1288                 {
1289                   sum1 = ip_csum_update (sum1, ip1->dst_address.as_u32,
1290                                          s1->ext_host_addr.as_u32,
1291                                          ip4_header_t, dst_address);
1292                   sum1 = ip_csum_update (sum1, tcp1->dst_port,
1293                                          s1->ext_host_port, ip4_header_t,
1294                                          length);
1295                   tcp1->dst_port = s1->ext_host_port;
1296                   ip1->dst_address.as_u32 = s1->ext_host_addr.as_u32;
1297                 }
1298               tcp1->checksum = ip_csum_fold (sum1);
1299               mss_clamping (sm, tcp1, &sum1);
1300               tcp_packets++;
1301               if (nat44_set_tcp_session_state_i2o
1302                   (sm, s1, tcp1, thread_index))
1303                 goto trace01;
1304             }
1305           else if (udp1->checksum)
1306             {
1307               sum1 = udp1->checksum;
1308               sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
1309                                      dst_address);
1310               sum1 = ip_csum_update (sum1, old_port1, new_port1, ip4_header_t,
1311                                      length);
1312
1313               if (PREDICT_FALSE (is_twice_nat_session (s1)))
1314                 {
1315                   sum1 = ip_csum_update (sum1, ip1->dst_address.as_u32,
1316                                          s1->ext_host_addr.as_u32,
1317                                          ip4_header_t, dst_address);
1318                   sum1 = ip_csum_update (sum1, tcp1->dst_port,
1319                                          s1->ext_host_port, ip4_header_t,
1320                                          length);
1321                   udp1->dst_port = s1->ext_host_port;
1322                   ip1->dst_address.as_u32 = s1->ext_host_addr.as_u32;
1323                 }
1324               udp1->checksum = ip_csum_fold (sum1);
1325               udp_packets++;
1326             }
1327           else
1328             {
1329               if (PREDICT_FALSE (is_twice_nat_session (s1)))
1330                 {
1331                   udp1->dst_port = s1->ext_host_port;
1332                   ip1->dst_address.as_u32 = s1->ext_host_addr.as_u32;
1333                 }
1334               udp_packets++;
1335             }
1336
1337           /* Accounting */
1338           nat44_session_update_counters (s1, now,
1339                                          vlib_buffer_length_in_chain (vm, b1),
1340                                          thread_index);
1341           /* Per-user LRU list maintenance */
1342           nat44_session_update_lru (sm, s1, thread_index);
1343
1344         trace01:
1345           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1346                              && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1347             {
1348               nat_in2out_ed_trace_t *t =
1349                 vlib_add_trace (vm, node, b1, sizeof (*t));
1350               t->is_slow_path = is_slow_path;
1351               t->sw_if_index = sw_if_index1;
1352               t->next_index = next1;
1353               t->session_index = ~0;
1354               if (s1)
1355                 t->session_index = s1 - tsm->sessions;
1356             }
1357
1358           pkts_processed += next1 == NAT_IN2OUT_ED_NEXT_LOOKUP;
1359
1360           /* verify speculative enqueues, maybe switch current next frame */
1361           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1362                                            to_next, n_left_to_next,
1363                                            bi0, bi1, next0, next1);
1364         }
1365
1366       while (n_left_from > 0 && n_left_to_next > 0)
1367         {
1368           u32 bi0;
1369           vlib_buffer_t *b0;
1370           u32 next0, sw_if_index0, rx_fib_index0, iph_offset0 = 0, proto0,
1371             new_addr0, old_addr0;
1372           u16 old_port0, new_port0;
1373           ip4_header_t *ip0;
1374           udp_header_t *udp0;
1375           tcp_header_t *tcp0;
1376           icmp46_header_t *icmp0;
1377           snat_session_t *s0 = 0;
1378           clib_bihash_kv_16_8_t kv0, value0;
1379           ip_csum_t sum0;
1380
1381           /* speculatively enqueue b0 to the current next frame */
1382           bi0 = from[0];
1383           to_next[0] = bi0;
1384           from += 1;
1385           to_next += 1;
1386           n_left_from -= 1;
1387           n_left_to_next -= 1;
1388
1389           b0 = vlib_get_buffer (vm, bi0);
1390           next0 = NAT_IN2OUT_ED_NEXT_LOOKUP;
1391
1392           if (is_output_feature)
1393             iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1394
1395           ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1396                                   iph_offset0);
1397
1398           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1399           rx_fib_index0 =
1400             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1401                                                  sw_if_index0);
1402
1403           if (PREDICT_FALSE (ip0->ttl == 1))
1404             {
1405               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1406               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1407                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1408                                            0);
1409               next0 = NAT_IN2OUT_ED_NEXT_ICMP_ERROR;
1410               goto trace0;
1411             }
1412
1413           udp0 = ip4_next_header (ip0);
1414           tcp0 = (tcp_header_t *) udp0;
1415           icmp0 = (icmp46_header_t *) udp0;
1416           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1417
1418           if (is_slow_path)
1419             {
1420               if (PREDICT_FALSE (proto0 == ~0))
1421                 {
1422                   s0 = nat44_ed_in2out_unknown_proto (sm, b0, ip0,
1423                                                       rx_fib_index0,
1424                                                       thread_index, now, vm,
1425                                                       node);
1426                   if (!s0)
1427                     next0 = NAT_IN2OUT_ED_NEXT_DROP;
1428                   other_packets++;
1429                   goto trace0;
1430                 }
1431
1432               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1433                 {
1434                   next0 = icmp_in2out_ed_slow_path
1435                     (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1436                      next0, now, thread_index, &s0);
1437                   icmp_packets++;
1438                   goto trace0;
1439                 }
1440             }
1441           else
1442             {
1443               if (PREDICT_FALSE (proto0 == ~0))
1444                 {
1445                   next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1446                   goto trace0;
1447                 }
1448
1449               if (ip4_is_fragment (ip0))
1450                 {
1451                   next0 = NAT_IN2OUT_ED_NEXT_REASS;
1452                   fragments++;
1453                   goto trace0;
1454                 }
1455
1456               if (is_output_feature)
1457                 {
1458                   if (PREDICT_FALSE
1459                       (nat_not_translate_output_feature_fwd
1460                        (sm, ip0, thread_index, now, vm, b0)))
1461                     goto trace0;
1462                 }
1463
1464               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1465                 {
1466                   next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1467                   goto trace0;
1468                 }
1469             }
1470
1471           make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
1472                       ip0->protocol, rx_fib_index0, udp0->src_port,
1473                       udp0->dst_port);
1474
1475           if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
1476             {
1477               if (is_slow_path)
1478                 {
1479                   if (is_output_feature)
1480                     {
1481                       if (PREDICT_FALSE
1482                           (nat44_ed_not_translate_output_feature
1483                            (sm, ip0, ip0->protocol, udp0->src_port,
1484                             udp0->dst_port, thread_index, sw_if_index0,
1485                             vnet_buffer (b0)->sw_if_index[VLIB_TX])))
1486                         goto trace0;
1487                     }
1488                   else
1489                     {
1490                       if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1491                                                                  sw_if_index0,
1492                                                                  ip0, proto0,
1493                                                                  rx_fib_index0,
1494                                                                  thread_index)))
1495                         goto trace0;
1496                     }
1497
1498                   next0 =
1499                     slow_path_ed (sm, b0, rx_fib_index0, &kv0, &s0, node,
1500                                   next0, thread_index, now, tcp0);
1501
1502                   if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
1503                     goto trace0;
1504
1505                   if (PREDICT_FALSE (!s0))
1506                     goto trace0;
1507                 }
1508               else
1509                 {
1510                   next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1511                   goto trace0;
1512                 }
1513             }
1514           else
1515             {
1516               s0 = pool_elt_at_index (tsm->sessions, value0.value);
1517             }
1518
1519           b0->flags |= VNET_BUFFER_F_IS_NATED;
1520
1521           if (!is_output_feature)
1522             vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1523
1524           old_addr0 = ip0->src_address.as_u32;
1525           new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
1526           sum0 = ip0->checksum;
1527           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1528                                  src_address);
1529           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1530             sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1531                                    s0->ext_host_addr.as_u32, ip4_header_t,
1532                                    dst_address);
1533           ip0->checksum = ip_csum_fold (sum0);
1534
1535           old_port0 = udp0->src_port;
1536           new_port0 = udp0->src_port = s0->out2in.port;
1537
1538           if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1539             {
1540               sum0 = tcp0->checksum;
1541               sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1542                                      dst_address);
1543               sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1544                                      length);
1545               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1546                 {
1547                   sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1548                                          s0->ext_host_addr.as_u32,
1549                                          ip4_header_t, dst_address);
1550                   sum0 = ip_csum_update (sum0, tcp0->dst_port,
1551                                          s0->ext_host_port, ip4_header_t,
1552                                          length);
1553                   tcp0->dst_port = s0->ext_host_port;
1554                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1555                 }
1556               mss_clamping (sm, tcp0, &sum0);
1557               tcp0->checksum = ip_csum_fold (sum0);
1558               tcp_packets++;
1559               if (nat44_set_tcp_session_state_i2o
1560                   (sm, s0, tcp0, thread_index))
1561                 goto trace0;
1562             }
1563           else if (udp0->checksum)
1564             {
1565               sum0 = udp0->checksum;
1566               sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1567                                      dst_address);
1568               sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1569                                      length);
1570               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1571                 {
1572                   sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1573                                          s0->ext_host_addr.as_u32,
1574                                          ip4_header_t, dst_address);
1575                   sum0 = ip_csum_update (sum0, tcp0->dst_port,
1576                                          s0->ext_host_port, ip4_header_t,
1577                                          length);
1578                   udp0->dst_port = s0->ext_host_port;
1579                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1580                 }
1581               udp0->checksum = ip_csum_fold (sum0);
1582               udp_packets++;
1583             }
1584           else
1585             {
1586               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1587                 {
1588                   udp0->dst_port = s0->ext_host_port;
1589                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1590                 }
1591               udp_packets++;
1592             }
1593
1594           /* Accounting */
1595           nat44_session_update_counters (s0, now,
1596                                          vlib_buffer_length_in_chain (vm, b0),
1597                                          thread_index);
1598           /* Per-user LRU list maintenance */
1599           nat44_session_update_lru (sm, s0, thread_index);
1600
1601         trace0:
1602           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1603                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1604             {
1605               nat_in2out_ed_trace_t *t =
1606                 vlib_add_trace (vm, node, b0, sizeof (*t));
1607               t->is_slow_path = is_slow_path;
1608               t->sw_if_index = sw_if_index0;
1609               t->next_index = next0;
1610               t->session_index = ~0;
1611               if (s0)
1612                 t->session_index = s0 - tsm->sessions;
1613             }
1614
1615           pkts_processed += next0 == NAT_IN2OUT_ED_NEXT_LOOKUP;
1616
1617           /* verify speculative enqueue, maybe switch current next frame */
1618           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1619                                            to_next, n_left_to_next,
1620                                            bi0, next0);
1621         }
1622
1623       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1624     }
1625
1626   vlib_node_increment_counter (vm, stats_node_index,
1627                                NAT_IN2OUT_ED_ERROR_IN2OUT_PACKETS,
1628                                pkts_processed);
1629   vlib_node_increment_counter (vm, stats_node_index,
1630                                NAT_IN2OUT_ED_ERROR_TCP_PACKETS, tcp_packets);
1631   vlib_node_increment_counter (vm, stats_node_index,
1632                                NAT_IN2OUT_ED_ERROR_UDP_PACKETS, udp_packets);
1633   vlib_node_increment_counter (vm, stats_node_index,
1634                                NAT_IN2OUT_ED_ERROR_ICMP_PACKETS,
1635                                icmp_packets);
1636   vlib_node_increment_counter (vm, stats_node_index,
1637                                NAT_IN2OUT_ED_ERROR_OTHER_PACKETS,
1638                                other_packets);
1639   vlib_node_increment_counter (vm, stats_node_index,
1640                                NAT_IN2OUT_ED_ERROR_FRAGMENTS, fragments);
1641
1642   return frame->n_vectors;
1643 }
1644
1645 VLIB_NODE_FN (nat44_ed_in2out_node) (vlib_main_t * vm,
1646                                      vlib_node_runtime_t * node,
1647                                      vlib_frame_t * frame)
1648 {
1649   return nat44_ed_in2out_node_fn_inline (vm, node, frame, 0, 0);
1650 }
1651
1652 /* *INDENT-OFF* */
1653 VLIB_REGISTER_NODE (nat44_ed_in2out_node) = {
1654   .name = "nat44-ed-in2out",
1655   .vector_size = sizeof (u32),
1656   .format_trace = format_nat_in2out_ed_trace,
1657   .type = VLIB_NODE_TYPE_INTERNAL,
1658   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1659   .error_strings = nat_in2out_ed_error_strings,
1660   .runtime_data_bytes = sizeof (snat_runtime_t),
1661   .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1662   .next_nodes = {
1663     [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1664     [NAT_IN2OUT_ED_NEXT_LOOKUP] = "ip4-lookup",
1665     [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-slowpath",
1666     [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1667     [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
1668   },
1669 };
1670 /* *INDENT-ON* */
1671
1672 VLIB_NODE_FN (nat44_ed_in2out_output_node) (vlib_main_t * vm,
1673                                             vlib_node_runtime_t * node,
1674                                             vlib_frame_t * frame)
1675 {
1676   return nat44_ed_in2out_node_fn_inline (vm, node, frame, 0, 1);
1677 }
1678
1679 /* *INDENT-OFF* */
1680 VLIB_REGISTER_NODE (nat44_ed_in2out_output_node) = {
1681   .name = "nat44-ed-in2out-output",
1682   .vector_size = sizeof (u32),
1683   .format_trace = format_nat_in2out_ed_trace,
1684   .type = VLIB_NODE_TYPE_INTERNAL,
1685   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1686   .error_strings = nat_in2out_ed_error_strings,
1687   .runtime_data_bytes = sizeof (snat_runtime_t),
1688   .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1689   .next_nodes = {
1690     [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1691     [NAT_IN2OUT_ED_NEXT_LOOKUP] = "interface-output",
1692     [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
1693     [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1694     [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass-output",
1695   },
1696 };
1697 /* *INDENT-ON* */
1698
1699 VLIB_NODE_FN (nat44_ed_in2out_slowpath_node) (vlib_main_t * vm,
1700                                               vlib_node_runtime_t * node,
1701                                               vlib_frame_t * frame)
1702 {
1703   return nat44_ed_in2out_node_fn_inline (vm, node, frame, 1, 0);
1704 }
1705
1706 /* *INDENT-OFF* */
1707 VLIB_REGISTER_NODE (nat44_ed_in2out_slowpath_node) = {
1708   .name = "nat44-ed-in2out-slowpath",
1709   .vector_size = sizeof (u32),
1710   .format_trace = format_nat_in2out_ed_trace,
1711   .type = VLIB_NODE_TYPE_INTERNAL,
1712   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1713   .error_strings = nat_in2out_ed_error_strings,
1714   .runtime_data_bytes = sizeof (snat_runtime_t),
1715   .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1716   .next_nodes = {
1717     [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1718     [NAT_IN2OUT_ED_NEXT_LOOKUP] = "ip4-lookup",
1719     [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-slowpath",
1720     [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1721     [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
1722   },
1723 };
1724 /* *INDENT-ON* */
1725
1726 VLIB_NODE_FN (nat44_ed_in2out_output_slowpath_node) (vlib_main_t * vm,
1727                                                      vlib_node_runtime_t *
1728                                                      node,
1729                                                      vlib_frame_t * frame)
1730 {
1731   return nat44_ed_in2out_node_fn_inline (vm, node, frame, 1, 1);
1732 }
1733
1734 /* *INDENT-OFF* */
1735 VLIB_REGISTER_NODE (nat44_ed_in2out_output_slowpath_node) = {
1736   .name = "nat44-ed-in2out-output-slowpath",
1737   .vector_size = sizeof (u32),
1738   .format_trace = format_nat_in2out_ed_trace,
1739   .type = VLIB_NODE_TYPE_INTERNAL,
1740   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1741   .error_strings = nat_in2out_ed_error_strings,
1742   .runtime_data_bytes = sizeof (snat_runtime_t),
1743   .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1744   .next_nodes = {
1745     [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1746     [NAT_IN2OUT_ED_NEXT_LOOKUP] = "interface-output",
1747     [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
1748     [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1749     [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
1750   },
1751 };
1752 /* *INDENT-ON* */
1753
1754 static inline uword
1755 nat44_ed_in2out_reass_node_fn_inline (vlib_main_t * vm,
1756                                       vlib_node_runtime_t * node,
1757                                       vlib_frame_t * frame,
1758                                       int is_output_feature)
1759 {
1760   u32 n_left_from, *from, *to_next;
1761   nat_in2out_ed_next_t next_index;
1762   u32 pkts_processed = 0, cached_fragments = 0;
1763   snat_main_t *sm = &snat_main;
1764   f64 now = vlib_time_now (vm);
1765   u32 thread_index = vm->thread_index;
1766   snat_main_per_thread_data_t *per_thread_data =
1767     &sm->per_thread_data[thread_index];
1768   u32 *fragments_to_drop = 0;
1769   u32 *fragments_to_loopback = 0;
1770
1771   from = vlib_frame_vector_args (frame);
1772   n_left_from = frame->n_vectors;
1773   next_index = node->cached_next_index;
1774
1775   while (n_left_from > 0)
1776     {
1777       u32 n_left_to_next;
1778
1779       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1780
1781       while (n_left_from > 0 && n_left_to_next > 0)
1782         {
1783           u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1784           u32 iph_offset0 = 0;
1785           vlib_buffer_t *b0;
1786           u32 next0;
1787           u8 cached0 = 0;
1788           ip4_header_t *ip0 = 0;
1789           nat_reass_ip4_t *reass0;
1790           udp_header_t *udp0;
1791           tcp_header_t *tcp0;
1792           icmp46_header_t *icmp0;
1793           clib_bihash_kv_16_8_t kv0, value0;
1794           snat_session_t *s0 = 0;
1795           u16 old_port0, new_port0;
1796           ip_csum_t sum0;
1797
1798           /* speculatively enqueue b0 to the current next frame */
1799           bi0 = from[0];
1800           to_next[0] = bi0;
1801           from += 1;
1802           to_next += 1;
1803           n_left_from -= 1;
1804           n_left_to_next -= 1;
1805
1806           b0 = vlib_get_buffer (vm, bi0);
1807
1808           next0 = NAT_IN2OUT_ED_NEXT_LOOKUP;
1809
1810           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1811           rx_fib_index0 =
1812             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1813                                                  sw_if_index0);
1814
1815           if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
1816             {
1817               next0 = NAT_IN2OUT_ED_NEXT_DROP;
1818               b0->error = node->errors[NAT_IN2OUT_ED_ERROR_DROP_FRAGMENT];
1819               goto trace0;
1820             }
1821
1822           if (is_output_feature)
1823             iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1824
1825           ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1826                                   iph_offset0);
1827
1828           udp0 = ip4_next_header (ip0);
1829           tcp0 = (tcp_header_t *) udp0;
1830           icmp0 = (icmp46_header_t *) udp0;
1831           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1832
1833           reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1834                                                  ip0->dst_address,
1835                                                  ip0->fragment_id,
1836                                                  ip0->protocol,
1837                                                  1, &fragments_to_drop);
1838
1839           if (PREDICT_FALSE (!reass0))
1840             {
1841               next0 = NAT_IN2OUT_ED_NEXT_DROP;
1842               b0->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_REASS];
1843               nat_elog_notice ("maximum reassemblies exceeded");
1844               goto trace0;
1845             }
1846
1847           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1848             {
1849               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1850                 {
1851                   if (is_output_feature)
1852                     {
1853                       if (PREDICT_FALSE
1854                           (nat_not_translate_output_feature_fwd
1855                            (sm, ip0, thread_index, now, vm, b0)))
1856                         reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1857                       goto trace0;
1858                     }
1859
1860                   next0 = icmp_in2out_ed_slow_path
1861                     (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1862                      next0, now, thread_index, &s0);
1863
1864                   if (PREDICT_TRUE (next0 != NAT_IN2OUT_ED_NEXT_DROP))
1865                     {
1866                       if (s0)
1867                         reass0->sess_index = s0 - per_thread_data->sessions;
1868                       else
1869                         reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1870                       nat_ip4_reass_get_frags (reass0,
1871                                                &fragments_to_loopback);
1872                     }
1873
1874                   goto trace0;
1875                 }
1876
1877               make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
1878                           ip0->protocol, rx_fib_index0, udp0->src_port,
1879                           udp0->dst_port);
1880
1881               if (clib_bihash_search_16_8
1882                   (&per_thread_data->in2out_ed, &kv0, &value0))
1883                 {
1884                   if (is_output_feature)
1885                     {
1886                       if (PREDICT_FALSE
1887                           (nat44_ed_not_translate_output_feature
1888                            (sm, ip0, ip0->protocol, udp0->src_port,
1889                             udp0->dst_port, thread_index, sw_if_index0,
1890                             vnet_buffer (b0)->sw_if_index[VLIB_TX])))
1891                         {
1892                           reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1893                           nat_ip4_reass_get_frags (reass0,
1894                                                    &fragments_to_loopback);
1895                           goto trace0;
1896                         }
1897                     }
1898                   else
1899                     {
1900                       if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1901                                                                  sw_if_index0,
1902                                                                  ip0, proto0,
1903                                                                  rx_fib_index0,
1904                                                                  thread_index)))
1905                         {
1906                           reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1907                           nat_ip4_reass_get_frags (reass0,
1908                                                    &fragments_to_loopback);
1909                           goto trace0;
1910                         }
1911                     }
1912
1913                   next0 = slow_path_ed (sm, b0, rx_fib_index0, &kv0,
1914                                         &s0, node, next0, thread_index, now,
1915                                         tcp0);
1916
1917                   if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
1918                     goto trace0;
1919
1920                   if (PREDICT_FALSE (!s0))
1921                     {
1922                       reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1923                       goto trace0;
1924                     }
1925
1926                   reass0->sess_index = s0 - per_thread_data->sessions;
1927                 }
1928               else
1929                 {
1930                   s0 = pool_elt_at_index (per_thread_data->sessions,
1931                                           value0.value);
1932                   reass0->sess_index = value0.value;
1933                 }
1934               nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1935             }
1936           else
1937             {
1938               if (reass0->flags & NAT_REASS_FLAG_ED_DONT_TRANSLATE)
1939                 goto trace0;
1940               if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
1941                 {
1942                   if (nat_ip4_reass_add_fragment
1943                       (thread_index, reass0, bi0, &fragments_to_drop))
1944                     {
1945                       b0->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_FRAG];
1946                       nat_elog_notice
1947                         ("maximum fragments per reassembly exceeded");
1948                       next0 = NAT_IN2OUT_ED_NEXT_DROP;
1949                       goto trace0;
1950                     }
1951                   cached0 = 1;
1952                   goto trace0;
1953                 }
1954               s0 = pool_elt_at_index (per_thread_data->sessions,
1955                                       reass0->sess_index);
1956             }
1957
1958           old_addr0 = ip0->src_address.as_u32;
1959           ip0->src_address = s0->out2in.addr;
1960           new_addr0 = ip0->src_address.as_u32;
1961           if (!is_output_feature)
1962             vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1963
1964           sum0 = ip0->checksum;
1965           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1966                                  ip4_header_t,
1967                                  src_address /* changed member */ );
1968           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1969             sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1970                                    s0->ext_host_addr.as_u32, ip4_header_t,
1971                                    dst_address);
1972           ip0->checksum = ip_csum_fold (sum0);
1973
1974           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1975             {
1976               old_port0 = udp0->src_port;
1977               new_port0 = udp0->src_port = s0->out2in.port;
1978
1979               if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1980                 {
1981                   sum0 = tcp0->checksum;
1982                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1983                                          ip4_header_t,
1984                                          dst_address /* changed member */ );
1985                   sum0 = ip_csum_update (sum0, old_port0, new_port0,
1986                                          ip4_header_t /* cheat */ ,
1987                                          length /* changed member */ );
1988                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
1989                     {
1990                       sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1991                                              s0->ext_host_addr.as_u32,
1992                                              ip4_header_t, dst_address);
1993                       sum0 = ip_csum_update (sum0, tcp0->dst_port,
1994                                              s0->ext_host_port, ip4_header_t,
1995                                              length);
1996                       tcp0->dst_port = s0->ext_host_port;
1997                       ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1998                     }
1999                   tcp0->checksum = ip_csum_fold (sum0);
2000                 }
2001               else if (udp0->checksum)
2002                 {
2003                   sum0 = udp0->checksum;
2004                   sum0 =
2005                     ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
2006                                     dst_address);
2007                   sum0 =
2008                     ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
2009                                     length);
2010                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
2011                     {
2012                       sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
2013                                              s0->ext_host_addr.as_u32,
2014                                              ip4_header_t, dst_address);
2015                       sum0 = ip_csum_update (sum0, tcp0->dst_port,
2016                                              s0->ext_host_port, ip4_header_t,
2017                                              length);
2018                       udp0->dst_port = s0->ext_host_port;
2019                       ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
2020                     }
2021                   udp0->checksum = ip_csum_fold (sum0);
2022                 }
2023               else
2024                 {
2025                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
2026                     {
2027                       udp0->dst_port = s0->ext_host_port;
2028                       ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
2029                     }
2030                 }
2031             }
2032
2033           /* Hairpinning */
2034           nat44_reass_hairpinning (sm, b0, ip0, s0->out2in.port,
2035                                    s0->ext_host_port, proto0, 1);
2036
2037           /* Accounting */
2038           nat44_session_update_counters (s0, now,
2039                                          vlib_buffer_length_in_chain (vm, b0),
2040                                          thread_index);
2041           /* Per-user LRU list maintenance */
2042           nat44_session_update_lru (sm, s0, thread_index);
2043
2044         trace0:
2045           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
2046                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2047             {
2048               nat44_reass_trace_t *t =
2049                 vlib_add_trace (vm, node, b0, sizeof (*t));
2050               t->cached = cached0;
2051               t->sw_if_index = sw_if_index0;
2052               t->next_index = next0;
2053             }
2054
2055           if (cached0)
2056             {
2057               n_left_to_next++;
2058               to_next--;
2059               cached_fragments++;
2060             }
2061           else
2062             {
2063               pkts_processed += next0 != NAT_IN2OUT_ED_NEXT_DROP;
2064
2065               /* verify speculative enqueue, maybe switch current next frame */
2066               vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2067                                                to_next, n_left_to_next,
2068                                                bi0, next0);
2069             }
2070
2071           if (n_left_from == 0 && vec_len (fragments_to_loopback))
2072             {
2073               from = vlib_frame_vector_args (frame);
2074               u32 len = vec_len (fragments_to_loopback);
2075               if (len <= VLIB_FRAME_SIZE)
2076                 {
2077                   clib_memcpy_fast (from, fragments_to_loopback,
2078                                     sizeof (u32) * len);
2079                   n_left_from = len;
2080                   vec_reset_length (fragments_to_loopback);
2081                 }
2082               else
2083                 {
2084                   clib_memcpy_fast (from, fragments_to_loopback +
2085                                     (len - VLIB_FRAME_SIZE),
2086                                     sizeof (u32) * VLIB_FRAME_SIZE);
2087                   n_left_from = VLIB_FRAME_SIZE;
2088                   _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
2089                 }
2090             }
2091         }
2092
2093       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2094     }
2095
2096   vlib_node_increment_counter (vm, sm->ed_in2out_reass_node_index,
2097                                NAT_IN2OUT_ED_ERROR_PROCESSED_FRAGMENTS,
2098                                pkts_processed);
2099   vlib_node_increment_counter (vm, sm->ed_in2out_reass_node_index,
2100                                NAT_IN2OUT_ED_ERROR_CACHED_FRAGMENTS,
2101                                cached_fragments);
2102
2103   nat_send_all_to_node (vm, fragments_to_drop, node,
2104                         &node->errors[NAT_IN2OUT_ED_ERROR_DROP_FRAGMENT],
2105                         NAT_IN2OUT_ED_NEXT_DROP);
2106
2107   vec_free (fragments_to_drop);
2108   vec_free (fragments_to_loopback);
2109   return frame->n_vectors;
2110 }
2111
2112 VLIB_NODE_FN (nat44_ed_in2out_reass_node) (vlib_main_t * vm,
2113                                            vlib_node_runtime_t * node,
2114                                            vlib_frame_t * frame)
2115 {
2116   return nat44_ed_in2out_reass_node_fn_inline (vm, node, frame, 0);
2117 }
2118
2119 /* *INDENT-OFF* */
2120 VLIB_REGISTER_NODE (nat44_ed_in2out_reass_node) = {
2121   .name = "nat44-ed-in2out-reass",
2122   .vector_size = sizeof (u32),
2123   .format_trace = format_nat44_reass_trace,
2124   .type = VLIB_NODE_TYPE_INTERNAL,
2125   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
2126   .error_strings = nat_in2out_ed_error_strings,
2127   .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
2128   .next_nodes = {
2129     [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
2130     [NAT_IN2OUT_ED_NEXT_LOOKUP] = "ip4-lookup",
2131     [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2132     [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2133     [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
2134   },
2135 };
2136 /* *INDENT-ON* */
2137
2138 VLIB_NODE_FN (nat44_ed_in2out_reass_output_node) (vlib_main_t * vm,
2139                                                   vlib_node_runtime_t * node,
2140                                                   vlib_frame_t * frame)
2141 {
2142   return nat44_ed_in2out_reass_node_fn_inline (vm, node, frame, 1);
2143 }
2144
2145 /* *INDENT-OFF* */
2146 VLIB_REGISTER_NODE (nat44_ed_in2out_reass_output_node) = {
2147   .name = "nat44-ed-in2out-reass-output",
2148   .vector_size = sizeof (u32),
2149   .format_trace = format_nat44_reass_trace,
2150   .type = VLIB_NODE_TYPE_INTERNAL,
2151   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
2152   .error_strings = nat_in2out_ed_error_strings,
2153   .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
2154   .next_nodes = {
2155     [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
2156     [NAT_IN2OUT_ED_NEXT_LOOKUP] = "interface-output",
2157     [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2158     [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2159     [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
2160   },
2161 };
2162 /* *INDENT-ON* */
2163
2164 /*
2165  * fd.io coding-style-patch-verification: ON
2166  *
2167  * Local Variables:
2168  * eval: (c-set-style "gnu")
2169  * End:
2170  */