nat: handoff traffic matching for dynamic NAT
[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           if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1049             {
1050               old_port0 = tcp0->src_port;
1051               new_port0 = tcp0->src_port = s0->out2in.port;
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
1077             {
1078               udp0->src_port = s0->out2in.port;
1079               udp0->checksum = 0;
1080               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1081                 {
1082                   udp0->dst_port = s0->ext_host_port;
1083                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1084                 }
1085               udp_packets++;
1086             }
1087
1088           /* Accounting */
1089           nat44_session_update_counters (s0, now,
1090                                          vlib_buffer_length_in_chain (vm,
1091                                                                       b0),
1092                                          thread_index);
1093           /* Per-user LRU list maintenance */
1094           nat44_session_update_lru (sm, s0, thread_index);
1095
1096         trace00:
1097           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1098                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1099             {
1100               nat_in2out_ed_trace_t *t =
1101                 vlib_add_trace (vm, node, b0, sizeof (*t));
1102               t->is_slow_path = is_slow_path;
1103               t->sw_if_index = sw_if_index0;
1104               t->next_index = next0;
1105               t->session_index = ~0;
1106               if (s0)
1107                 t->session_index = s0 - tsm->sessions;
1108             }
1109
1110           pkts_processed += next0 == NAT_IN2OUT_ED_NEXT_LOOKUP;
1111
1112
1113           next1 = NAT_IN2OUT_ED_NEXT_LOOKUP;
1114
1115           if (is_output_feature)
1116             iph_offset1 = vnet_buffer (b1)->ip.save_rewrite_length;
1117
1118           ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) +
1119                                   iph_offset1);
1120
1121           sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1122           rx_fib_index1 =
1123             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1124                                                  sw_if_index1);
1125
1126           if (PREDICT_FALSE (ip1->ttl == 1))
1127             {
1128               vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1129               icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1130                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1131                                            0);
1132               next1 = NAT_IN2OUT_ED_NEXT_ICMP_ERROR;
1133               goto trace01;
1134             }
1135
1136           udp1 = ip4_next_header (ip1);
1137           tcp1 = (tcp_header_t *) udp1;
1138           icmp1 = (icmp46_header_t *) udp1;
1139           proto1 = ip_proto_to_snat_proto (ip1->protocol);
1140
1141           if (is_slow_path)
1142             {
1143               if (PREDICT_FALSE (proto1 == ~0))
1144                 {
1145                   s1 = nat44_ed_in2out_unknown_proto (sm, b1, ip1,
1146                                                       rx_fib_index1,
1147                                                       thread_index, now, vm,
1148                                                       node);
1149                   if (!s1)
1150                     next1 = NAT_IN2OUT_ED_NEXT_DROP;
1151                   other_packets++;
1152                   goto trace01;
1153                 }
1154
1155               if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1156                 {
1157                   next1 = icmp_in2out_ed_slow_path
1158                     (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1159                      next1, now, thread_index, &s1);
1160                   icmp_packets++;
1161                   goto trace01;
1162                 }
1163             }
1164           else
1165             {
1166               if (PREDICT_FALSE (proto1 == ~0))
1167                 {
1168                   next1 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1169                   goto trace01;
1170                 }
1171
1172               if (ip4_is_fragment (ip1))
1173                 {
1174                   next1 = NAT_IN2OUT_ED_NEXT_REASS;
1175                   fragments++;
1176                   goto trace01;
1177                 }
1178
1179               if (is_output_feature)
1180                 {
1181                   if (PREDICT_FALSE
1182                       (nat_not_translate_output_feature_fwd
1183                        (sm, ip1, thread_index, now, vm, b1)))
1184                     goto trace01;
1185                 }
1186
1187               if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1188                 {
1189                   next1 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1190                   goto trace01;
1191                 }
1192             }
1193
1194           make_ed_kv (&kv1, &ip1->src_address, &ip1->dst_address,
1195                       ip1->protocol, rx_fib_index1, udp1->src_port,
1196                       udp1->dst_port);
1197
1198           if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv1, &value1))
1199             {
1200               if (is_slow_path)
1201                 {
1202                   if (is_output_feature)
1203                     {
1204                       if (PREDICT_FALSE
1205                           (nat44_ed_not_translate_output_feature
1206                            (sm, ip1, ip1->protocol, udp1->src_port,
1207                             udp1->dst_port, thread_index, sw_if_index1,
1208                             vnet_buffer (b1)->sw_if_index[VLIB_TX])))
1209                         goto trace01;
1210                     }
1211                   else
1212                     {
1213                       if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1214                                                                  sw_if_index1,
1215                                                                  ip1, proto1,
1216                                                                  rx_fib_index1,
1217                                                                  thread_index)))
1218                         goto trace01;
1219                     }
1220
1221                   next1 =
1222                     slow_path_ed (sm, b1, rx_fib_index1, &kv1, &s1, node,
1223                                   next1, thread_index, now, tcp1);
1224
1225                   if (PREDICT_FALSE (next1 == NAT_IN2OUT_ED_NEXT_DROP))
1226                     goto trace01;
1227
1228                   if (PREDICT_FALSE (!s1))
1229                     goto trace01;
1230                 }
1231               else
1232                 {
1233                   next1 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1234                   goto trace01;
1235                 }
1236             }
1237           else
1238             {
1239               s1 = pool_elt_at_index (tsm->sessions, value1.value);
1240             }
1241
1242           b1->flags |= VNET_BUFFER_F_IS_NATED;
1243
1244           if (!is_output_feature)
1245             vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index;
1246
1247           old_addr1 = ip1->src_address.as_u32;
1248           new_addr1 = ip1->src_address.as_u32 = s1->out2in.addr.as_u32;
1249           sum1 = ip1->checksum;
1250           sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
1251                                  src_address);
1252           if (PREDICT_FALSE (is_twice_nat_session (s1)))
1253             sum1 = ip_csum_update (sum1, ip1->dst_address.as_u32,
1254                                    s1->ext_host_addr.as_u32, ip4_header_t,
1255                                    dst_address);
1256           ip1->checksum = ip_csum_fold (sum1);
1257
1258           if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
1259             {
1260               old_port1 = tcp1->src_port;
1261               new_port1 = tcp1->src_port = s1->out2in.port;
1262
1263               sum1 = tcp1->checksum;
1264               sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
1265                                      dst_address);
1266               sum1 = ip_csum_update (sum1, old_port1, new_port1, ip4_header_t,
1267                                      length);
1268               if (PREDICT_FALSE (is_twice_nat_session (s1)))
1269                 {
1270                   sum1 = ip_csum_update (sum1, ip1->dst_address.as_u32,
1271                                          s1->ext_host_addr.as_u32,
1272                                          ip4_header_t, dst_address);
1273                   sum1 = ip_csum_update (sum1, tcp1->dst_port,
1274                                          s1->ext_host_port, ip4_header_t,
1275                                          length);
1276                   tcp1->dst_port = s1->ext_host_port;
1277                   ip1->dst_address.as_u32 = s1->ext_host_addr.as_u32;
1278                 }
1279               tcp1->checksum = ip_csum_fold (sum1);
1280               mss_clamping (sm, tcp1, &sum1);
1281               tcp_packets++;
1282               if (nat44_set_tcp_session_state_i2o
1283                   (sm, s1, tcp1, thread_index))
1284                 goto trace01;
1285             }
1286           else
1287             {
1288               udp1->src_port = s1->out2in.port;
1289               udp1->checksum = 0;
1290               if (PREDICT_FALSE (is_twice_nat_session (s1)))
1291                 {
1292                   udp1->dst_port = s1->ext_host_port;
1293                   ip1->dst_address.as_u32 = s1->ext_host_addr.as_u32;
1294                 }
1295               udp_packets++;
1296             }
1297
1298           /* Accounting */
1299           nat44_session_update_counters (s1, now,
1300                                          vlib_buffer_length_in_chain (vm, b1),
1301                                          thread_index);
1302           /* Per-user LRU list maintenance */
1303           nat44_session_update_lru (sm, s1, thread_index);
1304
1305         trace01:
1306           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1307                              && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1308             {
1309               nat_in2out_ed_trace_t *t =
1310                 vlib_add_trace (vm, node, b1, sizeof (*t));
1311               t->is_slow_path = is_slow_path;
1312               t->sw_if_index = sw_if_index1;
1313               t->next_index = next1;
1314               t->session_index = ~0;
1315               if (s1)
1316                 t->session_index = s1 - tsm->sessions;
1317             }
1318
1319           pkts_processed += next1 == NAT_IN2OUT_ED_NEXT_LOOKUP;
1320
1321           /* verify speculative enqueues, maybe switch current next frame */
1322           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1323                                            to_next, n_left_to_next,
1324                                            bi0, bi1, next0, next1);
1325         }
1326
1327       while (n_left_from > 0 && n_left_to_next > 0)
1328         {
1329           u32 bi0;
1330           vlib_buffer_t *b0;
1331           u32 next0, sw_if_index0, rx_fib_index0, iph_offset0 = 0, proto0,
1332             new_addr0, old_addr0;
1333           u16 old_port0, new_port0;
1334           ip4_header_t *ip0;
1335           udp_header_t *udp0;
1336           tcp_header_t *tcp0;
1337           icmp46_header_t *icmp0;
1338           snat_session_t *s0 = 0;
1339           clib_bihash_kv_16_8_t kv0, value0;
1340           ip_csum_t sum0;
1341
1342           /* speculatively enqueue b0 to the current next frame */
1343           bi0 = from[0];
1344           to_next[0] = bi0;
1345           from += 1;
1346           to_next += 1;
1347           n_left_from -= 1;
1348           n_left_to_next -= 1;
1349
1350           b0 = vlib_get_buffer (vm, bi0);
1351           next0 = NAT_IN2OUT_ED_NEXT_LOOKUP;
1352
1353           if (is_output_feature)
1354             iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1355
1356           ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1357                                   iph_offset0);
1358
1359           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1360           rx_fib_index0 =
1361             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1362                                                  sw_if_index0);
1363
1364           if (PREDICT_FALSE (ip0->ttl == 1))
1365             {
1366               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1367               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1368                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1369                                            0);
1370               next0 = NAT_IN2OUT_ED_NEXT_ICMP_ERROR;
1371               goto trace0;
1372             }
1373
1374           udp0 = ip4_next_header (ip0);
1375           tcp0 = (tcp_header_t *) udp0;
1376           icmp0 = (icmp46_header_t *) udp0;
1377           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1378
1379           if (is_slow_path)
1380             {
1381               if (PREDICT_FALSE (proto0 == ~0))
1382                 {
1383                   s0 = nat44_ed_in2out_unknown_proto (sm, b0, ip0,
1384                                                       rx_fib_index0,
1385                                                       thread_index, now, vm,
1386                                                       node);
1387                   if (!s0)
1388                     next0 = NAT_IN2OUT_ED_NEXT_DROP;
1389                   other_packets++;
1390                   goto trace0;
1391                 }
1392
1393               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1394                 {
1395                   next0 = icmp_in2out_ed_slow_path
1396                     (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1397                      next0, now, thread_index, &s0);
1398                   icmp_packets++;
1399                   goto trace0;
1400                 }
1401             }
1402           else
1403             {
1404               if (PREDICT_FALSE (proto0 == ~0))
1405                 {
1406                   next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1407                   goto trace0;
1408                 }
1409
1410               if (ip4_is_fragment (ip0))
1411                 {
1412                   next0 = NAT_IN2OUT_ED_NEXT_REASS;
1413                   fragments++;
1414                   goto trace0;
1415                 }
1416
1417               if (is_output_feature)
1418                 {
1419                   if (PREDICT_FALSE
1420                       (nat_not_translate_output_feature_fwd
1421                        (sm, ip0, thread_index, now, vm, b0)))
1422                     goto trace0;
1423                 }
1424
1425               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1426                 {
1427                   next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1428                   goto trace0;
1429                 }
1430             }
1431
1432           make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
1433                       ip0->protocol, rx_fib_index0, udp0->src_port,
1434                       udp0->dst_port);
1435
1436           if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
1437             {
1438               if (is_slow_path)
1439                 {
1440                   if (is_output_feature)
1441                     {
1442                       if (PREDICT_FALSE
1443                           (nat44_ed_not_translate_output_feature
1444                            (sm, ip0, ip0->protocol, udp0->src_port,
1445                             udp0->dst_port, thread_index, sw_if_index0,
1446                             vnet_buffer (b0)->sw_if_index[VLIB_TX])))
1447                         goto trace0;
1448                     }
1449                   else
1450                     {
1451                       if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1452                                                                  sw_if_index0,
1453                                                                  ip0, proto0,
1454                                                                  rx_fib_index0,
1455                                                                  thread_index)))
1456                         goto trace0;
1457                     }
1458
1459                   next0 =
1460                     slow_path_ed (sm, b0, rx_fib_index0, &kv0, &s0, node,
1461                                   next0, thread_index, now, tcp0);
1462
1463                   if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
1464                     goto trace0;
1465
1466                   if (PREDICT_FALSE (!s0))
1467                     goto trace0;
1468                 }
1469               else
1470                 {
1471                   next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1472                   goto trace0;
1473                 }
1474             }
1475           else
1476             {
1477               s0 = pool_elt_at_index (tsm->sessions, value0.value);
1478             }
1479
1480           b0->flags |= VNET_BUFFER_F_IS_NATED;
1481
1482           if (!is_output_feature)
1483             vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1484
1485           old_addr0 = ip0->src_address.as_u32;
1486           new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
1487           sum0 = ip0->checksum;
1488           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1489                                  src_address);
1490           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1491             sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1492                                    s0->ext_host_addr.as_u32, ip4_header_t,
1493                                    dst_address);
1494           ip0->checksum = ip_csum_fold (sum0);
1495
1496           if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1497             {
1498               old_port0 = tcp0->src_port;
1499               new_port0 = tcp0->src_port = s0->out2in.port;
1500
1501               sum0 = tcp0->checksum;
1502               sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1503                                      dst_address);
1504               sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1505                                      length);
1506               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1507                 {
1508                   sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1509                                          s0->ext_host_addr.as_u32,
1510                                          ip4_header_t, dst_address);
1511                   sum0 = ip_csum_update (sum0, tcp0->dst_port,
1512                                          s0->ext_host_port, ip4_header_t,
1513                                          length);
1514                   tcp0->dst_port = s0->ext_host_port;
1515                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1516                 }
1517               mss_clamping (sm, tcp0, &sum0);
1518               tcp0->checksum = ip_csum_fold (sum0);
1519               tcp_packets++;
1520               if (nat44_set_tcp_session_state_i2o
1521                   (sm, s0, tcp0, thread_index))
1522                 goto trace0;
1523             }
1524           else
1525             {
1526               udp0->src_port = s0->out2in.port;
1527               udp0->checksum = 0;
1528               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1529                 {
1530                   udp0->dst_port = s0->ext_host_port;
1531                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1532                 }
1533               udp_packets++;
1534             }
1535
1536           /* Accounting */
1537           nat44_session_update_counters (s0, now,
1538                                          vlib_buffer_length_in_chain (vm, b0),
1539                                          thread_index);
1540           /* Per-user LRU list maintenance */
1541           nat44_session_update_lru (sm, s0, thread_index);
1542
1543         trace0:
1544           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1545                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1546             {
1547               nat_in2out_ed_trace_t *t =
1548                 vlib_add_trace (vm, node, b0, sizeof (*t));
1549               t->is_slow_path = is_slow_path;
1550               t->sw_if_index = sw_if_index0;
1551               t->next_index = next0;
1552               t->session_index = ~0;
1553               if (s0)
1554                 t->session_index = s0 - tsm->sessions;
1555             }
1556
1557           pkts_processed += next0 == NAT_IN2OUT_ED_NEXT_LOOKUP;
1558
1559           /* verify speculative enqueue, maybe switch current next frame */
1560           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1561                                            to_next, n_left_to_next,
1562                                            bi0, next0);
1563         }
1564
1565       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1566     }
1567
1568   vlib_node_increment_counter (vm, stats_node_index,
1569                                NAT_IN2OUT_ED_ERROR_IN2OUT_PACKETS,
1570                                pkts_processed);
1571   vlib_node_increment_counter (vm, stats_node_index,
1572                                NAT_IN2OUT_ED_ERROR_TCP_PACKETS, tcp_packets);
1573   vlib_node_increment_counter (vm, stats_node_index,
1574                                NAT_IN2OUT_ED_ERROR_UDP_PACKETS, tcp_packets);
1575   vlib_node_increment_counter (vm, stats_node_index,
1576                                NAT_IN2OUT_ED_ERROR_ICMP_PACKETS,
1577                                icmp_packets);
1578   vlib_node_increment_counter (vm, stats_node_index,
1579                                NAT_IN2OUT_ED_ERROR_OTHER_PACKETS,
1580                                other_packets);
1581   vlib_node_increment_counter (vm, stats_node_index,
1582                                NAT_IN2OUT_ED_ERROR_FRAGMENTS, fragments);
1583
1584   return frame->n_vectors;
1585 }
1586
1587 VLIB_NODE_FN (nat44_ed_in2out_node) (vlib_main_t * vm,
1588                                      vlib_node_runtime_t * node,
1589                                      vlib_frame_t * frame)
1590 {
1591   return nat44_ed_in2out_node_fn_inline (vm, node, frame, 0, 0);
1592 }
1593
1594 /* *INDENT-OFF* */
1595 VLIB_REGISTER_NODE (nat44_ed_in2out_node) = {
1596   .name = "nat44-ed-in2out",
1597   .vector_size = sizeof (u32),
1598   .format_trace = format_nat_in2out_ed_trace,
1599   .type = VLIB_NODE_TYPE_INTERNAL,
1600   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1601   .error_strings = nat_in2out_ed_error_strings,
1602   .runtime_data_bytes = sizeof (snat_runtime_t),
1603   .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1604   .next_nodes = {
1605     [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1606     [NAT_IN2OUT_ED_NEXT_LOOKUP] = "ip4-lookup",
1607     [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-slowpath",
1608     [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1609     [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
1610   },
1611 };
1612 /* *INDENT-ON* */
1613
1614 VLIB_NODE_FN (nat44_ed_in2out_output_node) (vlib_main_t * vm,
1615                                             vlib_node_runtime_t * node,
1616                                             vlib_frame_t * frame)
1617 {
1618   return nat44_ed_in2out_node_fn_inline (vm, node, frame, 0, 1);
1619 }
1620
1621 /* *INDENT-OFF* */
1622 VLIB_REGISTER_NODE (nat44_ed_in2out_output_node) = {
1623   .name = "nat44-ed-in2out-output",
1624   .vector_size = sizeof (u32),
1625   .format_trace = format_nat_in2out_ed_trace,
1626   .type = VLIB_NODE_TYPE_INTERNAL,
1627   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1628   .error_strings = nat_in2out_ed_error_strings,
1629   .runtime_data_bytes = sizeof (snat_runtime_t),
1630   .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1631   .next_nodes = {
1632     [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1633     [NAT_IN2OUT_ED_NEXT_LOOKUP] = "interface-output",
1634     [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
1635     [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1636     [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass-output",
1637   },
1638 };
1639 /* *INDENT-ON* */
1640
1641 VLIB_NODE_FN (nat44_ed_in2out_slowpath_node) (vlib_main_t * vm,
1642                                               vlib_node_runtime_t * node,
1643                                               vlib_frame_t * frame)
1644 {
1645   return nat44_ed_in2out_node_fn_inline (vm, node, frame, 1, 0);
1646 }
1647
1648 /* *INDENT-OFF* */
1649 VLIB_REGISTER_NODE (nat44_ed_in2out_slowpath_node) = {
1650   .name = "nat44-ed-in2out-slowpath",
1651   .vector_size = sizeof (u32),
1652   .format_trace = format_nat_in2out_ed_trace,
1653   .type = VLIB_NODE_TYPE_INTERNAL,
1654   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1655   .error_strings = nat_in2out_ed_error_strings,
1656   .runtime_data_bytes = sizeof (snat_runtime_t),
1657   .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1658   .next_nodes = {
1659     [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1660     [NAT_IN2OUT_ED_NEXT_LOOKUP] = "ip4-lookup",
1661     [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-slowpath",
1662     [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1663     [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
1664   },
1665 };
1666 /* *INDENT-ON* */
1667
1668 VLIB_NODE_FN (nat44_ed_in2out_output_slowpath_node) (vlib_main_t * vm,
1669                                                      vlib_node_runtime_t *
1670                                                      node,
1671                                                      vlib_frame_t * frame)
1672 {
1673   return nat44_ed_in2out_node_fn_inline (vm, node, frame, 1, 1);
1674 }
1675
1676 /* *INDENT-OFF* */
1677 VLIB_REGISTER_NODE (nat44_ed_in2out_output_slowpath_node) = {
1678   .name = "nat44-ed-in2out-output-slowpath",
1679   .vector_size = sizeof (u32),
1680   .format_trace = format_nat_in2out_ed_trace,
1681   .type = VLIB_NODE_TYPE_INTERNAL,
1682   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1683   .error_strings = nat_in2out_ed_error_strings,
1684   .runtime_data_bytes = sizeof (snat_runtime_t),
1685   .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1686   .next_nodes = {
1687     [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1688     [NAT_IN2OUT_ED_NEXT_LOOKUP] = "interface-output",
1689     [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
1690     [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1691     [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
1692   },
1693 };
1694 /* *INDENT-ON* */
1695
1696 static inline uword
1697 nat44_ed_in2out_reass_node_fn_inline (vlib_main_t * vm,
1698                                       vlib_node_runtime_t * node,
1699                                       vlib_frame_t * frame,
1700                                       int is_output_feature)
1701 {
1702   u32 n_left_from, *from, *to_next;
1703   nat_in2out_ed_next_t next_index;
1704   u32 pkts_processed = 0, cached_fragments = 0;
1705   snat_main_t *sm = &snat_main;
1706   f64 now = vlib_time_now (vm);
1707   u32 thread_index = vm->thread_index;
1708   snat_main_per_thread_data_t *per_thread_data =
1709     &sm->per_thread_data[thread_index];
1710   u32 *fragments_to_drop = 0;
1711   u32 *fragments_to_loopback = 0;
1712
1713   from = vlib_frame_vector_args (frame);
1714   n_left_from = frame->n_vectors;
1715   next_index = node->cached_next_index;
1716
1717   while (n_left_from > 0)
1718     {
1719       u32 n_left_to_next;
1720
1721       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1722
1723       while (n_left_from > 0 && n_left_to_next > 0)
1724         {
1725           u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1726           u32 iph_offset0 = 0;
1727           vlib_buffer_t *b0;
1728           u32 next0;
1729           u8 cached0 = 0;
1730           ip4_header_t *ip0 = 0;
1731           nat_reass_ip4_t *reass0;
1732           udp_header_t *udp0;
1733           tcp_header_t *tcp0;
1734           icmp46_header_t *icmp0;
1735           clib_bihash_kv_16_8_t kv0, value0;
1736           snat_session_t *s0 = 0;
1737           u16 old_port0, new_port0;
1738           ip_csum_t sum0;
1739
1740           /* speculatively enqueue b0 to the current next frame */
1741           bi0 = from[0];
1742           to_next[0] = bi0;
1743           from += 1;
1744           to_next += 1;
1745           n_left_from -= 1;
1746           n_left_to_next -= 1;
1747
1748           b0 = vlib_get_buffer (vm, bi0);
1749
1750           next0 = NAT_IN2OUT_ED_NEXT_LOOKUP;
1751
1752           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1753           rx_fib_index0 =
1754             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1755                                                  sw_if_index0);
1756
1757           if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
1758             {
1759               next0 = NAT_IN2OUT_ED_NEXT_DROP;
1760               b0->error = node->errors[NAT_IN2OUT_ED_ERROR_DROP_FRAGMENT];
1761               goto trace0;
1762             }
1763
1764           if (is_output_feature)
1765             iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1766
1767           ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1768                                   iph_offset0);
1769
1770           udp0 = ip4_next_header (ip0);
1771           tcp0 = (tcp_header_t *) udp0;
1772           icmp0 = (icmp46_header_t *) udp0;
1773           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1774
1775           reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1776                                                  ip0->dst_address,
1777                                                  ip0->fragment_id,
1778                                                  ip0->protocol,
1779                                                  1, &fragments_to_drop);
1780
1781           if (PREDICT_FALSE (!reass0))
1782             {
1783               next0 = NAT_IN2OUT_ED_NEXT_DROP;
1784               b0->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_REASS];
1785               nat_elog_notice ("maximum reassemblies exceeded");
1786               goto trace0;
1787             }
1788
1789           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1790             {
1791               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1792                 {
1793                   if (is_output_feature)
1794                     {
1795                       if (PREDICT_FALSE
1796                           (nat_not_translate_output_feature_fwd
1797                            (sm, ip0, thread_index, now, vm, b0)))
1798                         reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1799                       goto trace0;
1800                     }
1801
1802                   next0 = icmp_in2out_ed_slow_path
1803                     (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1804                      next0, now, thread_index, &s0);
1805
1806                   if (PREDICT_TRUE (next0 != NAT_IN2OUT_ED_NEXT_DROP))
1807                     {
1808                       if (s0)
1809                         reass0->sess_index = s0 - per_thread_data->sessions;
1810                       else
1811                         reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1812                       nat_ip4_reass_get_frags (reass0,
1813                                                &fragments_to_loopback);
1814                     }
1815
1816                   goto trace0;
1817                 }
1818
1819               make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
1820                           ip0->protocol, rx_fib_index0, udp0->src_port,
1821                           udp0->dst_port);
1822
1823               if (clib_bihash_search_16_8
1824                   (&per_thread_data->in2out_ed, &kv0, &value0))
1825                 {
1826                   if (is_output_feature)
1827                     {
1828                       if (PREDICT_FALSE
1829                           (nat44_ed_not_translate_output_feature
1830                            (sm, ip0, ip0->protocol, udp0->src_port,
1831                             udp0->dst_port, thread_index, sw_if_index0,
1832                             vnet_buffer (b0)->sw_if_index[VLIB_TX])))
1833                         {
1834                           reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1835                           nat_ip4_reass_get_frags (reass0,
1836                                                    &fragments_to_loopback);
1837                           goto trace0;
1838                         }
1839                     }
1840                   else
1841                     {
1842                       if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1843                                                                  sw_if_index0,
1844                                                                  ip0, proto0,
1845                                                                  rx_fib_index0,
1846                                                                  thread_index)))
1847                         {
1848                           reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1849                           nat_ip4_reass_get_frags (reass0,
1850                                                    &fragments_to_loopback);
1851                           goto trace0;
1852                         }
1853                     }
1854
1855                   next0 = slow_path_ed (sm, b0, rx_fib_index0, &kv0,
1856                                         &s0, node, next0, thread_index, now,
1857                                         tcp0);
1858
1859                   if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
1860                     goto trace0;
1861
1862                   if (PREDICT_FALSE (!s0))
1863                     {
1864                       reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1865                       goto trace0;
1866                     }
1867
1868                   reass0->sess_index = s0 - per_thread_data->sessions;
1869                 }
1870               else
1871                 {
1872                   s0 = pool_elt_at_index (per_thread_data->sessions,
1873                                           value0.value);
1874                   reass0->sess_index = value0.value;
1875                 }
1876               nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1877             }
1878           else
1879             {
1880               if (reass0->flags & NAT_REASS_FLAG_ED_DONT_TRANSLATE)
1881                 goto trace0;
1882               if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
1883                 {
1884                   if (nat_ip4_reass_add_fragment
1885                       (thread_index, reass0, bi0, &fragments_to_drop))
1886                     {
1887                       b0->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_FRAG];
1888                       nat_elog_notice
1889                         ("maximum fragments per reassembly exceeded");
1890                       next0 = NAT_IN2OUT_ED_NEXT_DROP;
1891                       goto trace0;
1892                     }
1893                   cached0 = 1;
1894                   goto trace0;
1895                 }
1896               s0 = pool_elt_at_index (per_thread_data->sessions,
1897                                       reass0->sess_index);
1898             }
1899
1900           old_addr0 = ip0->src_address.as_u32;
1901           ip0->src_address = s0->out2in.addr;
1902           new_addr0 = ip0->src_address.as_u32;
1903           if (!is_output_feature)
1904             vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1905
1906           sum0 = ip0->checksum;
1907           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1908                                  ip4_header_t,
1909                                  src_address /* changed member */ );
1910           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1911             sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1912                                    s0->ext_host_addr.as_u32, ip4_header_t,
1913                                    dst_address);
1914           ip0->checksum = ip_csum_fold (sum0);
1915
1916           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1917             {
1918               if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1919                 {
1920                   old_port0 = tcp0->src_port;
1921                   tcp0->src_port = s0->out2in.port;
1922                   new_port0 = tcp0->src_port;
1923
1924                   sum0 = tcp0->checksum;
1925                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1926                                          ip4_header_t,
1927                                          dst_address /* changed member */ );
1928                   sum0 = ip_csum_update (sum0, old_port0, new_port0,
1929                                          ip4_header_t /* cheat */ ,
1930                                          length /* changed member */ );
1931                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
1932                     {
1933                       sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1934                                              s0->ext_host_addr.as_u32,
1935                                              ip4_header_t, dst_address);
1936                       sum0 = ip_csum_update (sum0, tcp0->dst_port,
1937                                              s0->ext_host_port, ip4_header_t,
1938                                              length);
1939                       tcp0->dst_port = s0->ext_host_port;
1940                       ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1941                     }
1942                   tcp0->checksum = ip_csum_fold (sum0);
1943                 }
1944               else
1945                 {
1946                   old_port0 = udp0->src_port;
1947                   udp0->src_port = s0->out2in.port;
1948                   udp0->checksum = 0;
1949                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
1950                     {
1951                       udp0->dst_port = s0->ext_host_port;
1952                       ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1953                     }
1954                 }
1955             }
1956
1957           /* Hairpinning */
1958           nat44_reass_hairpinning (sm, b0, ip0, s0->out2in.port,
1959                                    s0->ext_host_port, proto0, 1);
1960
1961           /* Accounting */
1962           nat44_session_update_counters (s0, now,
1963                                          vlib_buffer_length_in_chain (vm, b0),
1964                                          thread_index);
1965           /* Per-user LRU list maintenance */
1966           nat44_session_update_lru (sm, s0, thread_index);
1967
1968         trace0:
1969           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1970                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1971             {
1972               nat44_reass_trace_t *t =
1973                 vlib_add_trace (vm, node, b0, sizeof (*t));
1974               t->cached = cached0;
1975               t->sw_if_index = sw_if_index0;
1976               t->next_index = next0;
1977             }
1978
1979           if (cached0)
1980             {
1981               n_left_to_next++;
1982               to_next--;
1983               cached_fragments++;
1984             }
1985           else
1986             {
1987               pkts_processed += next0 != NAT_IN2OUT_ED_NEXT_DROP;
1988
1989               /* verify speculative enqueue, maybe switch current next frame */
1990               vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1991                                                to_next, n_left_to_next,
1992                                                bi0, next0);
1993             }
1994
1995           if (n_left_from == 0 && vec_len (fragments_to_loopback))
1996             {
1997               from = vlib_frame_vector_args (frame);
1998               u32 len = vec_len (fragments_to_loopback);
1999               if (len <= VLIB_FRAME_SIZE)
2000                 {
2001                   clib_memcpy_fast (from, fragments_to_loopback,
2002                                     sizeof (u32) * len);
2003                   n_left_from = len;
2004                   vec_reset_length (fragments_to_loopback);
2005                 }
2006               else
2007                 {
2008                   clib_memcpy_fast (from, fragments_to_loopback +
2009                                     (len - VLIB_FRAME_SIZE),
2010                                     sizeof (u32) * VLIB_FRAME_SIZE);
2011                   n_left_from = VLIB_FRAME_SIZE;
2012                   _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
2013                 }
2014             }
2015         }
2016
2017       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2018     }
2019
2020   vlib_node_increment_counter (vm, sm->ed_in2out_reass_node_index,
2021                                NAT_IN2OUT_ED_ERROR_PROCESSED_FRAGMENTS,
2022                                pkts_processed);
2023   vlib_node_increment_counter (vm, sm->ed_in2out_reass_node_index,
2024                                NAT_IN2OUT_ED_ERROR_CACHED_FRAGMENTS,
2025                                cached_fragments);
2026
2027   nat_send_all_to_node (vm, fragments_to_drop, node,
2028                         &node->errors[NAT_IN2OUT_ED_ERROR_DROP_FRAGMENT],
2029                         NAT_IN2OUT_ED_NEXT_DROP);
2030
2031   vec_free (fragments_to_drop);
2032   vec_free (fragments_to_loopback);
2033   return frame->n_vectors;
2034 }
2035
2036 VLIB_NODE_FN (nat44_ed_in2out_reass_node) (vlib_main_t * vm,
2037                                            vlib_node_runtime_t * node,
2038                                            vlib_frame_t * frame)
2039 {
2040   return nat44_ed_in2out_reass_node_fn_inline (vm, node, frame, 0);
2041 }
2042
2043 /* *INDENT-OFF* */
2044 VLIB_REGISTER_NODE (nat44_ed_in2out_reass_node) = {
2045   .name = "nat44-ed-in2out-reass",
2046   .vector_size = sizeof (u32),
2047   .format_trace = format_nat44_reass_trace,
2048   .type = VLIB_NODE_TYPE_INTERNAL,
2049   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
2050   .error_strings = nat_in2out_ed_error_strings,
2051   .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
2052   .next_nodes = {
2053     [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
2054     [NAT_IN2OUT_ED_NEXT_LOOKUP] = "ip4-lookup",
2055     [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2056     [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2057     [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
2058   },
2059 };
2060 /* *INDENT-ON* */
2061
2062 VLIB_NODE_FN (nat44_ed_in2out_reass_output_node) (vlib_main_t * vm,
2063                                                   vlib_node_runtime_t * node,
2064                                                   vlib_frame_t * frame)
2065 {
2066   return nat44_ed_in2out_reass_node_fn_inline (vm, node, frame, 1);
2067 }
2068
2069 /* *INDENT-OFF* */
2070 VLIB_REGISTER_NODE (nat44_ed_in2out_reass_output_node) = {
2071   .name = "nat44-ed-in2out-reass-output",
2072   .vector_size = sizeof (u32),
2073   .format_trace = format_nat44_reass_trace,
2074   .type = VLIB_NODE_TYPE_INTERNAL,
2075   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
2076   .error_strings = nat_in2out_ed_error_strings,
2077   .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
2078   .next_nodes = {
2079     [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
2080     [NAT_IN2OUT_ED_NEXT_LOOKUP] = "interface-output",
2081     [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2082     [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2083     [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
2084   },
2085 };
2086 /* *INDENT-ON* */
2087
2088 /*
2089  * fd.io coding-style-patch-verification: ON
2090  *
2091  * Local Variables:
2092  * eval: (c-set-style "gnu")
2093  * End:
2094  */