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