misc: Purge unused pg includes
[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.h>
26 #include <vppinfra/error.h>
27 #include <nat/nat.h>
28 #include <nat/nat_ipfix_logging.h>
29 #include <nat/nat_inlines.h>
30 #include <nat/nat44/inlines.h>
31 #include <nat/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       snat_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   snat_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   snat_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               if (nat44_set_tcp_session_state_i2o
569                   (sm, now, s, b, thread_index))
570                 return 1;
571             }
572           /* Accounting */
573           nat44_session_update_counters (s, now,
574                                          vlib_buffer_length_in_chain (vm, b),
575                                          thread_index);
576           /* Per-user LRU list maintenance */
577           nat44_session_update_lru (sm, s, thread_index);
578           return 1;
579         }
580       else
581         return 0;
582     }
583
584   return 0;
585 }
586
587 static_always_inline int
588 nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip,
589                                        u16 src_port, u16 dst_port,
590                                        u32 thread_index, u32 rx_sw_if_index,
591                                        u32 tx_sw_if_index)
592 {
593   clib_bihash_kv_16_8_t kv, value;
594   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
595   snat_interface_t *i;
596   snat_session_t *s;
597   u32 rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (rx_sw_if_index);
598   u32 tx_fib_index = ip4_fib_table_get_index_for_sw_if_index (tx_sw_if_index);
599
600   /* src NAT check */
601   init_ed_k (&kv, ip->src_address, src_port, ip->dst_address, dst_port,
602              tx_fib_index, ip->protocol);
603   if (!clib_bihash_search_16_8 (&sm->out2in_ed, &kv, &value))
604     {
605       ASSERT (thread_index == ed_value_get_thread_index (&value));
606       s =
607         pool_elt_at_index (tsm->sessions,
608                            ed_value_get_session_index (&value));
609       if (nat44_is_ses_closed (s))
610         {
611           nat_free_session_data (sm, s, thread_index, 0);
612           nat_ed_session_delete (sm, s, thread_index, 1);
613         }
614       else
615         s->flags |= SNAT_SESSION_FLAG_OUTPUT_FEATURE;
616       return 1;
617     }
618
619   /* dst NAT check */
620   init_ed_k (&kv, ip->dst_address, dst_port, ip->src_address, src_port,
621              rx_fib_index, ip->protocol);
622   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
623     {
624       ASSERT (thread_index == ed_value_get_thread_index (&value));
625       s =
626         pool_elt_at_index (tsm->sessions,
627                            ed_value_get_session_index (&value));
628       if (is_fwd_bypass_session (s))
629         return 0;
630
631       /* hairpinning */
632       /* *INDENT-OFF* */
633       pool_foreach (i, sm->output_feature_interfaces,
634       ({
635         if ((nat_interface_is_inside (i)) && (rx_sw_if_index == i->sw_if_index))
636            return 0;
637       }));
638       /* *INDENT-ON* */
639       return 1;
640     }
641
642   return 0;
643 }
644
645 #ifndef CLIB_MARCH_VARIANT
646 u32
647 icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node,
648                       u32 thread_index, vlib_buffer_t * b,
649                       ip4_header_t * ip, ip4_address_t * addr,
650                       u16 * port, u32 * fib_index, nat_protocol_t * proto,
651                       void *d, void *e, u8 * dont_translate)
652 {
653   u32 sw_if_index;
654   u32 rx_fib_index;
655   clib_bihash_kv_16_8_t kv, value;
656   u32 next = ~0;
657   int err;
658   snat_session_t *s = NULL;
659   u16 l_port = 0, r_port = 0;   // initialize to workaround gcc warning
660   vlib_main_t *vm = vlib_get_main ();
661   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
662   *dont_translate = 0;
663
664   sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
665   rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
666
667   err =
668     get_icmp_i2o_ed_key (b, ip, rx_fib_index, ~0, ~0, proto, &l_port,
669                          &r_port, &kv);
670   if (err != 0)
671     {
672       b->error = node->errors[err];
673       next = NAT_NEXT_DROP;
674       goto out;
675     }
676
677   if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
678     {
679       if (vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0)
680         {
681           if (PREDICT_FALSE
682               (nat44_ed_not_translate_output_feature
683                (sm, ip, l_port, r_port, thread_index,
684                 sw_if_index, vnet_buffer (b)->sw_if_index[VLIB_TX])))
685             {
686               *dont_translate = 1;
687               goto out;
688             }
689         }
690       else
691         {
692           if (PREDICT_FALSE (nat44_ed_not_translate (sm, node, sw_if_index,
693                                                      ip, NAT_PROTOCOL_ICMP,
694                                                      rx_fib_index,
695                                                      thread_index)))
696             {
697               *dont_translate = 1;
698               goto out;
699             }
700         }
701
702       if (PREDICT_FALSE
703           (icmp_type_is_error_message
704            (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)))
705         {
706           b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
707           next = NAT_NEXT_DROP;
708           goto out;
709         }
710
711       next =
712         slow_path_ed (sm, b, ip->src_address, ip->dst_address, l_port, r_port,
713                       ip->protocol, rx_fib_index, &s, node, next,
714                       thread_index, vlib_time_now (vm));
715
716       if (PREDICT_FALSE (next == NAT_NEXT_DROP))
717         goto out;
718
719       if (!s)
720         {
721           *dont_translate = 1;
722           goto out;
723         }
724     }
725   else
726     {
727       if (PREDICT_FALSE
728           (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
729            ICMP4_echo_request
730            && vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
731            ICMP4_echo_reply
732            && !icmp_type_is_error_message (vnet_buffer (b)->ip.
733                                            reass.icmp_type_or_tcp_flags)))
734         {
735           b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
736           next = NAT_NEXT_DROP;
737           goto out;
738         }
739
740       ASSERT (thread_index == ed_value_get_thread_index (&value));
741       s =
742         pool_elt_at_index (tsm->sessions,
743                            ed_value_get_session_index (&value));
744     }
745 out:
746   if (s)
747     {
748       *addr = s->out2in.addr;
749       *port = s->out2in.port;
750       *fib_index = s->out2in.fib_index;
751     }
752   if (d)
753     {
754       *(snat_session_t **) d = s;
755     }
756   return next;
757 }
758 #endif
759
760 static snat_session_t *
761 nat44_ed_in2out_unknown_proto (snat_main_t * sm,
762                                vlib_buffer_t * b,
763                                ip4_header_t * ip,
764                                u32 rx_fib_index,
765                                u32 thread_index,
766                                f64 now,
767                                vlib_main_t * vm, vlib_node_runtime_t * node)
768 {
769   clib_bihash_kv_8_8_t kv, value;
770   clib_bihash_kv_16_8_t s_kv, s_value;
771   snat_static_mapping_t *m;
772   u32 old_addr, new_addr = 0;
773   ip_csum_t sum;
774   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
775   snat_session_t *s;
776   u32 outside_fib_index = sm->outside_fib_index;
777   int i;
778   u8 is_sm = 0;
779
780   switch (vec_len (sm->outside_fibs))
781     {
782     case 0:
783       outside_fib_index = sm->outside_fib_index;
784       break;
785     case 1:
786       outside_fib_index = sm->outside_fibs[0].fib_index;
787       break;
788     default:
789       outside_fib_index = nat_outside_fib_index_lookup (sm, ip->dst_address);
790       break;
791     }
792   old_addr = ip->src_address.as_u32;
793
794   init_ed_k (&s_kv, ip->src_address, 0, ip->dst_address, 0, rx_fib_index,
795              ip->protocol);
796
797   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &s_kv, &s_value))
798     {
799       ASSERT (thread_index == ed_value_get_thread_index (&s_value));
800       s =
801         pool_elt_at_index (tsm->sessions,
802                            ed_value_get_session_index (&s_value));
803       new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
804     }
805   else
806     {
807       if (PREDICT_FALSE
808           (nat44_ed_maximum_sessions_exceeded
809            (sm, rx_fib_index, thread_index)))
810         {
811           b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
812           nat_ipfix_logging_max_sessions (thread_index,
813                                           sm->max_translations_per_thread);
814           nat_elog_notice ("maximum sessions exceeded");
815           return 0;
816         }
817
818       init_nat_k (&kv, ip->src_address, 0, rx_fib_index, 0);
819
820       /* Try to find static mapping first */
821       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
822         {
823           m = pool_elt_at_index (sm->static_mappings, value.value);
824           new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
825           is_sm = 1;
826           goto create_ses;
827         }
828       else
829         {
830           /* *INDENT-OFF* */
831           pool_foreach (s, tsm->sessions, {
832             if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32)
833               {
834                 new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
835
836                 init_ed_k(&s_kv, s->out2in.addr, 0, ip->dst_address, 0, outside_fib_index, ip->protocol);
837                 if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
838                   goto create_ses;
839
840                 break;
841               }
842           });
843           /* *INDENT-ON* */
844
845           for (i = 0; i < vec_len (sm->addresses); i++)
846             {
847               init_ed_k (&s_kv, sm->addresses[i].addr, 0, ip->dst_address, 0,
848                          outside_fib_index, ip->protocol);
849               if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
850                 {
851                   new_addr = ip->src_address.as_u32 =
852                     sm->addresses[i].addr.as_u32;
853                   goto create_ses;
854                 }
855             }
856           return 0;
857         }
858
859     create_ses:
860       s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
861       if (!s)
862         {
863           b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
864           nat_elog_warn ("create NAT session failed");
865           return 0;
866         }
867
868       s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
869       s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
870       s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
871       s->out2in.addr.as_u32 = new_addr;
872       s->out2in.fib_index = outside_fib_index;
873       s->in2out.addr.as_u32 = old_addr;
874       s->in2out.fib_index = rx_fib_index;
875       s->in2out.port = s->out2in.port = ip->protocol;
876       if (is_sm)
877         s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
878
879       /* Add to lookup tables */
880       init_ed_kv (&s_kv, s->in2out.addr, 0, ip->dst_address, 0, rx_fib_index,
881                   ip->protocol, thread_index, s - tsm->sessions);
882       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
883         nat_elog_notice ("in2out key add failed");
884
885       init_ed_kv (&s_kv, s->out2in.addr, 0, ip->dst_address, 0,
886                   outside_fib_index, ip->protocol, thread_index,
887                   s - tsm->sessions);
888       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
889         nat_elog_notice ("out2in key add failed");
890
891       per_vrf_sessions_register_session (s, thread_index);
892     }
893
894   /* Update IP checksum */
895   sum = ip->checksum;
896   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
897   ip->checksum = ip_csum_fold (sum);
898
899   /* Accounting */
900   nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b),
901                                  thread_index);
902   /* Per-user LRU list maintenance */
903   nat44_session_update_lru (sm, s, thread_index);
904
905   /* Hairpinning */
906   if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
907     nat44_ed_hairpinning_unknown_proto (sm, b, ip);
908
909   if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
910     vnet_buffer (b)->sw_if_index[VLIB_TX] = outside_fib_index;
911
912   return s;
913 }
914
915 static inline uword
916 nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
917                                           vlib_node_runtime_t * node,
918                                           vlib_frame_t * frame,
919                                           int is_output_feature)
920 {
921   u32 n_left_from, *from;
922   snat_main_t *sm = &snat_main;
923   f64 now = vlib_time_now (vm);
924   u32 thread_index = vm->thread_index;
925   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
926   u32 def_slow = is_output_feature ? NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH
927     : NAT_NEXT_IN2OUT_ED_SLOW_PATH;
928
929   from = vlib_frame_vector_args (frame);
930   n_left_from = frame->n_vectors;
931
932   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
933   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
934   vlib_get_buffers (vm, from, b, n_left_from);
935
936   while (n_left_from > 0)
937     {
938       vlib_buffer_t *b0;
939       u32 sw_if_index0, rx_fib_index0, proto0, new_addr0, old_addr0,
940         iph_offset0 = 0;
941       u16 old_port0, new_port0;
942       ip4_header_t *ip0;
943       udp_header_t *udp0;
944       tcp_header_t *tcp0;
945       snat_session_t *s0 = 0;
946       clib_bihash_kv_16_8_t kv0, value0;
947       ip_csum_t sum0;
948
949       b0 = *b;
950       b++;
951
952       /* Prefetch next iteration. */
953       if (PREDICT_TRUE (n_left_from >= 2))
954         {
955           vlib_buffer_t *p2;
956
957           p2 = *b;
958
959           vlib_prefetch_buffer_header (p2, LOAD);
960
961           CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
962         }
963
964       if (is_output_feature)
965         {
966           iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
967         }
968
969       next[0] = vnet_buffer2 (b0)->nat.arc_next;
970
971       ip0 =
972         (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + iph_offset0);
973
974       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
975       rx_fib_index0 =
976         fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index0);
977
978       if (PREDICT_FALSE (ip0->ttl == 1))
979         {
980           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
981           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
982                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
983                                        0);
984           next[0] = NAT_NEXT_ICMP_ERROR;
985           goto trace0;
986         }
987
988       udp0 = ip4_next_header (ip0);
989       tcp0 = (tcp_header_t *) udp0;
990       proto0 = ip_proto_to_nat_proto (ip0->protocol);
991
992       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
993         {
994           next[0] = def_slow;
995           goto trace0;
996         }
997
998       if (is_output_feature)
999         {
1000           if (PREDICT_FALSE
1001               (nat_not_translate_output_feature_fwd
1002                (sm, ip0, thread_index, now, vm, b0)))
1003             goto trace0;
1004         }
1005
1006       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1007         {
1008           next[0] = def_slow;
1009           goto trace0;
1010         }
1011
1012       init_ed_k (&kv0, ip0->src_address,
1013                  vnet_buffer (b0)->ip.reass.l4_src_port, ip0->dst_address,
1014                  vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
1015                  ip0->protocol);
1016
1017       // lookup for session
1018       if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
1019         {
1020           // session does not exist go slow path
1021           next[0] = def_slow;
1022           goto trace0;
1023         }
1024       ASSERT (thread_index == ed_value_get_thread_index (&value0));
1025       s0 =
1026         pool_elt_at_index (tsm->sessions,
1027                            ed_value_get_session_index (&value0));
1028
1029       if (PREDICT_FALSE (per_vrf_sessions_is_expired (s0, thread_index)))
1030         {
1031           // session is closed, go slow path
1032           nat_free_session_data (sm, s0, thread_index, 0);
1033           nat_ed_session_delete (sm, s0, thread_index, 1);
1034           next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
1035           goto trace0;
1036         }
1037
1038       if (s0->tcp_closed_timestamp)
1039         {
1040           if (now >= s0->tcp_closed_timestamp)
1041             {
1042               // session is closed, go slow path, freed in slow path
1043               next[0] = def_slow;
1044             }
1045           else
1046             {
1047               // session in transitory timeout, drop
1048               b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TCP_CLOSED];
1049               next[0] = NAT_NEXT_DROP;
1050             }
1051           goto trace0;
1052         }
1053
1054       // drop if session expired
1055       u64 sess_timeout_time;
1056       sess_timeout_time =
1057         s0->last_heard + (f64) nat44_session_get_timeout (sm, s0);
1058       if (now >= sess_timeout_time)
1059         {
1060           nat_free_session_data (sm, s0, thread_index, 0);
1061           nat_ed_session_delete (sm, s0, thread_index, 1);
1062           // session is closed, go slow path
1063           next[0] = def_slow;
1064           goto trace0;
1065         }
1066
1067       b0->flags |= VNET_BUFFER_F_IS_NATED;
1068
1069       if (!is_output_feature)
1070         vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1071
1072       old_addr0 = ip0->src_address.as_u32;
1073       new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
1074       sum0 = ip0->checksum;
1075       sum0 =
1076         ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1077                         src_address);
1078       if (PREDICT_FALSE (is_twice_nat_session (s0)))
1079         sum0 =
1080           ip_csum_update (sum0, ip0->dst_address.as_u32,
1081                           s0->ext_host_addr.as_u32, ip4_header_t,
1082                           dst_address);
1083       ip0->checksum = ip_csum_fold (sum0);
1084
1085       old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1086
1087       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1088         {
1089           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1090             {
1091               new_port0 = udp0->src_port = s0->out2in.port;
1092               sum0 = tcp0->checksum;
1093               sum0 =
1094                 ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1095                                 dst_address);
1096               sum0 =
1097                 ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1098                                 length);
1099               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1100                 {
1101                   sum0 =
1102                     ip_csum_update (sum0, ip0->dst_address.as_u32,
1103                                     s0->ext_host_addr.as_u32, ip4_header_t,
1104                                     dst_address);
1105                   sum0 =
1106                     ip_csum_update (sum0,
1107                                     vnet_buffer (b0)->ip.reass.l4_dst_port,
1108                                     s0->ext_host_port, ip4_header_t, length);
1109                   tcp0->dst_port = s0->ext_host_port;
1110                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1111                 }
1112               mss_clamping (sm->mss_clamping, tcp0, &sum0);
1113               tcp0->checksum = ip_csum_fold (sum0);
1114             }
1115           vlib_increment_simple_counter (&sm->counters.fastpath.in2out_ed.tcp,
1116                                          thread_index, sw_if_index0, 1);
1117           if (nat44_set_tcp_session_state_i2o (sm, now, s0, b0, thread_index))
1118             goto trace0;
1119         }
1120       else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
1121                && udp0->checksum)
1122         {
1123           new_port0 = udp0->src_port = s0->out2in.port;
1124           sum0 = udp0->checksum;
1125           sum0 =
1126             ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1127                             dst_address);
1128           sum0 =
1129             ip_csum_update (sum0, old_port0, new_port0, ip4_header_t, length);
1130           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1131             {
1132               sum0 =
1133                 ip_csum_update (sum0, ip0->dst_address.as_u32,
1134                                 s0->ext_host_addr.as_u32, ip4_header_t,
1135                                 dst_address);
1136               sum0 =
1137                 ip_csum_update (sum0, vnet_buffer (b0)->ip.reass.l4_dst_port,
1138                                 s0->ext_host_port, ip4_header_t, length);
1139               udp0->dst_port = s0->ext_host_port;
1140               ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1141             }
1142           udp0->checksum = ip_csum_fold (sum0);
1143           vlib_increment_simple_counter (&sm->counters.fastpath.in2out_ed.udp,
1144                                          thread_index, sw_if_index0, 1);
1145         }
1146       else
1147         {
1148           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1149             {
1150               new_port0 = udp0->src_port = s0->out2in.port;
1151               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1152                 {
1153                   udp0->dst_port = s0->ext_host_port;
1154                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1155                 }
1156               vlib_increment_simple_counter (&sm->counters.fastpath.
1157                                              in2out_ed.udp, thread_index,
1158                                              sw_if_index0, 1);
1159             }
1160         }
1161
1162       /* Accounting */
1163       nat44_session_update_counters (s0, now,
1164                                      vlib_buffer_length_in_chain (vm, b0),
1165                                      thread_index);
1166       /* Per-user LRU list maintenance */
1167       nat44_session_update_lru (sm, s0, thread_index);
1168
1169     trace0:
1170       if (PREDICT_FALSE
1171           ((node->flags & VLIB_NODE_FLAG_TRACE)
1172            && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1173         {
1174           nat_in2out_ed_trace_t *t =
1175             vlib_add_trace (vm, node, b0, sizeof (*t));
1176           t->sw_if_index = sw_if_index0;
1177           t->next_index = next[0];
1178           t->is_slow_path = 0;
1179
1180           if (s0)
1181             t->session_index = s0 - tsm->sessions;
1182           else
1183             t->session_index = ~0;
1184         }
1185
1186       if (next[0] == NAT_NEXT_DROP)
1187         {
1188           vlib_increment_simple_counter (&sm->counters.fastpath.
1189                                          in2out_ed.drops, thread_index,
1190                                          sw_if_index0, 1);
1191         }
1192
1193       n_left_from--;
1194       next++;
1195     }
1196
1197   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1198                                frame->n_vectors);
1199   return frame->n_vectors;
1200 }
1201
1202 static inline uword
1203 nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm,
1204                                           vlib_node_runtime_t * node,
1205                                           vlib_frame_t * frame,
1206                                           int is_output_feature)
1207 {
1208   u32 n_left_from, *from;
1209   snat_main_t *sm = &snat_main;
1210   f64 now = vlib_time_now (vm);
1211   u32 thread_index = vm->thread_index;
1212   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1213
1214   from = vlib_frame_vector_args (frame);
1215   n_left_from = frame->n_vectors;
1216
1217   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
1218   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
1219   vlib_get_buffers (vm, from, b, n_left_from);
1220
1221   while (n_left_from > 0)
1222     {
1223       vlib_buffer_t *b0;
1224       u32 sw_if_index0, rx_fib_index0, proto0, new_addr0, old_addr0,
1225         iph_offset0 = 0;
1226       u16 old_port0, new_port0;
1227       ip4_header_t *ip0;
1228       udp_header_t *udp0;
1229       tcp_header_t *tcp0;
1230       icmp46_header_t *icmp0;
1231       snat_session_t *s0 = 0;
1232       clib_bihash_kv_16_8_t kv0, value0;
1233       ip_csum_t sum0;
1234
1235       b0 = *b;
1236
1237       if (is_output_feature)
1238         iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
1239
1240       next[0] = vnet_buffer2 (b0)->nat.arc_next;
1241
1242       ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1243                               iph_offset0);
1244
1245       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1246       rx_fib_index0 =
1247         fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index0);
1248
1249       if (PREDICT_FALSE (ip0->ttl == 1))
1250         {
1251           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1252           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1253                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
1254                                        0);
1255           next[0] = NAT_NEXT_ICMP_ERROR;
1256           goto trace0;
1257         }
1258
1259       udp0 = ip4_next_header (ip0);
1260       tcp0 = (tcp_header_t *) udp0;
1261       icmp0 = (icmp46_header_t *) udp0;
1262       proto0 = ip_proto_to_nat_proto (ip0->protocol);
1263
1264       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1265         {
1266           s0 = nat44_ed_in2out_unknown_proto (sm, b0, ip0,
1267                                               rx_fib_index0,
1268                                               thread_index, now, vm, node);
1269           if (!s0)
1270             next[0] = NAT_NEXT_DROP;
1271
1272           vlib_increment_simple_counter (&sm->counters.slowpath.
1273                                          in2out_ed.other, thread_index,
1274                                          sw_if_index0, 1);
1275           goto trace0;
1276         }
1277
1278       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1279         {
1280           next[0] =
1281             icmp_in2out_ed_slow_path (sm, b0, ip0, icmp0, sw_if_index0,
1282                                       rx_fib_index0, node, next[0], now,
1283                                       thread_index, &s0);
1284           vlib_increment_simple_counter (&sm->counters.slowpath.
1285                                          in2out_ed.icmp, thread_index,
1286                                          sw_if_index0, 1);
1287           goto trace0;
1288         }
1289
1290       init_ed_k (&kv0, ip0->src_address,
1291                  vnet_buffer (b0)->ip.reass.l4_src_port, ip0->dst_address,
1292                  vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
1293                  ip0->protocol);
1294       if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
1295         {
1296           ASSERT (thread_index == ed_value_get_thread_index (&value0));
1297           s0 =
1298             pool_elt_at_index (tsm->sessions,
1299                                ed_value_get_session_index (&value0));
1300
1301           if (s0->tcp_closed_timestamp && now >= s0->tcp_closed_timestamp)
1302             {
1303               nat_free_session_data (sm, s0, thread_index, 0);
1304               nat_ed_session_delete (sm, s0, thread_index, 1);
1305               s0 = NULL;
1306             }
1307         }
1308
1309       if (!s0)
1310         {
1311           if (is_output_feature)
1312             {
1313               if (PREDICT_FALSE
1314                   (nat44_ed_not_translate_output_feature
1315                    (sm, ip0, vnet_buffer (b0)->ip.reass.l4_src_port,
1316                     vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
1317                     sw_if_index0, vnet_buffer (b0)->sw_if_index[VLIB_TX])))
1318                 goto trace0;
1319
1320               /*
1321                * Send DHCP packets to the ipv4 stack, or we won't
1322                * be able to use dhcp client on the outside interface
1323                */
1324               if (PREDICT_FALSE
1325                   (proto0 == NAT_PROTOCOL_UDP
1326                    && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1327                        clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_server))
1328                    && ip0->dst_address.as_u32 == 0xffffffff))
1329                 goto trace0;
1330             }
1331           else
1332             {
1333               if (PREDICT_FALSE
1334                   (nat44_ed_not_translate
1335                    (sm, node, sw_if_index0, ip0, proto0, rx_fib_index0,
1336                     thread_index)))
1337                 goto trace0;
1338             }
1339
1340           next[0] =
1341             slow_path_ed (sm, b0, ip0->src_address, ip0->dst_address,
1342                           vnet_buffer (b0)->ip.reass.l4_src_port,
1343                           vnet_buffer (b0)->ip.reass.l4_dst_port,
1344                           ip0->protocol, rx_fib_index0, &s0, node, next[0],
1345                           thread_index, now);
1346
1347           if (PREDICT_FALSE (next[0] == NAT_NEXT_DROP))
1348             goto trace0;
1349
1350           if (PREDICT_FALSE (!s0))
1351             goto trace0;
1352
1353         }
1354
1355       b0->flags |= VNET_BUFFER_F_IS_NATED;
1356
1357       if (!is_output_feature)
1358         vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1359
1360       old_addr0 = ip0->src_address.as_u32;
1361       new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
1362       sum0 = ip0->checksum;
1363       sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1364                              src_address);
1365       if (PREDICT_FALSE (is_twice_nat_session (s0)))
1366         sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1367                                s0->ext_host_addr.as_u32, ip4_header_t,
1368                                dst_address);
1369       ip0->checksum = ip_csum_fold (sum0);
1370
1371       old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1372
1373       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1374         {
1375           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1376             {
1377               new_port0 = udp0->src_port = s0->out2in.port;
1378               sum0 = tcp0->checksum;
1379               sum0 =
1380                 ip_csum_update (sum0, old_addr0, new_addr0,
1381                                 ip4_header_t, dst_address);
1382               sum0 =
1383                 ip_csum_update (sum0, old_port0, new_port0,
1384                                 ip4_header_t, length);
1385               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1386                 {
1387                   sum0 =
1388                     ip_csum_update (sum0, ip0->dst_address.as_u32,
1389                                     s0->ext_host_addr.as_u32,
1390                                     ip4_header_t, dst_address);
1391                   sum0 =
1392                     ip_csum_update (sum0,
1393                                     vnet_buffer (b0)->ip.reass.l4_dst_port,
1394                                     s0->ext_host_port, ip4_header_t, length);
1395                   tcp0->dst_port = s0->ext_host_port;
1396                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1397                 }
1398               mss_clamping (sm->mss_clamping, tcp0, &sum0);
1399               tcp0->checksum = ip_csum_fold (sum0);
1400             }
1401           vlib_increment_simple_counter (&sm->counters.slowpath.in2out_ed.tcp,
1402                                          thread_index, sw_if_index0, 1);
1403           if (nat44_set_tcp_session_state_i2o (sm, now, s0, b0, thread_index))
1404             goto trace0;
1405         }
1406       else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
1407                && udp0->checksum)
1408         {
1409           new_port0 = udp0->src_port = s0->out2in.port;
1410           sum0 = udp0->checksum;
1411           sum0 =
1412             ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1413                             dst_address);
1414           sum0 =
1415             ip_csum_update (sum0, old_port0, new_port0, ip4_header_t, length);
1416           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1417             {
1418               sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1419                                      s0->ext_host_addr.as_u32,
1420                                      ip4_header_t, dst_address);
1421               sum0 =
1422                 ip_csum_update (sum0,
1423                                 vnet_buffer (b0)->ip.reass.l4_dst_port,
1424                                 s0->ext_host_port, ip4_header_t, length);
1425               udp0->dst_port = s0->ext_host_port;
1426               ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1427             }
1428           udp0->checksum = ip_csum_fold (sum0);
1429           vlib_increment_simple_counter (&sm->counters.slowpath.in2out_ed.udp,
1430                                          thread_index, sw_if_index0, 1);
1431         }
1432       else
1433         {
1434           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1435             {
1436               new_port0 = udp0->src_port = s0->out2in.port;
1437               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1438                 {
1439                   udp0->dst_port = s0->ext_host_port;
1440                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1441                 }
1442               vlib_increment_simple_counter (&sm->counters.slowpath.
1443                                              in2out_ed.udp, thread_index,
1444                                              sw_if_index0, 1);
1445             }
1446         }
1447
1448       /* Accounting */
1449       nat44_session_update_counters (s0, now,
1450                                      vlib_buffer_length_in_chain
1451                                      (vm, b0), thread_index);
1452       /* Per-user LRU list maintenance */
1453       nat44_session_update_lru (sm, s0, thread_index);
1454
1455     trace0:
1456       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1457                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1458         {
1459           nat_in2out_ed_trace_t *t =
1460             vlib_add_trace (vm, node, b0, sizeof (*t));
1461           t->sw_if_index = sw_if_index0;
1462           t->next_index = next[0];
1463           t->is_slow_path = 1;
1464
1465           if (s0)
1466             t->session_index = s0 - tsm->sessions;
1467           else
1468             t->session_index = ~0;
1469         }
1470
1471       if (next[0] == NAT_NEXT_DROP)
1472         {
1473           vlib_increment_simple_counter (&sm->counters.slowpath.
1474                                          in2out_ed.drops, thread_index,
1475                                          sw_if_index0, 1);
1476         }
1477
1478       n_left_from--;
1479       next++;
1480       b++;
1481     }
1482
1483   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1484                                frame->n_vectors);
1485
1486   return frame->n_vectors;
1487 }
1488
1489 VLIB_NODE_FN (nat44_ed_in2out_node) (vlib_main_t * vm,
1490                                      vlib_node_runtime_t * node,
1491                                      vlib_frame_t * frame)
1492 {
1493   return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 0);
1494 }
1495
1496 /* *INDENT-OFF* */
1497 VLIB_REGISTER_NODE (nat44_ed_in2out_node) = {
1498   .name = "nat44-ed-in2out",
1499   .vector_size = sizeof (u32),
1500   .sibling_of = "nat-default",
1501   .format_trace = format_nat_in2out_ed_trace,
1502   .type = VLIB_NODE_TYPE_INTERNAL,
1503   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1504   .error_strings = nat_in2out_ed_error_strings,
1505   .runtime_data_bytes = sizeof (snat_runtime_t),
1506 };
1507 /* *INDENT-ON* */
1508
1509 VLIB_NODE_FN (nat44_ed_in2out_output_node) (vlib_main_t * vm,
1510                                             vlib_node_runtime_t * node,
1511                                             vlib_frame_t * frame)
1512 {
1513   return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 1);
1514 }
1515
1516 /* *INDENT-OFF* */
1517 VLIB_REGISTER_NODE (nat44_ed_in2out_output_node) = {
1518   .name = "nat44-ed-in2out-output",
1519   .vector_size = sizeof (u32),
1520   .sibling_of = "nat-default",
1521   .format_trace = format_nat_in2out_ed_trace,
1522   .type = VLIB_NODE_TYPE_INTERNAL,
1523   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1524   .error_strings = nat_in2out_ed_error_strings,
1525   .runtime_data_bytes = sizeof (snat_runtime_t),
1526 };
1527 /* *INDENT-ON* */
1528
1529 VLIB_NODE_FN (nat44_ed_in2out_slowpath_node) (vlib_main_t * vm,
1530                                               vlib_node_runtime_t *
1531                                               node, vlib_frame_t * frame)
1532 {
1533   return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 0);
1534 }
1535
1536 /* *INDENT-OFF* */
1537 VLIB_REGISTER_NODE (nat44_ed_in2out_slowpath_node) = {
1538   .name = "nat44-ed-in2out-slowpath",
1539   .vector_size = sizeof (u32),
1540   .sibling_of = "nat-default",
1541   .format_trace = format_nat_in2out_ed_trace,
1542   .type = VLIB_NODE_TYPE_INTERNAL,
1543   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1544   .error_strings = nat_in2out_ed_error_strings,
1545   .runtime_data_bytes = sizeof (snat_runtime_t),
1546 };
1547 /* *INDENT-ON* */
1548
1549 VLIB_NODE_FN (nat44_ed_in2out_output_slowpath_node) (vlib_main_t * vm,
1550                                                      vlib_node_runtime_t
1551                                                      * node,
1552                                                      vlib_frame_t * frame)
1553 {
1554   return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 1);
1555 }
1556
1557 /* *INDENT-OFF* */
1558 VLIB_REGISTER_NODE (nat44_ed_in2out_output_slowpath_node) = {
1559   .name = "nat44-ed-in2out-output-slowpath",
1560   .vector_size = sizeof (u32),
1561   .sibling_of = "nat-default",
1562   .format_trace = format_nat_in2out_ed_trace,
1563   .type = VLIB_NODE_TYPE_INTERNAL,
1564   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1565   .error_strings = nat_in2out_ed_error_strings,
1566   .runtime_data_bytes = sizeof (snat_runtime_t),
1567 };
1568 /* *INDENT-ON* */
1569
1570 static u8 *
1571 format_nat_pre_trace (u8 * s, va_list * args)
1572 {
1573   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1574   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1575   nat_pre_trace_t *t = va_arg (*args, nat_pre_trace_t *);
1576   return format (s, "in2out next_index %d arc_next_index %d", t->next_index,
1577                  t->arc_next_index);
1578 }
1579
1580 VLIB_NODE_FN (nat_pre_in2out_node)
1581   (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1582 {
1583   return nat_pre_node_fn_inline (vm, node, frame,
1584                                  NAT_NEXT_IN2OUT_ED_FAST_PATH);
1585 }
1586
1587 VLIB_NODE_FN (nat_pre_in2out_output_node)
1588   (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1589 {
1590   return nat_pre_node_fn_inline (vm, node, frame,
1591                                  NAT_NEXT_IN2OUT_ED_OUTPUT_FAST_PATH);
1592 }
1593
1594 /* *INDENT-OFF* */
1595 VLIB_REGISTER_NODE (nat_pre_in2out_node) = {
1596   .name = "nat-pre-in2out",
1597   .vector_size = sizeof (u32),
1598   .sibling_of = "nat-default",
1599   .format_trace = format_nat_pre_trace,
1600   .type = VLIB_NODE_TYPE_INTERNAL,
1601   .n_errors = 0,
1602 };
1603
1604 VLIB_REGISTER_NODE (nat_pre_in2out_output_node) = {
1605   .name = "nat-pre-in2out-output",
1606   .vector_size = sizeof (u32),
1607   .sibling_of = "nat-default",
1608   .format_trace = format_nat_pre_trace,
1609   .type = VLIB_NODE_TYPE_INTERNAL,
1610   .n_errors = 0,
1611 };
1612 /* *INDENT-ON* */
1613
1614 /*
1615  * fd.io coding-style-patch-verification: ON
1616  *
1617  * Local Variables:
1618  * eval: (c-set-style "gnu")
1619  * End:
1620  */