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