nat: cleanup & reorganization
[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/ip/ip.h>
23 #include <vnet/ethernet/ethernet.h>
24 #include <vnet/fib/ip4_fib.h>
25 #include <vnet/udp/udp_local.h>
26 #include <vppinfra/error.h>
27 #include <nat/nat.h>
28 #include <nat/lib/ipfix_logging.h>
29 #include <nat/nat_inlines.h>
30 #include <nat/nat44/inlines.h>
31 #include <nat/lib/nat_syslog.h>
32 #include <nat/nat_ha.h>
33 #include <nat/nat44/ed_inlines.h>
34 #include <nat/lib/nat_inlines.h>
35
36 /* number of attempts to get a port for ED overloading algorithm, if rolling
37  * a dice this many times doesn't produce a free port, it's treated
38  * as if there were no free ports available to conserve resources */
39 #define ED_PORT_ALLOC_ATTEMPTS (10)
40
41 static char *nat_in2out_ed_error_strings[] = {
42 #define _(sym,string) string,
43   foreach_nat_in2out_ed_error
44 #undef _
45 };
46
47 typedef struct
48 {
49   u32 sw_if_index;
50   u32 next_index;
51   u32 session_index;
52   u32 is_slow_path;
53 } nat_in2out_ed_trace_t;
54
55 static u8 *
56 format_nat_in2out_ed_trace (u8 * s, va_list * args)
57 {
58   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
59   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
60   nat_in2out_ed_trace_t *t = va_arg (*args, nat_in2out_ed_trace_t *);
61   char *tag;
62
63   tag =
64     t->is_slow_path ? "NAT44_IN2OUT_ED_SLOW_PATH" :
65     "NAT44_IN2OUT_ED_FAST_PATH";
66
67   s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
68               t->sw_if_index, t->next_index, t->session_index);
69
70   return s;
71 }
72
73 #ifndef CLIB_MARCH_VARIANT
74 int
75 nat44_i2o_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
76 {
77   snat_main_t *sm = &snat_main;
78   nat44_is_idle_session_ctx_t *ctx = arg;
79   snat_session_t *s;
80   u64 sess_timeout_time;
81   u8 proto;
82   u16 r_port, l_port;
83   ip4_address_t *l_addr, *r_addr;
84   u32 fib_index;
85   clib_bihash_kv_16_8_t ed_kv;
86   int i;
87   snat_address_t *a;
88   snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
89                                                        ctx->thread_index);
90
91   ASSERT (ctx->thread_index == ed_value_get_thread_index (kv));
92   s = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (kv));
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       l_addr = &s->out2in.addr;
100       r_addr = &s->ext_host_addr;
101       fib_index = s->out2in.fib_index;
102       if (snat_is_unk_proto_session (s))
103         {
104           proto = s->in2out.port;
105           r_port = 0;
106           l_port = 0;
107         }
108       else
109         {
110           proto = nat_proto_to_ip_proto (s->nat_proto);
111           l_port = s->out2in.port;
112           r_port = s->ext_host_port;
113         }
114       init_ed_k (&ed_kv, *l_addr, l_port, *r_addr, r_port, fib_index, proto);
115       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0))
116         nat_elog_warn ("out2in_ed key del failed");
117
118       if (snat_is_unk_proto_session (s))
119         goto delete;
120
121       nat_ipfix_logging_nat44_ses_delete (ctx->thread_index,
122                                           s->in2out.addr.as_u32,
123                                           s->out2in.addr.as_u32,
124                                           s->nat_proto,
125                                           s->in2out.port,
126                                           s->out2in.port,
127                                           s->in2out.fib_index);
128
129       nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
130                              &s->in2out.addr, s->in2out.port,
131                              &s->ext_host_nat_addr, s->ext_host_nat_port,
132                              &s->out2in.addr, s->out2in.port,
133                              &s->ext_host_addr, s->ext_host_port,
134                              s->nat_proto, is_twice_nat_session (s));
135
136       nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
137                    s->ext_host_port, s->nat_proto, s->out2in.fib_index,
138                    ctx->thread_index);
139
140       if (is_twice_nat_session (s))
141         {
142           for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
143             {
144               // TODO FIXME this is obviously broken - which address should be
145               // freed here?!
146               a = sm->twice_nat_addresses + i;
147               if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
148                 {
149                   snat_free_outside_address_and_port (sm->twice_nat_addresses,
150                                                       ctx->thread_index,
151                                                       &s->ext_host_nat_addr,
152                                                       s->ext_host_nat_port,
153                                                       s->nat_proto);
154                   break;
155                 }
156             }
157         }
158
159       if (snat_is_session_static (s))
160         goto delete;
161
162       snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
163                                           &s->out2in.addr, s->out2in.port,
164                                           s->nat_proto);
165     delete:
166       nat_ed_session_delete (sm, s, ctx->thread_index, 1);
167       return 1;
168     }
169
170   return 0;
171 }
172 #endif
173
174 static inline u32
175 icmp_in2out_ed_slow_path (snat_main_t * sm, vlib_buffer_t * b0,
176                           ip4_header_t * ip0, icmp46_header_t * icmp0,
177                           u32 sw_if_index0, u32 rx_fib_index0,
178                           vlib_node_runtime_t * node, u32 next0, f64 now,
179                           u32 thread_index, snat_session_t ** p_s0)
180 {
181   vlib_main_t *vm = vlib_get_main ();
182
183   next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
184                        next0, thread_index, p_s0, 0);
185   snat_session_t *s0 = *p_s0;
186   if (PREDICT_TRUE (next0 != NAT_NEXT_DROP && s0))
187     {
188       /* Accounting */
189       nat44_session_update_counters (s0, now,
190                                      vlib_buffer_length_in_chain
191                                      (vm, b0), thread_index);
192       /* Per-user LRU list maintenance */
193       nat44_session_update_lru (sm, s0, thread_index);
194     }
195   return next0;
196 }
197
198 static int
199 nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 rx_fib_index,
200                             u32 nat_proto, u32 thread_index,
201                             ip4_address_t r_addr, u16 r_port, u8 proto,
202                             u16 port_per_thread, u32 snat_thread_index,
203                             snat_session_t * s,
204                             ip4_address_t * outside_addr,
205                             u16 * outside_port,
206                             clib_bihash_kv_16_8_t * out2in_ed_kv)
207 {
208   int i;
209   snat_address_t *a, *ga = 0;
210   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
211
212   const u16 port_thread_offset = (port_per_thread * snat_thread_index) + 1024;
213
214   for (i = 0; i < vec_len (sm->addresses); i++)
215     {
216       a = sm->addresses + i;
217       switch (nat_proto)
218         {
219 #define _(N, j, n, unused)                                                   \
220   case NAT_PROTOCOL_##N:                                                     \
221     if (a->fib_index == rx_fib_index)                                        \
222       {                                                                      \
223         /* first try port suggested by caller */                             \
224         u16 port = clib_net_to_host_u16 (*outside_port);                     \
225         u16 port_offset = port - port_thread_offset;                         \
226         if (port <= port_thread_offset ||                                    \
227             port > port_thread_offset + port_per_thread)                     \
228           {                                                                  \
229             /* need to pick a different port, suggested port doesn't fit in  \
230              * this thread's port range */                                   \
231             port_offset = snat_random_port (0, port_per_thread - 1);         \
232             port = port_thread_offset + port_offset;                         \
233           }                                                                  \
234         u16 attempts = ED_PORT_ALLOC_ATTEMPTS;                               \
235         do                                                                   \
236           {                                                                  \
237             init_ed_kv (out2in_ed_kv, a->addr, clib_host_to_net_u16 (port),  \
238                         r_addr, r_port, s->out2in.fib_index, proto,          \
239                         thread_index, s - tsm->sessions);                    \
240             int rv = clib_bihash_add_del_16_8 (&sm->out2in_ed, out2in_ed_kv, \
241                                                2 /* is_add */);              \
242             if (0 == rv)                                                     \
243               {                                                              \
244                 ++a->busy_##n##_port_refcounts[port];                        \
245                 a->busy_##n##_ports_per_thread[thread_index]++;              \
246                 a->busy_##n##_ports++;                                       \
247                 *outside_addr = a->addr;                                     \
248                 *outside_port = clib_host_to_net_u16 (port);                 \
249                 return 0;                                                    \
250               }                                                              \
251             port_offset = snat_random_port (0, port_per_thread - 1);         \
252             port = port_thread_offset + port_offset;                         \
253             --attempts;                                                      \
254           }                                                                  \
255         while (attempts > 0);                                                \
256       }                                                                      \
257     else if (a->fib_index == ~0)                                             \
258       {                                                                      \
259         ga = a;                                                              \
260       }                                                                      \
261     break;
262
263           foreach_nat_protocol;
264         default:
265           nat_elog_info ("unknown protocol");
266           return 1;
267         }
268     }
269
270   if (ga)
271     {
272       /* fake fib_index to reuse macro */
273       rx_fib_index = ~0;
274       a = ga;
275       switch (nat_proto)
276         {
277           foreach_nat_protocol;
278         default:
279           nat_elog_info ("unknown protocol");
280           return 1;
281         }
282     }
283
284 #undef _
285
286   /* Totally out of translations to use... */
287   nat_ipfix_logging_addresses_exhausted (thread_index, 0);
288   return 1;
289 }
290
291 static_always_inline u32
292 nat_outside_fib_index_lookup (snat_main_t * sm, ip4_address_t addr)
293 {
294   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
295   nat_outside_fib_t *outside_fib;
296   fib_prefix_t pfx = {
297     .fp_proto = FIB_PROTOCOL_IP4,
298     .fp_len = 32,
299     .fp_addr = {.ip4.as_u32 = addr.as_u32,}
300     ,
301   };
302   // TODO: multiple vrfs none can resolve addr
303   /* *INDENT-OFF* */
304   vec_foreach (outside_fib, sm->outside_fibs)
305     {
306       fei = fib_table_lookup (outside_fib->fib_index, &pfx);
307       if (FIB_NODE_INDEX_INVALID != fei)
308         {
309           if (fib_entry_get_resolving_interface (fei) != ~0)
310             {
311               return outside_fib->fib_index;
312             }
313         }
314     }
315   /* *INDENT-ON* */
316   return ~0;
317 }
318
319 static u32
320 slow_path_ed (snat_main_t * sm,
321               vlib_buffer_t * b,
322               ip4_address_t l_addr,
323               ip4_address_t r_addr,
324               u16 l_port,
325               u16 r_port,
326               u8 proto,
327               u32 rx_fib_index,
328               snat_session_t ** sessionp,
329               vlib_node_runtime_t * node, u32 next, u32 thread_index, f64 now)
330 {
331   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
332   clib_bihash_kv_16_8_t out2in_ed_kv;
333   nat44_is_idle_session_ctx_t ctx;
334   ip4_address_t outside_addr;
335   u16 outside_port;
336   u8 identity_nat;
337
338   u32 nat_proto = ip_proto_to_nat_proto (proto);
339   snat_session_t *s = NULL;
340   lb_nat_type_t lb = 0;
341
342   if (PREDICT_TRUE (nat_proto == NAT_PROTOCOL_TCP))
343     {
344       if (PREDICT_FALSE
345           (!tcp_flags_is_init
346            (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)))
347         {
348           b->error = node->errors[NAT_IN2OUT_ED_ERROR_NON_SYN];
349           return NAT_NEXT_DROP;
350         }
351     }
352
353   if (PREDICT_FALSE
354       (nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index)))
355     {
356       if (!nat_lru_free_one (sm, thread_index, now))
357         {
358           b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
359           nat_ipfix_logging_max_sessions (thread_index,
360                                           sm->max_translations_per_thread);
361           nat_elog_notice ("maximum sessions exceeded");
362           return NAT_NEXT_DROP;
363         }
364     }
365
366   ip4_address_t sm_addr;
367   u16 sm_port;
368   u32 sm_fib_index;
369   /* First try to match static mapping by local address and port */
370   if (snat_static_mapping_match
371       (sm, l_addr, l_port, rx_fib_index, nat_proto, &sm_addr, &sm_port,
372        &sm_fib_index, 0, 0, 0, &lb, 0, &identity_nat, 0))
373     {
374       s = nat_ed_session_alloc (sm, thread_index, now, proto);
375       ASSERT (s);
376       s->in2out.addr = l_addr;
377       s->in2out.port = l_port;
378       s->nat_proto = nat_proto;
379       s->in2out.fib_index = rx_fib_index;
380       s->out2in.fib_index = sm->outside_fib_index;
381
382       switch (vec_len (sm->outside_fibs))
383         {
384         case 0:
385           s->out2in.fib_index = sm->outside_fib_index;
386           break;
387         case 1:
388           s->out2in.fib_index = sm->outside_fibs[0].fib_index;
389           break;
390         default:
391           s->out2in.fib_index = nat_outside_fib_index_lookup (sm, r_addr);
392           break;
393         }
394
395       /* Try to create dynamic translation */
396       outside_port = l_port;    // suggest using local port to allocation function
397       if (nat_ed_alloc_addr_and_port (sm, rx_fib_index, nat_proto,
398                                       thread_index, r_addr, r_port, proto,
399                                       sm->port_per_thread,
400                                       tsm->snat_thread_index, s,
401                                       &outside_addr,
402                                       &outside_port, &out2in_ed_kv))
403         {
404           nat_elog_notice ("addresses exhausted");
405           b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
406           nat_ed_session_delete (sm, s, thread_index, 1);
407           return NAT_NEXT_DROP;
408         }
409       s->out2in.addr = outside_addr;
410       s->out2in.port = outside_port;
411     }
412   else
413     {
414       if (PREDICT_FALSE (identity_nat))
415         {
416           *sessionp = NULL;
417           return next;
418         }
419       s = nat_ed_session_alloc (sm, thread_index, now, proto);
420       ASSERT (s);
421       s->out2in.addr = sm_addr;
422       s->out2in.port = sm_port;
423       s->in2out.addr = l_addr;
424       s->in2out.port = l_port;
425       s->nat_proto = nat_proto;
426       s->in2out.fib_index = rx_fib_index;
427       s->out2in.fib_index = sm->outside_fib_index;
428       switch (vec_len (sm->outside_fibs))
429         {
430         case 0:
431           s->out2in.fib_index = sm->outside_fib_index;
432           break;
433         case 1:
434           s->out2in.fib_index = sm->outside_fibs[0].fib_index;
435           break;
436         default:
437           s->out2in.fib_index = nat_outside_fib_index_lookup (sm, r_addr);
438           break;
439         }
440
441       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
442
443       init_ed_kv (&out2in_ed_kv, sm_addr, sm_port, r_addr, r_port,
444                   s->out2in.fib_index, proto, thread_index,
445                   s - tsm->sessions);
446       if (clib_bihash_add_or_overwrite_stale_16_8
447           (&sm->out2in_ed, &out2in_ed_kv, nat44_o2i_ed_is_idle_session_cb,
448            &ctx))
449         nat_elog_notice ("out2in-ed key add failed");
450     }
451
452   if (lb)
453     s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
454   s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
455   s->ext_host_addr = r_addr;
456   s->ext_host_port = r_port;
457
458   clib_bihash_kv_16_8_t in2out_ed_kv;
459   init_ed_kv (&in2out_ed_kv, l_addr, l_port, r_addr, r_port, rx_fib_index,
460               proto, thread_index, s - tsm->sessions);
461   ctx.now = now;
462   ctx.thread_index = thread_index;
463   if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, &in2out_ed_kv,
464                                                nat44_i2o_ed_is_idle_session_cb,
465                                                &ctx))
466     nat_elog_notice ("in2out-ed key add failed");
467
468   *sessionp = s;
469
470   /* log NAT event */
471   nat_ipfix_logging_nat44_ses_create (thread_index,
472                                       s->in2out.addr.as_u32,
473                                       s->out2in.addr.as_u32,
474                                       s->nat_proto,
475                                       s->in2out.port,
476                                       s->out2in.port, s->in2out.fib_index);
477
478   nat_syslog_nat44_sadd (s->user_index, s->in2out.fib_index,
479                          &s->in2out.addr, s->in2out.port,
480                          &s->ext_host_nat_addr, s->ext_host_nat_port,
481                          &s->out2in.addr, s->out2in.port,
482                          &s->ext_host_addr, s->ext_host_port, s->nat_proto,
483                          0);
484
485   nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
486                s->out2in.port, &s->ext_host_addr, s->ext_host_port,
487                &s->ext_host_nat_addr, s->ext_host_nat_port,
488                s->nat_proto, s->in2out.fib_index, s->flags, thread_index, 0);
489
490   per_vrf_sessions_register_session (s, thread_index);
491
492   return next;
493 }
494
495 static_always_inline int
496 nat44_ed_not_translate (snat_main_t * sm, vlib_node_runtime_t * node,
497                         u32 sw_if_index, ip4_header_t * ip, u32 proto,
498                         u32 rx_fib_index, u32 thread_index)
499 {
500   udp_header_t *udp = ip4_next_header (ip);
501   clib_bihash_kv_16_8_t kv, value;
502
503   init_ed_k (&kv, ip->dst_address, udp->dst_port, ip->src_address,
504              udp->src_port, sm->outside_fib_index, ip->protocol);
505
506   /* NAT packet aimed at external address if has active sessions */
507   if (clib_bihash_search_16_8 (&sm->out2in_ed, &kv, &value))
508     {
509       /* or is static mappings */
510       ip4_address_t placeholder_addr;
511       u16 placeholder_port;
512       u32 placeholder_fib_index;
513       if (!snat_static_mapping_match
514           (sm, ip->dst_address, udp->dst_port, sm->outside_fib_index, proto,
515            &placeholder_addr, &placeholder_port, &placeholder_fib_index, 1, 0,
516            0, 0, 0, 0, 0))
517         return 0;
518     }
519   else
520     return 0;
521
522   if (sm->forwarding_enabled)
523     return 1;
524
525   return snat_not_translate_fast (sm, node, sw_if_index, ip, proto,
526                                   rx_fib_index);
527 }
528
529 static_always_inline int
530 nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
531                                       u32 thread_index, f64 now,
532                                       vlib_main_t * vm, vlib_buffer_t * b)
533 {
534   clib_bihash_kv_16_8_t kv, value;
535   snat_session_t *s = 0;
536   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
537
538   if (!sm->forwarding_enabled)
539     return 0;
540
541   if (ip->protocol == IP_PROTOCOL_ICMP)
542     {
543       if (get_icmp_i2o_ed_key (b, ip, 0, ~0, ~0, 0, 0, 0, &kv))
544         return 0;
545     }
546   else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
547     {
548       init_ed_k (&kv, ip->src_address, vnet_buffer (b)->ip.reass.l4_src_port,
549                  ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port, 0,
550                  ip->protocol);
551     }
552   else
553     {
554       init_ed_k (&kv, ip->src_address, 0, ip->dst_address, 0, 0,
555                  ip->protocol);
556     }
557
558   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
559     {
560       ASSERT (thread_index == ed_value_get_thread_index (&value));
561       s =
562         pool_elt_at_index (tsm->sessions,
563                            ed_value_get_session_index (&value));
564       if (is_fwd_bypass_session (s))
565         {
566           if (ip->protocol == IP_PROTOCOL_TCP)
567             {
568               nat44_set_tcp_session_state_i2o (sm, now, s, b, thread_index);
569             }
570           /* Accounting */
571           nat44_session_update_counters (s, now,
572                                          vlib_buffer_length_in_chain (vm, b),
573                                          thread_index);
574           /* Per-user LRU list maintenance */
575           nat44_session_update_lru (sm, s, thread_index);
576           return 1;
577         }
578       else
579         return 0;
580     }
581
582   return 0;
583 }
584
585 static_always_inline int
586 nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip,
587                                        u16 src_port, u16 dst_port,
588                                        u32 thread_index, u32 rx_sw_if_index,
589                                        u32 tx_sw_if_index)
590 {
591   clib_bihash_kv_16_8_t kv, value;
592   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
593   snat_interface_t *i;
594   snat_session_t *s;
595   u32 rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (rx_sw_if_index);
596   u32 tx_fib_index = ip4_fib_table_get_index_for_sw_if_index (tx_sw_if_index);
597
598   /* src NAT check */
599   init_ed_k (&kv, ip->src_address, src_port, ip->dst_address, dst_port,
600              tx_fib_index, ip->protocol);
601   if (!clib_bihash_search_16_8 (&sm->out2in_ed, &kv, &value))
602     {
603       ASSERT (thread_index == ed_value_get_thread_index (&value));
604       s =
605         pool_elt_at_index (tsm->sessions,
606                            ed_value_get_session_index (&value));
607       if (nat44_is_ses_closed (s))
608         {
609           nat_free_session_data (sm, s, thread_index, 0);
610           nat_ed_session_delete (sm, s, thread_index, 1);
611         }
612       else
613         s->flags |= SNAT_SESSION_FLAG_OUTPUT_FEATURE;
614       return 1;
615     }
616
617   /* dst NAT check */
618   init_ed_k (&kv, ip->dst_address, dst_port, ip->src_address, src_port,
619              rx_fib_index, ip->protocol);
620   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
621     {
622       ASSERT (thread_index == ed_value_get_thread_index (&value));
623       s =
624         pool_elt_at_index (tsm->sessions,
625                            ed_value_get_session_index (&value));
626       if (is_fwd_bypass_session (s))
627         return 0;
628
629       /* hairpinning */
630       /* *INDENT-OFF* */
631       pool_foreach (i, sm->output_feature_interfaces,
632       ({
633         if ((nat_interface_is_inside (i)) && (rx_sw_if_index == i->sw_if_index))
634            return 0;
635       }));
636       /* *INDENT-ON* */
637       return 1;
638     }
639
640   return 0;
641 }
642
643 #ifndef CLIB_MARCH_VARIANT
644 u32
645 icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node,
646                       u32 thread_index, vlib_buffer_t * b,
647                       ip4_header_t * ip, ip4_address_t * addr,
648                       u16 * port, u32 * fib_index, nat_protocol_t * proto,
649                       void *d, void *e, u8 * dont_translate)
650 {
651   u32 sw_if_index;
652   u32 rx_fib_index;
653   clib_bihash_kv_16_8_t kv, value;
654   u32 next = ~0;
655   int err;
656   snat_session_t *s = NULL;
657   u16 l_port = 0, r_port = 0;   // initialize to workaround gcc warning
658   vlib_main_t *vm = vlib_get_main ();
659   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
660   *dont_translate = 0;
661
662   sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
663   rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
664
665   err =
666     get_icmp_i2o_ed_key (b, ip, rx_fib_index, ~0, ~0, proto, &l_port,
667                          &r_port, &kv);
668   if (err != 0)
669     {
670       b->error = node->errors[err];
671       next = NAT_NEXT_DROP;
672       goto out;
673     }
674
675   if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
676     {
677       if (vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0)
678         {
679           if (PREDICT_FALSE
680               (nat44_ed_not_translate_output_feature
681                (sm, ip, l_port, r_port, thread_index,
682                 sw_if_index, vnet_buffer (b)->sw_if_index[VLIB_TX])))
683             {
684               *dont_translate = 1;
685               goto out;
686             }
687         }
688       else
689         {
690           if (PREDICT_FALSE (nat44_ed_not_translate (sm, node, sw_if_index,
691                                                      ip, NAT_PROTOCOL_ICMP,
692                                                      rx_fib_index,
693                                                      thread_index)))
694             {
695               *dont_translate = 1;
696               goto out;
697             }
698         }
699
700       if (PREDICT_FALSE
701           (icmp_type_is_error_message
702            (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)))
703         {
704           b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
705           next = NAT_NEXT_DROP;
706           goto out;
707         }
708
709       next =
710         slow_path_ed (sm, b, ip->src_address, ip->dst_address, l_port, r_port,
711                       ip->protocol, rx_fib_index, &s, node, next,
712                       thread_index, vlib_time_now (vm));
713
714       if (PREDICT_FALSE (next == NAT_NEXT_DROP))
715         goto out;
716
717       if (!s)
718         {
719           *dont_translate = 1;
720           goto out;
721         }
722     }
723   else
724     {
725       if (PREDICT_FALSE
726           (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
727            ICMP4_echo_request
728            && vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
729            ICMP4_echo_reply
730            && !icmp_type_is_error_message (vnet_buffer (b)->ip.
731                                            reass.icmp_type_or_tcp_flags)))
732         {
733           b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
734           next = NAT_NEXT_DROP;
735           goto out;
736         }
737
738       ASSERT (thread_index == ed_value_get_thread_index (&value));
739       s =
740         pool_elt_at_index (tsm->sessions,
741                            ed_value_get_session_index (&value));
742     }
743 out:
744   if (s)
745     {
746       *addr = s->out2in.addr;
747       *port = s->out2in.port;
748       *fib_index = s->out2in.fib_index;
749     }
750   if (d)
751     {
752       *(snat_session_t **) d = s;
753     }
754   return next;
755 }
756 #endif
757
758 static snat_session_t *
759 nat44_ed_in2out_unknown_proto (snat_main_t * sm,
760                                vlib_buffer_t * b,
761                                ip4_header_t * ip,
762                                u32 rx_fib_index,
763                                u32 thread_index,
764                                f64 now,
765                                vlib_main_t * vm, vlib_node_runtime_t * node)
766 {
767   clib_bihash_kv_8_8_t kv, value;
768   clib_bihash_kv_16_8_t s_kv, s_value;
769   snat_static_mapping_t *m;
770   u32 old_addr, new_addr = 0;
771   ip_csum_t sum;
772   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
773   snat_session_t *s;
774   u32 outside_fib_index = sm->outside_fib_index;
775   int i;
776   u8 is_sm = 0;
777
778   switch (vec_len (sm->outside_fibs))
779     {
780     case 0:
781       outside_fib_index = sm->outside_fib_index;
782       break;
783     case 1:
784       outside_fib_index = sm->outside_fibs[0].fib_index;
785       break;
786     default:
787       outside_fib_index = nat_outside_fib_index_lookup (sm, ip->dst_address);
788       break;
789     }
790   old_addr = ip->src_address.as_u32;
791
792   init_ed_k (&s_kv, ip->src_address, 0, ip->dst_address, 0, rx_fib_index,
793              ip->protocol);
794
795   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &s_kv, &s_value))
796     {
797       ASSERT (thread_index == ed_value_get_thread_index (&s_value));
798       s =
799         pool_elt_at_index (tsm->sessions,
800                            ed_value_get_session_index (&s_value));
801       new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
802     }
803   else
804     {
805       if (PREDICT_FALSE
806           (nat44_ed_maximum_sessions_exceeded
807            (sm, rx_fib_index, thread_index)))
808         {
809           b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
810           nat_ipfix_logging_max_sessions (thread_index,
811                                           sm->max_translations_per_thread);
812           nat_elog_notice ("maximum sessions exceeded");
813           return 0;
814         }
815
816       init_nat_k (&kv, ip->src_address, 0, rx_fib_index, 0);
817
818       /* Try to find static mapping first */
819       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
820         {
821           m = pool_elt_at_index (sm->static_mappings, value.value);
822           new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
823           is_sm = 1;
824           goto create_ses;
825         }
826       else
827         {
828           /* *INDENT-OFF* */
829           pool_foreach (s, tsm->sessions, {
830             if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32)
831               {
832                 new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
833
834                 init_ed_k(&s_kv, s->out2in.addr, 0, ip->dst_address, 0, outside_fib_index, ip->protocol);
835                 if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
836                   goto create_ses;
837
838                 break;
839               }
840           });
841           /* *INDENT-ON* */
842
843           for (i = 0; i < vec_len (sm->addresses); i++)
844             {
845               init_ed_k (&s_kv, sm->addresses[i].addr, 0, ip->dst_address, 0,
846                          outside_fib_index, ip->protocol);
847               if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
848                 {
849                   new_addr = ip->src_address.as_u32 =
850                     sm->addresses[i].addr.as_u32;
851                   goto create_ses;
852                 }
853             }
854           return 0;
855         }
856
857     create_ses:
858       s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
859       if (!s)
860         {
861           b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
862           nat_elog_warn ("create NAT session failed");
863           return 0;
864         }
865
866       s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
867       s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
868       s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
869       s->out2in.addr.as_u32 = new_addr;
870       s->out2in.fib_index = outside_fib_index;
871       s->in2out.addr.as_u32 = old_addr;
872       s->in2out.fib_index = rx_fib_index;
873       s->in2out.port = s->out2in.port = ip->protocol;
874       if (is_sm)
875         s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
876
877       /* Add to lookup tables */
878       init_ed_kv (&s_kv, s->in2out.addr, 0, ip->dst_address, 0, rx_fib_index,
879                   ip->protocol, thread_index, s - tsm->sessions);
880       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
881         nat_elog_notice ("in2out key add failed");
882
883       init_ed_kv (&s_kv, s->out2in.addr, 0, ip->dst_address, 0,
884                   outside_fib_index, ip->protocol, thread_index,
885                   s - tsm->sessions);
886       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
887         nat_elog_notice ("out2in key add failed");
888
889       per_vrf_sessions_register_session (s, thread_index);
890     }
891
892   /* Update IP checksum */
893   sum = ip->checksum;
894   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
895   ip->checksum = ip_csum_fold (sum);
896
897   /* Accounting */
898   nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b),
899                                  thread_index);
900   /* Per-user LRU list maintenance */
901   nat44_session_update_lru (sm, s, thread_index);
902
903   /* Hairpinning */
904   if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
905     nat44_ed_hairpinning_unknown_proto (sm, b, ip);
906
907   if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
908     vnet_buffer (b)->sw_if_index[VLIB_TX] = outside_fib_index;
909
910   return s;
911 }
912
913 static inline uword
914 nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
915                                           vlib_node_runtime_t * node,
916                                           vlib_frame_t * frame,
917                                           int is_output_feature)
918 {
919   u32 n_left_from, *from;
920   snat_main_t *sm = &snat_main;
921   f64 now = vlib_time_now (vm);
922   u32 thread_index = vm->thread_index;
923   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
924   u32 def_slow = is_output_feature ? NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH
925     : NAT_NEXT_IN2OUT_ED_SLOW_PATH;
926
927   from = vlib_frame_vector_args (frame);
928   n_left_from = frame->n_vectors;
929
930   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
931   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
932   vlib_get_buffers (vm, from, b, n_left_from);
933
934   while (n_left_from > 0)
935     {
936       vlib_buffer_t *b0;
937       u32 sw_if_index0, rx_fib_index0, proto0, new_addr0, old_addr0,
938         iph_offset0 = 0;
939       u16 old_port0, new_port0;
940       ip4_header_t *ip0;
941       udp_header_t *udp0;
942       tcp_header_t *tcp0;
943       snat_session_t *s0 = 0;
944       clib_bihash_kv_16_8_t kv0, value0;
945       ip_csum_t sum0;
946
947       b0 = *b;
948       b++;
949
950       /* Prefetch next iteration. */
951       if (PREDICT_TRUE (n_left_from >= 2))
952         {
953           vlib_buffer_t *p2;
954
955           p2 = *b;
956
957           vlib_prefetch_buffer_header (p2, LOAD);
958
959           CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
960         }
961
962       if (is_output_feature)
963         {
964           iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
965         }
966
967       next[0] = vnet_buffer2 (b0)->nat.arc_next;
968
969       ip0 =
970         (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + iph_offset0);
971
972       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
973       rx_fib_index0 =
974         fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index0);
975
976       if (PREDICT_FALSE (ip0->ttl == 1))
977         {
978           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
979           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
980                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
981                                        0);
982           next[0] = NAT_NEXT_ICMP_ERROR;
983           goto trace0;
984         }
985
986       udp0 = ip4_next_header (ip0);
987       tcp0 = (tcp_header_t *) udp0;
988       proto0 = ip_proto_to_nat_proto (ip0->protocol);
989
990       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
991         {
992           next[0] = def_slow;
993           goto trace0;
994         }
995
996       if (is_output_feature)
997         {
998           if (PREDICT_FALSE
999               (nat_not_translate_output_feature_fwd
1000                (sm, ip0, thread_index, now, vm, b0)))
1001             goto trace0;
1002         }
1003
1004       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1005         {
1006           next[0] = def_slow;
1007           goto trace0;
1008         }
1009
1010       init_ed_k (&kv0, ip0->src_address,
1011                  vnet_buffer (b0)->ip.reass.l4_src_port, ip0->dst_address,
1012                  vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
1013                  ip0->protocol);
1014
1015       // lookup for session
1016       if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
1017         {
1018           // session does not exist go slow path
1019           next[0] = def_slow;
1020           goto trace0;
1021         }
1022       ASSERT (thread_index == ed_value_get_thread_index (&value0));
1023       s0 =
1024         pool_elt_at_index (tsm->sessions,
1025                            ed_value_get_session_index (&value0));
1026
1027       if (PREDICT_FALSE (per_vrf_sessions_is_expired (s0, thread_index)))
1028         {
1029           // session is closed, go slow path
1030           nat_free_session_data (sm, s0, thread_index, 0);
1031           nat_ed_session_delete (sm, s0, thread_index, 1);
1032           next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
1033           goto trace0;
1034         }
1035
1036       if (s0->tcp_closed_timestamp)
1037         {
1038           if (now >= s0->tcp_closed_timestamp)
1039             {
1040               // session is closed, go slow path, freed in slow path
1041               next[0] = def_slow;
1042             }
1043           else
1044             {
1045               // session in transitory timeout, drop
1046               b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TCP_CLOSED];
1047               next[0] = NAT_NEXT_DROP;
1048             }
1049           goto trace0;
1050         }
1051
1052       // drop if session expired
1053       u64 sess_timeout_time;
1054       sess_timeout_time =
1055         s0->last_heard + (f64) nat44_session_get_timeout (sm, s0);
1056       if (now >= sess_timeout_time)
1057         {
1058           nat_free_session_data (sm, s0, thread_index, 0);
1059           nat_ed_session_delete (sm, s0, thread_index, 1);
1060           // session is closed, go slow path
1061           next[0] = def_slow;
1062           goto trace0;
1063         }
1064
1065       b0->flags |= VNET_BUFFER_F_IS_NATED;
1066
1067       if (!is_output_feature)
1068         vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1069
1070       old_addr0 = ip0->src_address.as_u32;
1071       new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
1072       sum0 = ip0->checksum;
1073       sum0 =
1074         ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1075                         src_address);
1076       if (PREDICT_FALSE (is_twice_nat_session (s0)))
1077         sum0 =
1078           ip_csum_update (sum0, ip0->dst_address.as_u32,
1079                           s0->ext_host_addr.as_u32, ip4_header_t,
1080                           dst_address);
1081       ip0->checksum = ip_csum_fold (sum0);
1082
1083       old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1084
1085       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1086         {
1087           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1088             {
1089               new_port0 = udp0->src_port = s0->out2in.port;
1090               sum0 = tcp0->checksum;
1091               sum0 =
1092                 ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1093                                 dst_address);
1094               sum0 =
1095                 ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1096                                 length);
1097               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1098                 {
1099                   sum0 =
1100                     ip_csum_update (sum0, ip0->dst_address.as_u32,
1101                                     s0->ext_host_addr.as_u32, ip4_header_t,
1102                                     dst_address);
1103                   sum0 =
1104                     ip_csum_update (sum0,
1105                                     vnet_buffer (b0)->ip.reass.l4_dst_port,
1106                                     s0->ext_host_port, ip4_header_t, length);
1107                   tcp0->dst_port = s0->ext_host_port;
1108                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1109                 }
1110               mss_clamping (sm->mss_clamping, tcp0, &sum0);
1111               tcp0->checksum = ip_csum_fold (sum0);
1112             }
1113           vlib_increment_simple_counter (&sm->counters.fastpath.in2out_ed.tcp,
1114                                          thread_index, sw_if_index0, 1);
1115           nat44_set_tcp_session_state_i2o (sm, now, s0, b0, thread_index);
1116         }
1117       else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
1118                && udp0->checksum)
1119         {
1120           new_port0 = udp0->src_port = s0->out2in.port;
1121           sum0 = udp0->checksum;
1122           sum0 =
1123             ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1124                             dst_address);
1125           sum0 =
1126             ip_csum_update (sum0, old_port0, new_port0, ip4_header_t, length);
1127           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1128             {
1129               sum0 =
1130                 ip_csum_update (sum0, ip0->dst_address.as_u32,
1131                                 s0->ext_host_addr.as_u32, ip4_header_t,
1132                                 dst_address);
1133               sum0 =
1134                 ip_csum_update (sum0, vnet_buffer (b0)->ip.reass.l4_dst_port,
1135                                 s0->ext_host_port, ip4_header_t, length);
1136               udp0->dst_port = s0->ext_host_port;
1137               ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1138             }
1139           udp0->checksum = ip_csum_fold (sum0);
1140           vlib_increment_simple_counter (&sm->counters.fastpath.in2out_ed.udp,
1141                                          thread_index, sw_if_index0, 1);
1142         }
1143       else
1144         {
1145           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1146             {
1147               new_port0 = udp0->src_port = s0->out2in.port;
1148               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1149                 {
1150                   udp0->dst_port = s0->ext_host_port;
1151                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1152                 }
1153               vlib_increment_simple_counter (&sm->counters.fastpath.
1154                                              in2out_ed.udp, thread_index,
1155                                              sw_if_index0, 1);
1156             }
1157         }
1158
1159       /* Accounting */
1160       nat44_session_update_counters (s0, now,
1161                                      vlib_buffer_length_in_chain (vm, b0),
1162                                      thread_index);
1163       /* Per-user LRU list maintenance */
1164       nat44_session_update_lru (sm, s0, thread_index);
1165
1166     trace0:
1167       if (PREDICT_FALSE
1168           ((node->flags & VLIB_NODE_FLAG_TRACE)
1169            && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1170         {
1171           nat_in2out_ed_trace_t *t =
1172             vlib_add_trace (vm, node, b0, sizeof (*t));
1173           t->sw_if_index = sw_if_index0;
1174           t->next_index = next[0];
1175           t->is_slow_path = 0;
1176
1177           if (s0)
1178             t->session_index = s0 - tsm->sessions;
1179           else
1180             t->session_index = ~0;
1181         }
1182
1183       if (next[0] == NAT_NEXT_DROP)
1184         {
1185           vlib_increment_simple_counter (&sm->counters.fastpath.
1186                                          in2out_ed.drops, thread_index,
1187                                          sw_if_index0, 1);
1188         }
1189
1190       n_left_from--;
1191       next++;
1192     }
1193
1194   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1195                                frame->n_vectors);
1196   return frame->n_vectors;
1197 }
1198
1199 static inline uword
1200 nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm,
1201                                           vlib_node_runtime_t * node,
1202                                           vlib_frame_t * frame,
1203                                           int is_output_feature)
1204 {
1205   u32 n_left_from, *from;
1206   snat_main_t *sm = &snat_main;
1207   f64 now = vlib_time_now (vm);
1208   u32 thread_index = vm->thread_index;
1209   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1210
1211   from = vlib_frame_vector_args (frame);
1212   n_left_from = frame->n_vectors;
1213
1214   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
1215   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
1216   vlib_get_buffers (vm, from, b, n_left_from);
1217
1218   while (n_left_from > 0)
1219     {
1220       vlib_buffer_t *b0;
1221       u32 sw_if_index0, rx_fib_index0, proto0, new_addr0, old_addr0,
1222         iph_offset0 = 0;
1223       u16 old_port0, new_port0;
1224       ip4_header_t *ip0;
1225       udp_header_t *udp0;
1226       tcp_header_t *tcp0;
1227       icmp46_header_t *icmp0;
1228       snat_session_t *s0 = 0;
1229       clib_bihash_kv_16_8_t kv0, value0;
1230       ip_csum_t sum0;
1231
1232       b0 = *b;
1233
1234       if (is_output_feature)
1235         iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
1236
1237       next[0] = vnet_buffer2 (b0)->nat.arc_next;
1238
1239       ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1240                               iph_offset0);
1241
1242       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1243       rx_fib_index0 =
1244         fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index0);
1245
1246       if (PREDICT_FALSE (ip0->ttl == 1))
1247         {
1248           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1249           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1250                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
1251                                        0);
1252           next[0] = NAT_NEXT_ICMP_ERROR;
1253           goto trace0;
1254         }
1255
1256       udp0 = ip4_next_header (ip0);
1257       tcp0 = (tcp_header_t *) udp0;
1258       icmp0 = (icmp46_header_t *) udp0;
1259       proto0 = ip_proto_to_nat_proto (ip0->protocol);
1260
1261       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1262         {
1263           s0 = nat44_ed_in2out_unknown_proto (sm, b0, ip0,
1264                                               rx_fib_index0,
1265                                               thread_index, now, vm, node);
1266           if (!s0)
1267             next[0] = NAT_NEXT_DROP;
1268
1269           vlib_increment_simple_counter (&sm->counters.slowpath.
1270                                          in2out_ed.other, thread_index,
1271                                          sw_if_index0, 1);
1272           goto trace0;
1273         }
1274
1275       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1276         {
1277           next[0] =
1278             icmp_in2out_ed_slow_path (sm, b0, ip0, icmp0, sw_if_index0,
1279                                       rx_fib_index0, node, next[0], now,
1280                                       thread_index, &s0);
1281           vlib_increment_simple_counter (&sm->counters.slowpath.
1282                                          in2out_ed.icmp, thread_index,
1283                                          sw_if_index0, 1);
1284           goto trace0;
1285         }
1286
1287       init_ed_k (&kv0, ip0->src_address,
1288                  vnet_buffer (b0)->ip.reass.l4_src_port, ip0->dst_address,
1289                  vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
1290                  ip0->protocol);
1291       if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
1292         {
1293           ASSERT (thread_index == ed_value_get_thread_index (&value0));
1294           s0 =
1295             pool_elt_at_index (tsm->sessions,
1296                                ed_value_get_session_index (&value0));
1297
1298           if (s0->tcp_closed_timestamp && now >= s0->tcp_closed_timestamp)
1299             {
1300               nat_free_session_data (sm, s0, thread_index, 0);
1301               nat_ed_session_delete (sm, s0, thread_index, 1);
1302               s0 = NULL;
1303             }
1304         }
1305
1306       if (!s0)
1307         {
1308           if (is_output_feature)
1309             {
1310               if (PREDICT_FALSE
1311                   (nat44_ed_not_translate_output_feature
1312                    (sm, ip0, vnet_buffer (b0)->ip.reass.l4_src_port,
1313                     vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
1314                     sw_if_index0, vnet_buffer (b0)->sw_if_index[VLIB_TX])))
1315                 goto trace0;
1316
1317               /*
1318                * Send DHCP packets to the ipv4 stack, or we won't
1319                * be able to use dhcp client on the outside interface
1320                */
1321               if (PREDICT_FALSE
1322                   (proto0 == NAT_PROTOCOL_UDP
1323                    && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1324                        clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_server))
1325                    && ip0->dst_address.as_u32 == 0xffffffff))
1326                 goto trace0;
1327             }
1328           else
1329             {
1330               if (PREDICT_FALSE
1331                   (nat44_ed_not_translate
1332                    (sm, node, sw_if_index0, ip0, proto0, rx_fib_index0,
1333                     thread_index)))
1334                 goto trace0;
1335             }
1336
1337           next[0] =
1338             slow_path_ed (sm, b0, ip0->src_address, ip0->dst_address,
1339                           vnet_buffer (b0)->ip.reass.l4_src_port,
1340                           vnet_buffer (b0)->ip.reass.l4_dst_port,
1341                           ip0->protocol, rx_fib_index0, &s0, node, next[0],
1342                           thread_index, now);
1343
1344           if (PREDICT_FALSE (next[0] == NAT_NEXT_DROP))
1345             goto trace0;
1346
1347           if (PREDICT_FALSE (!s0))
1348             goto trace0;
1349
1350         }
1351
1352       b0->flags |= VNET_BUFFER_F_IS_NATED;
1353
1354       if (!is_output_feature)
1355         vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1356
1357       old_addr0 = ip0->src_address.as_u32;
1358       new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
1359       sum0 = ip0->checksum;
1360       sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1361                              src_address);
1362       if (PREDICT_FALSE (is_twice_nat_session (s0)))
1363         sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1364                                s0->ext_host_addr.as_u32, ip4_header_t,
1365                                dst_address);
1366       ip0->checksum = ip_csum_fold (sum0);
1367
1368       old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1369
1370       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1371         {
1372           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1373             {
1374               new_port0 = udp0->src_port = s0->out2in.port;
1375               sum0 = tcp0->checksum;
1376               sum0 =
1377                 ip_csum_update (sum0, old_addr0, new_addr0,
1378                                 ip4_header_t, dst_address);
1379               sum0 =
1380                 ip_csum_update (sum0, old_port0, new_port0,
1381                                 ip4_header_t, length);
1382               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1383                 {
1384                   sum0 =
1385                     ip_csum_update (sum0, ip0->dst_address.as_u32,
1386                                     s0->ext_host_addr.as_u32,
1387                                     ip4_header_t, dst_address);
1388                   sum0 =
1389                     ip_csum_update (sum0,
1390                                     vnet_buffer (b0)->ip.reass.l4_dst_port,
1391                                     s0->ext_host_port, ip4_header_t, length);
1392                   tcp0->dst_port = s0->ext_host_port;
1393                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1394                 }
1395               mss_clamping (sm->mss_clamping, tcp0, &sum0);
1396               tcp0->checksum = ip_csum_fold (sum0);
1397             }
1398           vlib_increment_simple_counter (&sm->counters.slowpath.in2out_ed.tcp,
1399                                          thread_index, sw_if_index0, 1);
1400           nat44_set_tcp_session_state_i2o (sm, now, s0, b0, thread_index);
1401         }
1402       else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
1403                && udp0->checksum)
1404         {
1405           new_port0 = udp0->src_port = s0->out2in.port;
1406           sum0 = udp0->checksum;
1407           sum0 =
1408             ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1409                             dst_address);
1410           sum0 =
1411             ip_csum_update (sum0, old_port0, new_port0, ip4_header_t, length);
1412           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1413             {
1414               sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1415                                      s0->ext_host_addr.as_u32,
1416                                      ip4_header_t, dst_address);
1417               sum0 =
1418                 ip_csum_update (sum0,
1419                                 vnet_buffer (b0)->ip.reass.l4_dst_port,
1420                                 s0->ext_host_port, ip4_header_t, length);
1421               udp0->dst_port = s0->ext_host_port;
1422               ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1423             }
1424           udp0->checksum = ip_csum_fold (sum0);
1425           vlib_increment_simple_counter (&sm->counters.slowpath.in2out_ed.udp,
1426                                          thread_index, sw_if_index0, 1);
1427         }
1428       else
1429         {
1430           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1431             {
1432               new_port0 = udp0->src_port = s0->out2in.port;
1433               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1434                 {
1435                   udp0->dst_port = s0->ext_host_port;
1436                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1437                 }
1438               vlib_increment_simple_counter (&sm->counters.slowpath.
1439                                              in2out_ed.udp, thread_index,
1440                                              sw_if_index0, 1);
1441             }
1442         }
1443
1444       /* Accounting */
1445       nat44_session_update_counters (s0, now,
1446                                      vlib_buffer_length_in_chain
1447                                      (vm, b0), thread_index);
1448       /* Per-user LRU list maintenance */
1449       nat44_session_update_lru (sm, s0, thread_index);
1450
1451     trace0:
1452       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1453                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1454         {
1455           nat_in2out_ed_trace_t *t =
1456             vlib_add_trace (vm, node, b0, sizeof (*t));
1457           t->sw_if_index = sw_if_index0;
1458           t->next_index = next[0];
1459           t->is_slow_path = 1;
1460
1461           if (s0)
1462             t->session_index = s0 - tsm->sessions;
1463           else
1464             t->session_index = ~0;
1465         }
1466
1467       if (next[0] == NAT_NEXT_DROP)
1468         {
1469           vlib_increment_simple_counter (&sm->counters.slowpath.
1470                                          in2out_ed.drops, thread_index,
1471                                          sw_if_index0, 1);
1472         }
1473
1474       n_left_from--;
1475       next++;
1476       b++;
1477     }
1478
1479   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1480                                frame->n_vectors);
1481
1482   return frame->n_vectors;
1483 }
1484
1485 VLIB_NODE_FN (nat44_ed_in2out_node) (vlib_main_t * vm,
1486                                      vlib_node_runtime_t * node,
1487                                      vlib_frame_t * frame)
1488 {
1489   return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 0);
1490 }
1491
1492 /* *INDENT-OFF* */
1493 VLIB_REGISTER_NODE (nat44_ed_in2out_node) = {
1494   .name = "nat44-ed-in2out",
1495   .vector_size = sizeof (u32),
1496   .sibling_of = "nat-default",
1497   .format_trace = format_nat_in2out_ed_trace,
1498   .type = VLIB_NODE_TYPE_INTERNAL,
1499   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1500   .error_strings = nat_in2out_ed_error_strings,
1501   .runtime_data_bytes = sizeof (snat_runtime_t),
1502 };
1503 /* *INDENT-ON* */
1504
1505 VLIB_NODE_FN (nat44_ed_in2out_output_node) (vlib_main_t * vm,
1506                                             vlib_node_runtime_t * node,
1507                                             vlib_frame_t * frame)
1508 {
1509   return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 1);
1510 }
1511
1512 /* *INDENT-OFF* */
1513 VLIB_REGISTER_NODE (nat44_ed_in2out_output_node) = {
1514   .name = "nat44-ed-in2out-output",
1515   .vector_size = sizeof (u32),
1516   .sibling_of = "nat-default",
1517   .format_trace = format_nat_in2out_ed_trace,
1518   .type = VLIB_NODE_TYPE_INTERNAL,
1519   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1520   .error_strings = nat_in2out_ed_error_strings,
1521   .runtime_data_bytes = sizeof (snat_runtime_t),
1522 };
1523 /* *INDENT-ON* */
1524
1525 VLIB_NODE_FN (nat44_ed_in2out_slowpath_node) (vlib_main_t * vm,
1526                                               vlib_node_runtime_t *
1527                                               node, vlib_frame_t * frame)
1528 {
1529   return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 0);
1530 }
1531
1532 /* *INDENT-OFF* */
1533 VLIB_REGISTER_NODE (nat44_ed_in2out_slowpath_node) = {
1534   .name = "nat44-ed-in2out-slowpath",
1535   .vector_size = sizeof (u32),
1536   .sibling_of = "nat-default",
1537   .format_trace = format_nat_in2out_ed_trace,
1538   .type = VLIB_NODE_TYPE_INTERNAL,
1539   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1540   .error_strings = nat_in2out_ed_error_strings,
1541   .runtime_data_bytes = sizeof (snat_runtime_t),
1542 };
1543 /* *INDENT-ON* */
1544
1545 VLIB_NODE_FN (nat44_ed_in2out_output_slowpath_node) (vlib_main_t * vm,
1546                                                      vlib_node_runtime_t
1547                                                      * node,
1548                                                      vlib_frame_t * frame)
1549 {
1550   return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 1);
1551 }
1552
1553 /* *INDENT-OFF* */
1554 VLIB_REGISTER_NODE (nat44_ed_in2out_output_slowpath_node) = {
1555   .name = "nat44-ed-in2out-output-slowpath",
1556   .vector_size = sizeof (u32),
1557   .sibling_of = "nat-default",
1558   .format_trace = format_nat_in2out_ed_trace,
1559   .type = VLIB_NODE_TYPE_INTERNAL,
1560   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1561   .error_strings = nat_in2out_ed_error_strings,
1562   .runtime_data_bytes = sizeof (snat_runtime_t),
1563 };
1564 /* *INDENT-ON* */
1565
1566 static u8 *
1567 format_nat_pre_trace (u8 * s, va_list * args)
1568 {
1569   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1570   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1571   nat_pre_trace_t *t = va_arg (*args, nat_pre_trace_t *);
1572   return format (s, "in2out next_index %d arc_next_index %d", t->next_index,
1573                  t->arc_next_index);
1574 }
1575
1576 VLIB_NODE_FN (nat_pre_in2out_node)
1577   (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1578 {
1579   return nat_pre_node_fn_inline (vm, node, frame,
1580                                  NAT_NEXT_IN2OUT_ED_FAST_PATH);
1581 }
1582
1583 VLIB_NODE_FN (nat_pre_in2out_output_node)
1584   (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1585 {
1586   return nat_pre_node_fn_inline (vm, node, frame,
1587                                  NAT_NEXT_IN2OUT_ED_OUTPUT_FAST_PATH);
1588 }
1589
1590 /* *INDENT-OFF* */
1591 VLIB_REGISTER_NODE (nat_pre_in2out_node) = {
1592   .name = "nat-pre-in2out",
1593   .vector_size = sizeof (u32),
1594   .sibling_of = "nat-default",
1595   .format_trace = format_nat_pre_trace,
1596   .type = VLIB_NODE_TYPE_INTERNAL,
1597   .n_errors = 0,
1598 };
1599
1600 VLIB_REGISTER_NODE (nat_pre_in2out_output_node) = {
1601   .name = "nat-pre-in2out-output",
1602   .vector_size = sizeof (u32),
1603   .sibling_of = "nat-default",
1604   .format_trace = format_nat_pre_trace,
1605   .type = VLIB_NODE_TYPE_INTERNAL,
1606   .n_errors = 0,
1607 };
1608 /* *INDENT-ON* */
1609
1610 /*
1611  * fd.io coding-style-patch-verification: ON
1612  *
1613  * Local Variables:
1614  * eval: (c-set-style "gnu")
1615  * End:
1616  */