NAT: VPP-1552 code migration from old multiarch scheme
[vpp.git] / src / plugins / nat / out2in_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 outside to inside network translation
18  */
19
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22 #include <vnet/pg/pg.h>
23 #include <vnet/ip/ip.h>
24 #include <vnet/ethernet/ethernet.h>
25 #include <vnet/fib/ip4_fib.h>
26 #include <vnet/udp/udp.h>
27 #include <vppinfra/error.h>
28 #include <nat/nat.h>
29 #include <nat/nat_ipfix_logging.h>
30 #include <nat/nat_reass.h>
31 #include <nat/nat_inlines.h>
32 #include <nat/nat_syslog.h>
33
34 #define foreach_nat_out2in_ed_error                     \
35 _(UNSUPPORTED_PROTOCOL, "unsupported protocol")         \
36 _(OUT2IN_PACKETS, "good out2in packets processed")      \
37 _(OUT_OF_PORTS, "out of ports")                         \
38 _(BAD_ICMP_TYPE, "unsupported ICMP type")               \
39 _(NO_TRANSLATION, "no translation")                     \
40 _(MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded")   \
41 _(DROP_FRAGMENT, "drop fragment")                       \
42 _(MAX_REASS, "maximum reassemblies exceeded")           \
43 _(MAX_FRAG, "maximum fragments per reassembly exceeded")\
44 _(NON_SYN, "non-SYN packet try to create session")      \
45 _(TCP_PACKETS, "TCP packets")                           \
46 _(UDP_PACKETS, "UDP packets")                           \
47 _(ICMP_PACKETS, "ICMP packets")                         \
48 _(OTHER_PACKETS, "other protocol packets")              \
49 _(FRAGMENTS, "fragments")                               \
50 _(CACHED_FRAGMENTS, "cached fragments")                 \
51 _(PROCESSED_FRAGMENTS, "processed fragments")
52
53 typedef enum
54 {
55 #define _(sym,str) NAT_OUT2IN_ED_ERROR_##sym,
56   foreach_nat_out2in_ed_error
57 #undef _
58     NAT_OUT2IN_ED_N_ERROR,
59 } nat_out2in_ed_error_t;
60
61 static char *nat_out2in_ed_error_strings[] = {
62 #define _(sym,string) string,
63   foreach_nat_out2in_ed_error
64 #undef _
65 };
66
67 typedef enum
68 {
69   NAT44_ED_OUT2IN_NEXT_DROP,
70   NAT44_ED_OUT2IN_NEXT_LOOKUP,
71   NAT44_ED_OUT2IN_NEXT_ICMP_ERROR,
72   NAT44_ED_OUT2IN_NEXT_IN2OUT,
73   NAT44_ED_OUT2IN_NEXT_SLOW_PATH,
74   NAT44_ED_OUT2IN_NEXT_REASS,
75   NAT44_ED_OUT2IN_N_NEXT,
76 } nat44_ed_out2in_next_t;
77
78 typedef struct
79 {
80   u32 sw_if_index;
81   u32 next_index;
82   u32 session_index;
83   u32 is_slow_path;
84 } nat44_ed_out2in_trace_t;
85
86 static u8 *
87 format_nat44_ed_out2in_trace (u8 * s, va_list * args)
88 {
89   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
90   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
91   nat44_ed_out2in_trace_t *t = va_arg (*args, nat44_ed_out2in_trace_t *);
92   char *tag;
93
94   tag =
95     t->is_slow_path ? "NAT44_OUT2IN_ED_SLOW_PATH" :
96     "NAT44_OUT2IN_ED_FAST_PATH";
97
98   s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
99               t->sw_if_index, t->next_index, t->session_index);
100
101   return s;
102 }
103
104 static inline u32
105 icmp_out2in_ed_slow_path (snat_main_t * sm, vlib_buffer_t * b0,
106                           ip4_header_t * ip0, icmp46_header_t * icmp0,
107                           u32 sw_if_index0, u32 rx_fib_index0,
108                           vlib_node_runtime_t * node, u32 next0, f64 now,
109                           u32 thread_index, snat_session_t ** p_s0)
110 {
111   next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
112                        next0, thread_index, p_s0, 0);
113   snat_session_t *s0 = *p_s0;
114   if (PREDICT_TRUE (next0 != NAT44_ED_OUT2IN_NEXT_DROP && s0))
115     {
116       /* Accounting */
117       nat44_session_update_counters (s0, now,
118                                      vlib_buffer_length_in_chain
119                                      (sm->vlib_main, b0));
120       /* Per-user LRU list maintenance */
121       nat44_session_update_lru (sm, s0, thread_index);
122     }
123   return next0;
124 }
125
126 #ifndef CLIB_MARCH_VARIANT
127 int
128 nat44_o2i_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
129 {
130   snat_main_t *sm = &snat_main;
131   nat44_is_idle_session_ctx_t *ctx = arg;
132   snat_session_t *s;
133   u64 sess_timeout_time;
134   nat_ed_ses_key_t ed_key;
135   clib_bihash_kv_16_8_t ed_kv;
136   int i;
137   snat_address_t *a;
138   snat_session_key_t key;
139   snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
140                                                        ctx->thread_index);
141
142   s = pool_elt_at_index (tsm->sessions, kv->value);
143   sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
144   if (ctx->now >= sess_timeout_time)
145     {
146       ed_key.l_addr = s->in2out.addr;
147       ed_key.r_addr = s->ext_host_addr;
148       ed_key.fib_index = s->in2out.fib_index;
149       if (snat_is_unk_proto_session (s))
150         {
151           ed_key.proto = s->in2out.port;
152           ed_key.r_port = 0;
153           ed_key.l_port = 0;
154         }
155       else
156         {
157           ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
158           ed_key.l_port = s->in2out.port;
159           ed_key.r_port = s->ext_host_port;
160         }
161       if (is_twice_nat_session (s))
162         {
163           ed_key.r_addr = s->ext_host_nat_addr;
164           ed_key.r_port = s->ext_host_nat_port;
165         }
166       ed_kv.key[0] = ed_key.as_u64[0];
167       ed_kv.key[1] = ed_key.as_u64[1];
168       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
169         nat_log_warn ("in2out_ed key del failed");
170
171       if (snat_is_unk_proto_session (s))
172         goto delete;
173
174       snat_ipfix_logging_nat44_ses_delete (ctx->thread_index,
175                                            s->in2out.addr.as_u32,
176                                            s->out2in.addr.as_u32,
177                                            s->in2out.protocol,
178                                            s->in2out.port,
179                                            s->out2in.port,
180                                            s->in2out.fib_index);
181
182       nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
183                              &s->in2out.addr, s->in2out.port,
184                              &s->ext_host_nat_addr, s->ext_host_nat_port,
185                              &s->out2in.addr, s->out2in.port,
186                              &s->ext_host_addr, s->ext_host_port,
187                              s->in2out.protocol, is_twice_nat_session (s));
188
189       if (is_twice_nat_session (s))
190         {
191           for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
192             {
193               key.protocol = s->in2out.protocol;
194               key.port = s->ext_host_nat_port;
195               a = sm->twice_nat_addresses + i;
196               if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
197                 {
198                   snat_free_outside_address_and_port (sm->twice_nat_addresses,
199                                                       ctx->thread_index,
200                                                       &key);
201                   break;
202                 }
203             }
204         }
205
206       if (snat_is_session_static (s))
207         goto delete;
208
209       snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
210                                           &s->out2in);
211     delete:
212       nat44_delete_session (sm, s, ctx->thread_index);
213       return 1;
214     }
215
216   return 0;
217 }
218 #endif
219
220 static snat_session_t *
221 create_session_for_static_mapping_ed (snat_main_t * sm,
222                                       vlib_buffer_t * b,
223                                       snat_session_key_t l_key,
224                                       snat_session_key_t e_key,
225                                       vlib_node_runtime_t * node,
226                                       u32 thread_index,
227                                       twice_nat_type_t twice_nat,
228                                       lb_nat_type_t lb_nat, f64 now)
229 {
230   snat_session_t *s;
231   snat_user_t *u;
232   ip4_header_t *ip;
233   udp_header_t *udp;
234   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
235   clib_bihash_kv_16_8_t kv;
236   snat_session_key_t eh_key;
237   nat44_is_idle_session_ctx_t ctx;
238
239   if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
240     {
241       b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
242       nat_log_notice ("maximum sessions exceeded");
243       return 0;
244     }
245
246   u = nat_user_get_or_create (sm, &l_key.addr, l_key.fib_index, thread_index);
247   if (!u)
248     {
249       nat_log_warn ("create NAT user failed");
250       return 0;
251     }
252
253   s = nat_ed_session_alloc (sm, u, thread_index, now);
254   if (!s)
255     {
256       nat44_delete_user_with_no_session (sm, u, thread_index);
257       nat_log_warn ("create NAT session failed");
258       return 0;
259     }
260
261   ip = vlib_buffer_get_current (b);
262   udp = ip4_next_header (ip);
263
264   s->ext_host_addr.as_u32 = ip->src_address.as_u32;
265   s->ext_host_port = e_key.protocol == SNAT_PROTOCOL_ICMP ? 0 : udp->src_port;
266   s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
267   if (lb_nat)
268     s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
269   if (lb_nat == AFFINITY_LB_NAT)
270     s->flags |= SNAT_SESSION_FLAG_AFFINITY;
271   s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
272   s->out2in = e_key;
273   s->in2out = l_key;
274   s->in2out.protocol = s->out2in.protocol;
275   user_session_increment (sm, u, 1);
276
277   /* Add to lookup tables */
278   make_ed_kv (&kv, &e_key.addr, &s->ext_host_addr, ip->protocol,
279               e_key.fib_index, e_key.port, s->ext_host_port);
280   kv.value = s - tsm->sessions;
281   ctx.now = now;
282   ctx.thread_index = thread_index;
283   if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->out2in_ed, &kv,
284                                                nat44_o2i_ed_is_idle_session_cb,
285                                                &ctx))
286     nat_log_notice ("out2in-ed key add failed");
287
288   if (twice_nat == TWICE_NAT || (twice_nat == TWICE_NAT_SELF &&
289                                  ip->src_address.as_u32 == l_key.addr.as_u32))
290     {
291       eh_key.protocol = e_key.protocol;
292       if (snat_alloc_outside_address_and_port (sm->twice_nat_addresses, 0,
293                                                thread_index, &eh_key,
294                                                sm->port_per_thread,
295                                                tsm->snat_thread_index))
296         {
297           b->error = node->errors[NAT_OUT2IN_ED_ERROR_OUT_OF_PORTS];
298           nat44_delete_session (sm, s, thread_index);
299           if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 0))
300             nat_log_notice ("out2in-ed key del failed");
301           return 0;
302         }
303       s->ext_host_nat_addr.as_u32 = eh_key.addr.as_u32;
304       s->ext_host_nat_port = eh_key.port;
305       s->flags |= SNAT_SESSION_FLAG_TWICE_NAT;
306       make_ed_kv (&kv, &l_key.addr, &s->ext_host_nat_addr, ip->protocol,
307                   l_key.fib_index, l_key.port, s->ext_host_nat_port);
308     }
309   else
310     {
311       make_ed_kv (&kv, &l_key.addr, &s->ext_host_addr, ip->protocol,
312                   l_key.fib_index, l_key.port, s->ext_host_port);
313     }
314   kv.value = s - tsm->sessions;
315   if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, &kv,
316                                                nat44_i2o_ed_is_idle_session_cb,
317                                                &ctx))
318     nat_log_notice ("in2out-ed key add failed");
319
320   snat_ipfix_logging_nat44_ses_create (thread_index,
321                                        s->in2out.addr.as_u32,
322                                        s->out2in.addr.as_u32,
323                                        s->in2out.protocol,
324                                        s->in2out.port,
325                                        s->out2in.port, s->in2out.fib_index);
326
327   nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
328                          &s->in2out.addr, s->in2out.port,
329                          &s->ext_host_nat_addr, s->ext_host_nat_port,
330                          &s->out2in.addr, s->out2in.port,
331                          &s->ext_host_addr, s->ext_host_port,
332                          s->in2out.protocol, is_twice_nat_session (s));
333
334   return s;
335 }
336
337 static_always_inline int
338 icmp_get_ed_key (ip4_header_t * ip0, nat_ed_ses_key_t * p_key0)
339 {
340   icmp46_header_t *icmp0;
341   nat_ed_ses_key_t key0;
342   icmp_echo_header_t *echo0, *inner_echo0 = 0;
343   ip4_header_t *inner_ip0;
344   void *l4_header = 0;
345   icmp46_header_t *inner_icmp0;
346
347   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
348   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
349
350   if (!icmp_is_error_message (icmp0))
351     {
352       key0.proto = IP_PROTOCOL_ICMP;
353       key0.l_addr = ip0->dst_address;
354       key0.r_addr = ip0->src_address;
355       key0.l_port = echo0->identifier;
356       key0.r_port = 0;
357     }
358   else
359     {
360       inner_ip0 = (ip4_header_t *) (echo0 + 1);
361       l4_header = ip4_next_header (inner_ip0);
362       key0.proto = inner_ip0->protocol;
363       key0.l_addr = inner_ip0->src_address;
364       key0.r_addr = inner_ip0->dst_address;
365       switch (ip_proto_to_snat_proto (inner_ip0->protocol))
366         {
367         case SNAT_PROTOCOL_ICMP:
368           inner_icmp0 = (icmp46_header_t *) l4_header;
369           inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
370           key0.l_port = inner_echo0->identifier;
371           key0.r_port = 0;
372           break;
373         case SNAT_PROTOCOL_UDP:
374         case SNAT_PROTOCOL_TCP:
375           key0.l_port = ((tcp_udp_header_t *) l4_header)->src_port;
376           key0.r_port = ((tcp_udp_header_t *) l4_header)->dst_port;
377           break;
378         default:
379           return -1;
380         }
381     }
382   *p_key0 = key0;
383   return 0;
384 }
385
386 static int
387 next_src_nat (snat_main_t * sm, ip4_header_t * ip, u8 proto, u16 src_port,
388               u16 dst_port, u32 thread_index, u32 rx_fib_index)
389 {
390   clib_bihash_kv_16_8_t kv, value;
391   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
392
393   make_ed_kv (&kv, &ip->src_address, &ip->dst_address, proto,
394               rx_fib_index, src_port, dst_port);
395   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
396     return 1;
397
398   return 0;
399 }
400
401 static void
402 create_bypass_for_fwd (snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index,
403                        u32 thread_index)
404 {
405   nat_ed_ses_key_t key;
406   clib_bihash_kv_16_8_t kv, value;
407   udp_header_t *udp;
408   snat_user_t *u;
409   snat_session_t *s = 0;
410   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
411   f64 now = vlib_time_now (sm->vlib_main);
412
413   if (ip->protocol == IP_PROTOCOL_ICMP)
414     {
415       if (icmp_get_ed_key (ip, &key))
416         return;
417     }
418   else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
419     {
420       udp = ip4_next_header (ip);
421       key.r_addr = ip->src_address;
422       key.l_addr = ip->dst_address;
423       key.proto = ip->protocol;
424       key.l_port = udp->dst_port;
425       key.r_port = udp->src_port;
426     }
427   else
428     {
429       key.r_addr = ip->src_address;
430       key.l_addr = ip->dst_address;
431       key.proto = ip->protocol;
432       key.l_port = key.r_port = 0;
433     }
434   key.fib_index = 0;
435   kv.key[0] = key.as_u64[0];
436   kv.key[1] = key.as_u64[1];
437
438   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
439     {
440       s = pool_elt_at_index (tsm->sessions, value.value);
441     }
442   else
443     {
444       if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
445         return;
446
447       u = nat_user_get_or_create (sm, &ip->dst_address, sm->inside_fib_index,
448                                   thread_index);
449       if (!u)
450         {
451           nat_log_warn ("create NAT user failed");
452           return;
453         }
454
455       s = nat_ed_session_alloc (sm, u, thread_index, now);
456       if (!s)
457         {
458           nat44_delete_user_with_no_session (sm, u, thread_index);
459           nat_log_warn ("create NAT session failed");
460           return;
461         }
462
463       s->ext_host_addr = key.r_addr;
464       s->ext_host_port = key.r_port;
465       s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS;
466       s->out2in.addr = key.l_addr;
467       s->out2in.port = key.l_port;
468       s->out2in.protocol = ip_proto_to_snat_proto (key.proto);
469       s->out2in.fib_index = 0;
470       s->in2out = s->out2in;
471       user_session_increment (sm, u, 0);
472
473       kv.value = s - tsm->sessions;
474       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
475         nat_log_notice ("in2out_ed key add failed");
476     }
477
478   if (ip->protocol == IP_PROTOCOL_TCP)
479     {
480       tcp_header_t *tcp = ip4_next_header (ip);
481       if (nat44_set_tcp_session_state_o2i (sm, s, tcp, thread_index))
482         return;
483     }
484
485   /* Accounting */
486   nat44_session_update_counters (s, now, 0);
487   /* Per-user LRU list maintenance */
488   nat44_session_update_lru (sm, s, thread_index);
489 }
490
491 #ifndef CLIB_MARCH_VARIANT
492 u32
493 icmp_match_out2in_ed (snat_main_t * sm, vlib_node_runtime_t * node,
494                       u32 thread_index, vlib_buffer_t * b, ip4_header_t * ip,
495                       u8 * p_proto, snat_session_key_t * p_value,
496                       u8 * p_dont_translate, void *d, void *e)
497 {
498   u32 next = ~0, sw_if_index, rx_fib_index;
499   icmp46_header_t *icmp;
500   nat_ed_ses_key_t key;
501   clib_bihash_kv_16_8_t kv, value;
502   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
503   snat_session_t *s = 0;
504   u8 dont_translate = 0, is_addr_only, identity_nat;
505   snat_session_key_t e_key, l_key;
506
507   icmp = (icmp46_header_t *) ip4_next_header (ip);
508   sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
509   rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
510
511   if (icmp_get_ed_key (ip, &key))
512     {
513       b->error = node->errors[NAT_OUT2IN_ED_ERROR_UNSUPPORTED_PROTOCOL];
514       next = NAT44_ED_OUT2IN_NEXT_DROP;
515       goto out;
516     }
517   key.fib_index = rx_fib_index;
518   kv.key[0] = key.as_u64[0];
519   kv.key[1] = key.as_u64[1];
520
521   if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
522     {
523       /* Try to match static mapping */
524       e_key.addr = ip->dst_address;
525       e_key.port = key.l_port;
526       e_key.protocol = ip_proto_to_snat_proto (key.proto);
527       e_key.fib_index = rx_fib_index;
528       if (snat_static_mapping_match
529           (sm, e_key, &l_key, 1, &is_addr_only, 0, 0, 0, &identity_nat))
530         {
531           if (!sm->forwarding_enabled)
532             {
533               /* Don't NAT packet aimed at the intfc address */
534               if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index,
535                                                     ip->dst_address.as_u32)))
536                 {
537                   dont_translate = 1;
538                   goto out;
539                 }
540               b->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
541               next = NAT44_ED_OUT2IN_NEXT_DROP;
542               goto out;
543             }
544           else
545             {
546               dont_translate = 1;
547               if (next_src_nat (sm, ip, key.proto, key.l_port, key.r_port,
548                                 thread_index, rx_fib_index))
549                 {
550                   next = NAT44_ED_OUT2IN_NEXT_IN2OUT;
551                   goto out;
552                 }
553               create_bypass_for_fwd (sm, ip, rx_fib_index, thread_index);
554               goto out;
555             }
556         }
557
558       if (PREDICT_FALSE (icmp->type != ICMP4_echo_reply &&
559                          (icmp->type != ICMP4_echo_request || !is_addr_only)))
560         {
561           b->error = node->errors[NAT_OUT2IN_ED_ERROR_BAD_ICMP_TYPE];
562           next = NAT44_ED_OUT2IN_NEXT_DROP;
563           goto out;
564         }
565
566       if (PREDICT_FALSE (identity_nat))
567         {
568           dont_translate = 1;
569           goto out;
570         }
571
572       /* Create session initiated by host from external network */
573       s = create_session_for_static_mapping_ed (sm, b, l_key, e_key, node,
574                                                 thread_index, 0, 0,
575                                                 vlib_time_now
576                                                 (sm->vlib_main));
577
578       if (!s)
579         {
580           next = NAT44_ED_OUT2IN_NEXT_DROP;
581           goto out;
582         }
583     }
584   else
585     {
586       if (PREDICT_FALSE (icmp->type != ICMP4_echo_reply &&
587                          icmp->type != ICMP4_echo_request &&
588                          !icmp_is_error_message (icmp)))
589         {
590           b->error = node->errors[NAT_OUT2IN_ED_ERROR_BAD_ICMP_TYPE];
591           next = NAT44_ED_OUT2IN_NEXT_DROP;
592           goto out;
593         }
594
595       s = pool_elt_at_index (tsm->sessions, value.value);
596     }
597
598   *p_proto = ip_proto_to_snat_proto (key.proto);
599 out:
600   if (s)
601     *p_value = s->in2out;
602   *p_dont_translate = dont_translate;
603   if (d)
604     *(snat_session_t **) d = s;
605   return next;
606 }
607 #endif
608
609 static snat_session_t *
610 nat44_ed_out2in_unknown_proto (snat_main_t * sm,
611                                vlib_buffer_t * b,
612                                ip4_header_t * ip,
613                                u32 rx_fib_index,
614                                u32 thread_index,
615                                f64 now,
616                                vlib_main_t * vm, vlib_node_runtime_t * node)
617 {
618   clib_bihash_kv_8_8_t kv, value;
619   clib_bihash_kv_16_8_t s_kv, s_value;
620   snat_static_mapping_t *m;
621   u32 old_addr, new_addr;
622   ip_csum_t sum;
623   snat_session_t *s;
624   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
625   snat_user_t *u;
626
627   old_addr = ip->dst_address.as_u32;
628
629   make_ed_kv (&s_kv, &ip->dst_address, &ip->src_address, ip->protocol,
630               rx_fib_index, 0, 0);
631
632   if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
633     {
634       s = pool_elt_at_index (tsm->sessions, s_value.value);
635       new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
636     }
637   else
638     {
639       if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
640         {
641           b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
642           nat_log_notice ("maximum sessions exceeded");
643           return 0;
644         }
645
646       make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
647       if (clib_bihash_search_8_8
648           (&sm->static_mapping_by_external, &kv, &value))
649         {
650           b->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
651           return 0;
652         }
653
654       m = pool_elt_at_index (sm->static_mappings, value.value);
655
656       new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
657
658       u = nat_user_get_or_create (sm, &m->local_addr, m->fib_index,
659                                   thread_index);
660       if (!u)
661         {
662           nat_log_warn ("create NAT user failed");
663           return 0;
664         }
665
666       /* Create a new session */
667       s = nat_ed_session_alloc (sm, u, thread_index, now);
668       if (!s)
669         {
670           nat44_delete_user_with_no_session (sm, u, thread_index);
671           nat_log_warn ("create NAT session failed");
672           return 0;
673         }
674
675       s->ext_host_addr.as_u32 = ip->src_address.as_u32;
676       s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
677       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
678       s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
679       s->out2in.addr.as_u32 = old_addr;
680       s->out2in.fib_index = rx_fib_index;
681       s->in2out.addr.as_u32 = new_addr;
682       s->in2out.fib_index = m->fib_index;
683       s->in2out.port = s->out2in.port = ip->protocol;
684       user_session_increment (sm, u, 1);
685
686       /* Add to lookup tables */
687       s_kv.value = s - tsm->sessions;
688       if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1))
689         nat_log_notice ("out2in key add failed");
690
691       make_ed_kv (&s_kv, &ip->dst_address, &ip->src_address, ip->protocol,
692                   m->fib_index, 0, 0);
693       s_kv.value = s - tsm->sessions;
694       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
695         nat_log_notice ("in2out key add failed");
696     }
697
698   /* Update IP checksum */
699   sum = ip->checksum;
700   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
701   ip->checksum = ip_csum_fold (sum);
702
703   vnet_buffer (b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
704
705   /* Accounting */
706   nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b));
707   /* Per-user LRU list maintenance */
708   nat44_session_update_lru (sm, s, thread_index);
709
710   return s;
711 }
712
713 static inline uword
714 nat44_ed_out2in_node_fn_inline (vlib_main_t * vm,
715                                 vlib_node_runtime_t * node,
716                                 vlib_frame_t * frame, int is_slow_path)
717 {
718   u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
719   nat44_ed_out2in_next_t next_index;
720   snat_main_t *sm = &snat_main;
721   f64 now = vlib_time_now (vm);
722   u32 thread_index = vm->thread_index;
723   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
724   u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
725     0, fragments = 0;
726
727   stats_node_index = is_slow_path ? sm->ed_out2in_slowpath_node_index :
728     sm->ed_out2in_node_index;
729
730   from = vlib_frame_vector_args (frame);
731   n_left_from = frame->n_vectors;
732   next_index = node->cached_next_index;
733
734   while (n_left_from > 0)
735     {
736       u32 n_left_to_next;
737
738       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
739
740       while (n_left_from >= 4 && n_left_to_next >= 2)
741         {
742           u32 bi0, bi1;
743           vlib_buffer_t *b0, *b1;
744           u32 next0, sw_if_index0, rx_fib_index0, proto0, old_addr0,
745             new_addr0;
746           u32 next1, sw_if_index1, rx_fib_index1, proto1, old_addr1,
747             new_addr1;
748           u16 old_port0, new_port0, old_port1, new_port1;
749           ip4_header_t *ip0, *ip1;
750           udp_header_t *udp0, *udp1;
751           tcp_header_t *tcp0, *tcp1;
752           icmp46_header_t *icmp0, *icmp1;
753           snat_session_t *s0 = 0, *s1 = 0;
754           clib_bihash_kv_16_8_t kv0, value0, kv1, value1;
755           ip_csum_t sum0, sum1;
756           snat_session_key_t e_key0, l_key0, e_key1, l_key1;
757           lb_nat_type_t lb_nat0, lb_nat1;
758           twice_nat_type_t twice_nat0, twice_nat1;
759           u8 identity_nat0, identity_nat1;
760
761           /* Prefetch next iteration. */
762           {
763             vlib_buffer_t *p2, *p3;
764
765             p2 = vlib_get_buffer (vm, from[2]);
766             p3 = vlib_get_buffer (vm, from[3]);
767
768             vlib_prefetch_buffer_header (p2, LOAD);
769             vlib_prefetch_buffer_header (p3, LOAD);
770
771             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
772             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
773           }
774
775           /* speculatively enqueue b0 and b1 to the current next frame */
776           to_next[0] = bi0 = from[0];
777           to_next[1] = bi1 = from[1];
778           from += 2;
779           to_next += 2;
780           n_left_from -= 2;
781           n_left_to_next -= 2;
782
783           b0 = vlib_get_buffer (vm, bi0);
784           b1 = vlib_get_buffer (vm, bi1);
785
786           next0 = NAT44_ED_OUT2IN_NEXT_LOOKUP;
787           vnet_buffer (b0)->snat.flags = 0;
788           ip0 = vlib_buffer_get_current (b0);
789
790           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
791           rx_fib_index0 =
792             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
793                                                  sw_if_index0);
794
795           if (PREDICT_FALSE (ip0->ttl == 1))
796             {
797               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
798               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
799                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
800                                            0);
801               next0 = NAT44_ED_OUT2IN_NEXT_ICMP_ERROR;
802               goto trace00;
803             }
804
805           udp0 = ip4_next_header (ip0);
806           tcp0 = (tcp_header_t *) udp0;
807           icmp0 = (icmp46_header_t *) udp0;
808           proto0 = ip_proto_to_snat_proto (ip0->protocol);
809
810           if (is_slow_path)
811             {
812               if (PREDICT_FALSE (proto0 == ~0))
813                 {
814                   s0 =
815                     nat44_ed_out2in_unknown_proto (sm, b0, ip0, rx_fib_index0,
816                                                    thread_index, now, vm,
817                                                    node);
818                   other_packets++;
819                   if (!sm->forwarding_enabled)
820                     {
821                       if (!s0)
822                         next0 = NAT44_ED_OUT2IN_NEXT_DROP;
823                       goto trace00;
824                     }
825                 }
826
827               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
828                 {
829                   next0 = icmp_out2in_ed_slow_path
830                     (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
831                      next0, now, thread_index, &s0);
832                   icmp_packets++;
833                   goto trace00;
834                 }
835             }
836           else
837             {
838               if (PREDICT_FALSE (proto0 == ~0))
839                 {
840                   next0 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
841                   goto trace00;
842                 }
843
844               if (ip4_is_fragment (ip0))
845                 {
846                   next0 = NAT44_ED_OUT2IN_NEXT_REASS;
847                   fragments++;
848                   goto trace00;
849                 }
850
851               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
852                 {
853                   next0 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
854                   goto trace00;
855                 }
856             }
857
858           make_ed_kv (&kv0, &ip0->dst_address, &ip0->src_address,
859                       ip0->protocol, rx_fib_index0, udp0->dst_port,
860                       udp0->src_port);
861
862           if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
863             {
864               if (is_slow_path)
865                 {
866                   /* Try to match static mapping by external address and port,
867                      destination address and port in packet */
868                   e_key0.addr = ip0->dst_address;
869                   e_key0.port = udp0->dst_port;
870                   e_key0.protocol = proto0;
871                   e_key0.fib_index = rx_fib_index0;
872                   if (snat_static_mapping_match (sm, e_key0, &l_key0, 1, 0,
873                                                  &twice_nat0, &lb_nat0,
874                                                  &ip0->src_address,
875                                                  &identity_nat0))
876                     {
877                       /*
878                        * Send DHCP packets to the ipv4 stack, or we won't
879                        * be able to use dhcp client on the outside interface
880                        */
881                       if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
882                                          && (udp0->dst_port ==
883                                              clib_host_to_net_u16
884                                              (UDP_DST_PORT_dhcp_to_client))))
885                         {
886                           vnet_feature_next (&next0, b0);
887                           goto trace00;
888                         }
889
890                       if (!sm->forwarding_enabled)
891                         {
892                           b0->error =
893                             node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
894                           next0 = NAT44_ED_OUT2IN_NEXT_DROP;
895                         }
896                       else
897                         {
898                           if (next_src_nat (sm, ip0, ip0->protocol,
899                                             udp0->src_port, udp0->dst_port,
900                                             thread_index, rx_fib_index0))
901                             {
902                               next0 = NAT44_ED_OUT2IN_NEXT_IN2OUT;
903                               goto trace00;
904                             }
905                           create_bypass_for_fwd (sm, ip0, rx_fib_index0,
906                                                  thread_index);
907                         }
908                       goto trace00;
909                     }
910
911                   if (PREDICT_FALSE (identity_nat0))
912                     goto trace00;
913
914                   if ((proto0 == SNAT_PROTOCOL_TCP) && !tcp_is_init (tcp0))
915                     {
916                       b0->error = node->errors[NAT_OUT2IN_ED_ERROR_NON_SYN];
917                       next0 = NAT44_ED_OUT2IN_NEXT_DROP;
918                       goto trace00;
919                     }
920
921                   /* Create session initiated by host from external network */
922                   s0 = create_session_for_static_mapping_ed (sm, b0, l_key0,
923                                                              e_key0, node,
924                                                              thread_index,
925                                                              twice_nat0,
926                                                              lb_nat0, now);
927
928                   if (!s0)
929                     {
930                       next0 = NAT44_ED_OUT2IN_NEXT_DROP;
931                       goto trace00;
932                     }
933                 }
934               else
935                 {
936                   next0 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
937                   goto trace00;
938                 }
939             }
940           else
941             {
942               s0 = pool_elt_at_index (tsm->sessions, value0.value);
943             }
944
945           old_addr0 = ip0->dst_address.as_u32;
946           new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
947           vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
948
949           sum0 = ip0->checksum;
950           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
951                                  dst_address);
952           if (PREDICT_FALSE (is_twice_nat_session (s0)))
953             sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
954                                    s0->ext_host_nat_addr.as_u32, ip4_header_t,
955                                    src_address);
956           ip0->checksum = ip_csum_fold (sum0);
957
958           if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
959             {
960               old_port0 = tcp0->dst_port;
961               new_port0 = tcp0->dst_port = s0->in2out.port;
962
963               sum0 = tcp0->checksum;
964               sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
965                                      dst_address);
966               sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
967                                      length);
968               if (is_twice_nat_session (s0))
969                 {
970                   sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
971                                          s0->ext_host_nat_addr.as_u32,
972                                          ip4_header_t, dst_address);
973                   sum0 = ip_csum_update (sum0, tcp0->src_port,
974                                          s0->ext_host_nat_port, ip4_header_t,
975                                          length);
976                   tcp0->src_port = s0->ext_host_nat_port;
977                   ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
978                 }
979               tcp0->checksum = ip_csum_fold (sum0);
980               tcp_packets++;
981               if (nat44_set_tcp_session_state_o2i
982                   (sm, s0, tcp0, thread_index))
983                 goto trace00;
984             }
985           else
986             {
987               udp0->dst_port = s0->in2out.port;
988               if (is_twice_nat_session (s0))
989                 {
990                   udp0->src_port = s0->ext_host_nat_port;
991                   ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
992                 }
993               udp0->checksum = 0;
994               udp_packets++;
995             }
996
997           /* Accounting */
998           nat44_session_update_counters (s0, now,
999                                          vlib_buffer_length_in_chain (vm,
1000                                                                       b0));
1001           /* Per-user LRU list maintenance */
1002           nat44_session_update_lru (sm, s0, thread_index);
1003
1004         trace00:
1005           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1006                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1007             {
1008               nat44_ed_out2in_trace_t *t =
1009                 vlib_add_trace (vm, node, b0, sizeof (*t));
1010               t->is_slow_path = is_slow_path;
1011               t->sw_if_index = sw_if_index0;
1012               t->next_index = next0;
1013               t->session_index = ~0;
1014               if (s0)
1015                 t->session_index = s0 - tsm->sessions;
1016             }
1017
1018           pkts_processed += next0 == NAT44_ED_OUT2IN_NEXT_LOOKUP;
1019
1020           next1 = NAT44_ED_OUT2IN_NEXT_LOOKUP;
1021           vnet_buffer (b1)->snat.flags = 0;
1022           ip1 = vlib_buffer_get_current (b1);
1023
1024           sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1025           rx_fib_index1 =
1026             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1027                                                  sw_if_index1);
1028
1029           if (PREDICT_FALSE (ip1->ttl == 1))
1030             {
1031               vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1032               icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1033                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1034                                            0);
1035               next1 = NAT44_ED_OUT2IN_NEXT_ICMP_ERROR;
1036               goto trace01;
1037             }
1038
1039           udp1 = ip4_next_header (ip1);
1040           tcp1 = (tcp_header_t *) udp1;
1041           icmp1 = (icmp46_header_t *) udp1;
1042           proto1 = ip_proto_to_snat_proto (ip1->protocol);
1043
1044           if (is_slow_path)
1045             {
1046               if (PREDICT_FALSE (proto1 == ~0))
1047                 {
1048                   s1 =
1049                     nat44_ed_out2in_unknown_proto (sm, b1, ip1, rx_fib_index1,
1050                                                    thread_index, now, vm,
1051                                                    node);
1052                   other_packets++;
1053                   if (!sm->forwarding_enabled)
1054                     {
1055                       if (!s1)
1056                         next1 = NAT44_ED_OUT2IN_NEXT_DROP;
1057                       goto trace01;
1058                     }
1059                 }
1060
1061               if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1062                 {
1063                   next1 = icmp_out2in_ed_slow_path
1064                     (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1065                      next1, now, thread_index, &s1);
1066                   icmp_packets++;
1067                   goto trace01;
1068                 }
1069             }
1070           else
1071             {
1072               if (PREDICT_FALSE (proto1 == ~0))
1073                 {
1074                   next1 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
1075                   goto trace01;
1076                 }
1077
1078               if (ip4_is_fragment (ip1))
1079                 {
1080                   next1 = NAT44_ED_OUT2IN_NEXT_REASS;
1081                   fragments++;
1082                   goto trace01;
1083                 }
1084
1085               if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1086                 {
1087                   next1 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
1088                   goto trace01;
1089                 }
1090             }
1091
1092           make_ed_kv (&kv1, &ip1->dst_address, &ip1->src_address,
1093                       ip1->protocol, rx_fib_index1, udp1->dst_port,
1094                       udp1->src_port);
1095
1096           if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv1, &value1))
1097             {
1098               if (is_slow_path)
1099                 {
1100                   /* Try to match static mapping by external address and port,
1101                      destination address and port in packet */
1102                   e_key1.addr = ip1->dst_address;
1103                   e_key1.port = udp1->dst_port;
1104                   e_key1.protocol = proto1;
1105                   e_key1.fib_index = rx_fib_index1;
1106                   if (snat_static_mapping_match (sm, e_key1, &l_key1, 1, 0,
1107                                                  &twice_nat1, &lb_nat1,
1108                                                  &ip1->src_address,
1109                                                  &identity_nat1))
1110                     {
1111                       /*
1112                        * Send DHCP packets to the ipv4 stack, or we won't
1113                        * be able to use dhcp client on the outside interface
1114                        */
1115                       if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_UDP
1116                                          && (udp1->dst_port ==
1117                                              clib_host_to_net_u16
1118                                              (UDP_DST_PORT_dhcp_to_client))))
1119                         {
1120                           vnet_feature_next (&next1, b1);
1121                           goto trace01;
1122                         }
1123
1124                       if (!sm->forwarding_enabled)
1125                         {
1126                           b1->error =
1127                             node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
1128                           next1 = NAT44_ED_OUT2IN_NEXT_DROP;
1129                         }
1130                       else
1131                         {
1132                           if (next_src_nat (sm, ip1, ip1->protocol,
1133                                             udp1->src_port, udp1->dst_port,
1134                                             thread_index, rx_fib_index1))
1135                             {
1136                               next1 = NAT44_ED_OUT2IN_NEXT_IN2OUT;
1137                               goto trace01;
1138                             }
1139                           create_bypass_for_fwd (sm, ip1, rx_fib_index1,
1140                                                  thread_index);
1141                         }
1142                       goto trace01;
1143                     }
1144
1145                   if (PREDICT_FALSE (identity_nat1))
1146                     goto trace01;
1147
1148                   if ((proto1 == SNAT_PROTOCOL_TCP) && !tcp_is_init (tcp1))
1149                     {
1150                       b1->error = node->errors[NAT_OUT2IN_ED_ERROR_NON_SYN];
1151                       next1 = NAT44_ED_OUT2IN_NEXT_DROP;
1152                       goto trace01;
1153                     }
1154
1155                   /* Create session initiated by host from external network */
1156                   s1 = create_session_for_static_mapping_ed (sm, b1, l_key1,
1157                                                              e_key1, node,
1158                                                              thread_index,
1159                                                              twice_nat1,
1160                                                              lb_nat1, now);
1161
1162                   if (!s1)
1163                     {
1164                       next1 = NAT44_ED_OUT2IN_NEXT_DROP;
1165                       goto trace01;
1166                     }
1167                 }
1168               else
1169                 {
1170                   next1 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
1171                   goto trace01;
1172                 }
1173             }
1174           else
1175             {
1176               s1 = pool_elt_at_index (tsm->sessions, value1.value);
1177             }
1178
1179           old_addr1 = ip1->dst_address.as_u32;
1180           new_addr1 = ip1->dst_address.as_u32 = s1->in2out.addr.as_u32;
1181           vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1182
1183           sum1 = ip1->checksum;
1184           sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
1185                                  dst_address);
1186           if (PREDICT_FALSE (is_twice_nat_session (s1)))
1187             sum1 = ip_csum_update (sum1, ip1->src_address.as_u32,
1188                                    s1->ext_host_nat_addr.as_u32, ip4_header_t,
1189                                    src_address);
1190           ip1->checksum = ip_csum_fold (sum1);
1191
1192           if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
1193             {
1194               old_port1 = tcp1->dst_port;
1195               new_port1 = tcp1->dst_port = s1->in2out.port;
1196
1197               sum1 = tcp1->checksum;
1198               sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
1199                                      dst_address);
1200               sum1 = ip_csum_update (sum1, old_port1, new_port1, ip4_header_t,
1201                                      length);
1202               if (is_twice_nat_session (s1))
1203                 {
1204                   sum1 = ip_csum_update (sum1, ip1->src_address.as_u32,
1205                                          s1->ext_host_nat_addr.as_u32,
1206                                          ip4_header_t, dst_address);
1207                   sum1 = ip_csum_update (sum1, tcp1->src_port,
1208                                          s1->ext_host_nat_port, ip4_header_t,
1209                                          length);
1210                   tcp1->src_port = s1->ext_host_nat_port;
1211                   ip1->src_address.as_u32 = s1->ext_host_nat_addr.as_u32;
1212                 }
1213               tcp1->checksum = ip_csum_fold (sum1);
1214               tcp_packets++;
1215               if (nat44_set_tcp_session_state_o2i
1216                   (sm, s1, tcp1, thread_index))
1217                 goto trace01;
1218             }
1219           else
1220             {
1221               udp1->dst_port = s1->in2out.port;
1222               if (is_twice_nat_session (s1))
1223                 {
1224                   udp1->src_port = s1->ext_host_nat_port;
1225                   ip1->src_address.as_u32 = s1->ext_host_nat_addr.as_u32;
1226                 }
1227               udp1->checksum = 0;
1228               udp_packets++;
1229             }
1230
1231           /* Accounting */
1232           nat44_session_update_counters (s1, now,
1233                                          vlib_buffer_length_in_chain (vm,
1234                                                                       b1));
1235           /* Per-user LRU list maintenance */
1236           nat44_session_update_lru (sm, s1, thread_index);
1237
1238         trace01:
1239           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1240                              && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1241             {
1242               nat44_ed_out2in_trace_t *t =
1243                 vlib_add_trace (vm, node, b1, sizeof (*t));
1244               t->is_slow_path = is_slow_path;
1245               t->sw_if_index = sw_if_index1;
1246               t->next_index = next1;
1247               t->session_index = ~0;
1248               if (s1)
1249                 t->session_index = s1 - tsm->sessions;
1250             }
1251
1252           pkts_processed += next1 == NAT44_ED_OUT2IN_NEXT_LOOKUP;
1253
1254           /* verify speculative enqueues, maybe switch current next frame */
1255           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1256                                            to_next, n_left_to_next,
1257                                            bi0, bi1, next0, next1);
1258         }
1259
1260       while (n_left_from > 0 && n_left_to_next > 0)
1261         {
1262           u32 bi0;
1263           vlib_buffer_t *b0;
1264           u32 next0, sw_if_index0, rx_fib_index0, proto0, old_addr0,
1265             new_addr0;
1266           u16 old_port0, new_port0;
1267           ip4_header_t *ip0;
1268           udp_header_t *udp0;
1269           tcp_header_t *tcp0;
1270           icmp46_header_t *icmp0;
1271           snat_session_t *s0 = 0;
1272           clib_bihash_kv_16_8_t kv0, value0;
1273           ip_csum_t sum0;
1274           snat_session_key_t e_key0, l_key0;
1275           lb_nat_type_t lb_nat0;
1276           twice_nat_type_t twice_nat0;
1277           u8 identity_nat0;
1278
1279           /* speculatively enqueue b0 to the current next frame */
1280           bi0 = from[0];
1281           to_next[0] = bi0;
1282           from += 1;
1283           to_next += 1;
1284           n_left_from -= 1;
1285           n_left_to_next -= 1;
1286
1287           b0 = vlib_get_buffer (vm, bi0);
1288           next0 = NAT44_ED_OUT2IN_NEXT_LOOKUP;
1289           vnet_buffer (b0)->snat.flags = 0;
1290           ip0 = vlib_buffer_get_current (b0);
1291
1292           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1293           rx_fib_index0 =
1294             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1295                                                  sw_if_index0);
1296
1297           if (PREDICT_FALSE (ip0->ttl == 1))
1298             {
1299               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1300               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1301                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1302                                            0);
1303               next0 = NAT44_ED_OUT2IN_NEXT_ICMP_ERROR;
1304               goto trace0;
1305             }
1306
1307           udp0 = ip4_next_header (ip0);
1308           tcp0 = (tcp_header_t *) udp0;
1309           icmp0 = (icmp46_header_t *) udp0;
1310           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1311
1312           if (is_slow_path)
1313             {
1314               if (PREDICT_FALSE (proto0 == ~0))
1315                 {
1316                   s0 =
1317                     nat44_ed_out2in_unknown_proto (sm, b0, ip0, rx_fib_index0,
1318                                                    thread_index, now, vm,
1319                                                    node);
1320                   other_packets++;
1321                   if (!sm->forwarding_enabled)
1322                     {
1323                       if (!s0)
1324                         next0 = NAT44_ED_OUT2IN_NEXT_DROP;
1325                       goto trace0;
1326                     }
1327                 }
1328
1329               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1330                 {
1331                   next0 = icmp_out2in_ed_slow_path
1332                     (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1333                      next0, now, thread_index, &s0);
1334                   icmp_packets++;
1335                   goto trace0;
1336                 }
1337             }
1338           else
1339             {
1340               if (PREDICT_FALSE (proto0 == ~0))
1341                 {
1342                   next0 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
1343                   goto trace0;
1344                 }
1345
1346               if (ip4_is_fragment (ip0))
1347                 {
1348                   next0 = NAT44_ED_OUT2IN_NEXT_REASS;
1349                   fragments++;
1350                   goto trace0;
1351                 }
1352
1353               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1354                 {
1355                   next0 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
1356                   goto trace0;
1357                 }
1358             }
1359
1360           make_ed_kv (&kv0, &ip0->dst_address, &ip0->src_address,
1361                       ip0->protocol, rx_fib_index0, udp0->dst_port,
1362                       udp0->src_port);
1363
1364           if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
1365             {
1366               if (is_slow_path)
1367                 {
1368                   /* Try to match static mapping by external address and port,
1369                      destination address and port in packet */
1370                   e_key0.addr = ip0->dst_address;
1371                   e_key0.port = udp0->dst_port;
1372                   e_key0.protocol = proto0;
1373                   e_key0.fib_index = rx_fib_index0;
1374                   if (snat_static_mapping_match (sm, e_key0, &l_key0, 1, 0,
1375                                                  &twice_nat0, &lb_nat0,
1376                                                  &ip0->src_address,
1377                                                  &identity_nat0))
1378                     {
1379                       /*
1380                        * Send DHCP packets to the ipv4 stack, or we won't
1381                        * be able to use dhcp client on the outside interface
1382                        */
1383                       if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1384                                          && (udp0->dst_port ==
1385                                              clib_host_to_net_u16
1386                                              (UDP_DST_PORT_dhcp_to_client))))
1387                         {
1388                           vnet_feature_next (&next0, b0);
1389                           goto trace0;
1390                         }
1391
1392                       if (!sm->forwarding_enabled)
1393                         {
1394                           b0->error =
1395                             node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
1396                           next0 = NAT44_ED_OUT2IN_NEXT_DROP;
1397                         }
1398                       else
1399                         {
1400                           if (next_src_nat (sm, ip0, ip0->protocol,
1401                                             udp0->src_port, udp0->dst_port,
1402                                             thread_index, rx_fib_index0))
1403                             {
1404                               next0 = NAT44_ED_OUT2IN_NEXT_IN2OUT;
1405                               goto trace0;
1406                             }
1407                           create_bypass_for_fwd (sm, ip0, rx_fib_index0,
1408                                                  thread_index);
1409                         }
1410                       goto trace0;
1411                     }
1412
1413                   if (PREDICT_FALSE (identity_nat0))
1414                     goto trace0;
1415
1416                   if ((proto0 == SNAT_PROTOCOL_TCP) && !tcp_is_init (tcp0))
1417                     {
1418                       b0->error = node->errors[NAT_OUT2IN_ED_ERROR_NON_SYN];
1419                       next0 = NAT44_ED_OUT2IN_NEXT_DROP;
1420                       goto trace0;
1421                     }
1422
1423                   /* Create session initiated by host from external network */
1424                   s0 = create_session_for_static_mapping_ed (sm, b0, l_key0,
1425                                                              e_key0, node,
1426                                                              thread_index,
1427                                                              twice_nat0,
1428                                                              lb_nat0, now);
1429
1430                   if (!s0)
1431                     {
1432                       next0 = NAT44_ED_OUT2IN_NEXT_DROP;
1433                       goto trace0;
1434                     }
1435                 }
1436               else
1437                 {
1438                   next0 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
1439                   goto trace0;
1440                 }
1441             }
1442           else
1443             {
1444               s0 = pool_elt_at_index (tsm->sessions, value0.value);
1445             }
1446
1447           old_addr0 = ip0->dst_address.as_u32;
1448           new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
1449           vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1450
1451           sum0 = ip0->checksum;
1452           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1453                                  dst_address);
1454           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1455             sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
1456                                    s0->ext_host_nat_addr.as_u32, ip4_header_t,
1457                                    src_address);
1458           ip0->checksum = ip_csum_fold (sum0);
1459
1460           if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1461             {
1462               old_port0 = tcp0->dst_port;
1463               new_port0 = tcp0->dst_port = s0->in2out.port;
1464
1465               sum0 = tcp0->checksum;
1466               sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1467                                      dst_address);
1468               sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1469                                      length);
1470               if (is_twice_nat_session (s0))
1471                 {
1472                   sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
1473                                          s0->ext_host_nat_addr.as_u32,
1474                                          ip4_header_t, dst_address);
1475                   sum0 = ip_csum_update (sum0, tcp0->src_port,
1476                                          s0->ext_host_nat_port, ip4_header_t,
1477                                          length);
1478                   tcp0->src_port = s0->ext_host_nat_port;
1479                   ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
1480                 }
1481               tcp0->checksum = ip_csum_fold (sum0);
1482               tcp_packets++;
1483               if (nat44_set_tcp_session_state_o2i
1484                   (sm, s0, tcp0, thread_index))
1485                 goto trace0;
1486             }
1487           else
1488             {
1489               udp0->dst_port = s0->in2out.port;
1490               if (is_twice_nat_session (s0))
1491                 {
1492                   udp0->src_port = s0->ext_host_nat_port;
1493                   ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
1494                 }
1495               udp0->checksum = 0;
1496               udp_packets++;
1497             }
1498
1499           /* Accounting */
1500           nat44_session_update_counters (s0, now,
1501                                          vlib_buffer_length_in_chain (vm,
1502                                                                       b0));
1503           /* Per-user LRU list maintenance */
1504           nat44_session_update_lru (sm, s0, thread_index);
1505
1506         trace0:
1507           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1508                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1509             {
1510               nat44_ed_out2in_trace_t *t =
1511                 vlib_add_trace (vm, node, b0, sizeof (*t));
1512               t->is_slow_path = is_slow_path;
1513               t->sw_if_index = sw_if_index0;
1514               t->next_index = next0;
1515               t->session_index = ~0;
1516               if (s0)
1517                 t->session_index = s0 - tsm->sessions;
1518             }
1519
1520           pkts_processed += next0 == NAT44_ED_OUT2IN_NEXT_LOOKUP;
1521           /* verify speculative enqueue, maybe switch current next frame */
1522           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1523                                            to_next, n_left_to_next,
1524                                            bi0, next0);
1525         }
1526
1527       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1528     }
1529
1530   vlib_node_increment_counter (vm, stats_node_index,
1531                                NAT_OUT2IN_ED_ERROR_OUT2IN_PACKETS,
1532                                pkts_processed);
1533   vlib_node_increment_counter (vm, stats_node_index,
1534                                NAT_OUT2IN_ED_ERROR_TCP_PACKETS, tcp_packets);
1535   vlib_node_increment_counter (vm, stats_node_index,
1536                                NAT_OUT2IN_ED_ERROR_UDP_PACKETS, udp_packets);
1537   vlib_node_increment_counter (vm, stats_node_index,
1538                                NAT_OUT2IN_ED_ERROR_ICMP_PACKETS,
1539                                icmp_packets);
1540   vlib_node_increment_counter (vm, stats_node_index,
1541                                NAT_OUT2IN_ED_ERROR_OTHER_PACKETS,
1542                                other_packets);
1543   vlib_node_increment_counter (vm, stats_node_index,
1544                                NAT_OUT2IN_ED_ERROR_FRAGMENTS, fragments);
1545   return frame->n_vectors;
1546 }
1547
1548 VLIB_NODE_FN (nat44_ed_out2in_node) (vlib_main_t * vm,
1549                                      vlib_node_runtime_t * node,
1550                                      vlib_frame_t * frame)
1551 {
1552   return nat44_ed_out2in_node_fn_inline (vm, node, frame, 0);
1553 }
1554
1555 /* *INDENT-OFF* */
1556 VLIB_REGISTER_NODE (nat44_ed_out2in_node) = {
1557   .name = "nat44-ed-out2in",
1558   .vector_size = sizeof (u32),
1559   .format_trace = format_nat44_ed_out2in_trace,
1560   .type = VLIB_NODE_TYPE_INTERNAL,
1561   .n_errors = ARRAY_LEN(nat_out2in_ed_error_strings),
1562   .error_strings = nat_out2in_ed_error_strings,
1563   .runtime_data_bytes = sizeof (snat_runtime_t),
1564   .n_next_nodes = NAT44_ED_OUT2IN_N_NEXT,
1565   .next_nodes = {
1566     [NAT44_ED_OUT2IN_NEXT_DROP] = "error-drop",
1567     [NAT44_ED_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1568     [NAT44_ED_OUT2IN_NEXT_SLOW_PATH] = "nat44-ed-out2in-slowpath",
1569     [NAT44_ED_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1570     [NAT44_ED_OUT2IN_NEXT_IN2OUT] = "nat44-ed-in2out",
1571     [NAT44_ED_OUT2IN_NEXT_REASS] = "nat44-ed-out2in-reass",
1572   },
1573 };
1574 /* *INDENT-ON* */
1575
1576 VLIB_NODE_FN (nat44_ed_out2in_slowpath_node) (vlib_main_t * vm,
1577                                               vlib_node_runtime_t * node,
1578                                               vlib_frame_t * frame)
1579 {
1580   return nat44_ed_out2in_node_fn_inline (vm, node, frame, 1);
1581 }
1582
1583 /* *INDENT-OFF* */
1584 VLIB_REGISTER_NODE (nat44_ed_out2in_slowpath_node) = {
1585   .name = "nat44-ed-out2in-slowpath",
1586   .vector_size = sizeof (u32),
1587   .format_trace = format_nat44_ed_out2in_trace,
1588   .type = VLIB_NODE_TYPE_INTERNAL,
1589   .n_errors = ARRAY_LEN(nat_out2in_ed_error_strings),
1590   .error_strings = nat_out2in_ed_error_strings,
1591   .runtime_data_bytes = sizeof (snat_runtime_t),
1592   .n_next_nodes = NAT44_ED_OUT2IN_N_NEXT,
1593   .next_nodes = {
1594     [NAT44_ED_OUT2IN_NEXT_DROP] = "error-drop",
1595     [NAT44_ED_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1596     [NAT44_ED_OUT2IN_NEXT_SLOW_PATH] = "nat44-ed-out2in-slowpath",
1597     [NAT44_ED_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1598     [NAT44_ED_OUT2IN_NEXT_IN2OUT] = "nat44-ed-in2out",
1599     [NAT44_ED_OUT2IN_NEXT_REASS] = "nat44-ed-out2in-reass",
1600   },
1601 };
1602 /* *INDENT-ON* */
1603
1604 VLIB_NODE_FN (nat44_ed_out2in_reass_node) (vlib_main_t * vm,
1605                                            vlib_node_runtime_t * node,
1606                                            vlib_frame_t * frame)
1607 {
1608   u32 n_left_from, *from, *to_next;
1609   nat44_ed_out2in_next_t next_index;
1610   u32 pkts_processed = 0;
1611   snat_main_t *sm = &snat_main;
1612   f64 now = vlib_time_now (vm);
1613   u32 thread_index = vm->thread_index;
1614   snat_main_per_thread_data_t *per_thread_data =
1615     &sm->per_thread_data[thread_index];
1616   u32 *fragments_to_drop = 0;
1617   u32 *fragments_to_loopback = 0;
1618
1619   from = vlib_frame_vector_args (frame);
1620   n_left_from = frame->n_vectors;
1621   next_index = node->cached_next_index;
1622
1623   while (n_left_from > 0)
1624     {
1625       u32 n_left_to_next;
1626
1627       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1628
1629       while (n_left_from > 0 && n_left_to_next > 0)
1630         {
1631           u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1632           vlib_buffer_t *b0;
1633           u32 next0;
1634           u8 cached0 = 0;
1635           ip4_header_t *ip0;
1636           nat_reass_ip4_t *reass0;
1637           udp_header_t *udp0;
1638           tcp_header_t *tcp0;
1639           icmp46_header_t *icmp0;
1640           clib_bihash_kv_16_8_t kv0, value0;
1641           snat_session_t *s0 = 0;
1642           u16 old_port0, new_port0;
1643           ip_csum_t sum0;
1644           snat_session_key_t e_key0, l_key0;
1645           lb_nat_type_t lb0;
1646           twice_nat_type_t twice_nat0;
1647           u8 identity_nat0;
1648
1649           /* speculatively enqueue b0 to the current next frame */
1650           bi0 = from[0];
1651           to_next[0] = bi0;
1652           from += 1;
1653           to_next += 1;
1654           n_left_from -= 1;
1655           n_left_to_next -= 1;
1656
1657           b0 = vlib_get_buffer (vm, bi0);
1658           next0 = NAT44_ED_OUT2IN_NEXT_LOOKUP;
1659
1660           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1661           rx_fib_index0 =
1662             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1663                                                  sw_if_index0);
1664
1665           if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
1666             {
1667               next0 = NAT44_ED_OUT2IN_NEXT_DROP;
1668               b0->error = node->errors[NAT_OUT2IN_ED_ERROR_DROP_FRAGMENT];
1669               goto trace0;
1670             }
1671
1672           ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1673           udp0 = ip4_next_header (ip0);
1674           tcp0 = (tcp_header_t *) udp0;
1675           icmp0 = (icmp46_header_t *) udp0;
1676           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1677
1678           reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1679                                                  ip0->dst_address,
1680                                                  ip0->fragment_id,
1681                                                  ip0->protocol,
1682                                                  1, &fragments_to_drop);
1683
1684           if (PREDICT_FALSE (!reass0))
1685             {
1686               next0 = NAT44_ED_OUT2IN_NEXT_DROP;
1687               b0->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_REASS];
1688               nat_log_notice ("maximum reassemblies exceeded");
1689               goto trace0;
1690             }
1691
1692           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1693             {
1694               if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1695                 {
1696                   next0 = icmp_out2in_ed_slow_path
1697                     (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1698                      next0, now, thread_index, &s0);
1699
1700                   if (PREDICT_TRUE (next0 != NAT44_ED_OUT2IN_NEXT_DROP))
1701                     {
1702                       if (s0)
1703                         reass0->sess_index = s0 - per_thread_data->sessions;
1704                       else
1705                         reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1706                       reass0->thread_index = thread_index;
1707                       nat_ip4_reass_get_frags (reass0,
1708                                                &fragments_to_loopback);
1709                     }
1710
1711                   goto trace0;
1712                 }
1713
1714               make_ed_kv (&kv0, &ip0->dst_address, &ip0->src_address,
1715                           ip0->protocol, rx_fib_index0, udp0->dst_port,
1716                           udp0->src_port);
1717
1718               if (clib_bihash_search_16_8
1719                   (&per_thread_data->out2in_ed, &kv0, &value0))
1720                 {
1721                   /* Try to match static mapping by external address and port,
1722                      destination address and port in packet */
1723                   e_key0.addr = ip0->dst_address;
1724                   e_key0.port = udp0->dst_port;
1725                   e_key0.protocol = proto0;
1726                   e_key0.fib_index = rx_fib_index0;
1727                   if (snat_static_mapping_match (sm, e_key0, &l_key0, 1, 0,
1728                                                  &twice_nat0, &lb0, 0,
1729                                                  &identity_nat0))
1730                     {
1731                       /*
1732                        * Send DHCP packets to the ipv4 stack, or we won't
1733                        * be able to use dhcp client on the outside interface
1734                        */
1735                       if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1736                                          && (udp0->dst_port
1737                                              ==
1738                                              clib_host_to_net_u16
1739                                              (UDP_DST_PORT_dhcp_to_client))))
1740                         {
1741                           vnet_feature_next (&next0, b0);
1742                           goto trace0;
1743                         }
1744
1745                       if (!sm->forwarding_enabled)
1746                         {
1747                           b0->error =
1748                             node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
1749                           next0 = NAT44_ED_OUT2IN_NEXT_DROP;
1750                         }
1751                       else
1752                         {
1753                           if (next_src_nat (sm, ip0, ip0->protocol,
1754                                             udp0->src_port, udp0->dst_port,
1755                                             thread_index, rx_fib_index0))
1756                             {
1757                               next0 = NAT44_ED_OUT2IN_NEXT_IN2OUT;
1758                               goto trace0;
1759                             }
1760                           create_bypass_for_fwd (sm, ip0, rx_fib_index0,
1761                                                  thread_index);
1762                           reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1763                           nat_ip4_reass_get_frags (reass0,
1764                                                    &fragments_to_loopback);
1765                         }
1766                       goto trace0;
1767                     }
1768
1769                   if (PREDICT_FALSE (identity_nat0))
1770                     {
1771                       reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1772                       goto trace0;
1773                     }
1774
1775                   if ((proto0 == SNAT_PROTOCOL_TCP) && !tcp_is_init (tcp0))
1776                     {
1777                       b0->error = node->errors[NAT_OUT2IN_ED_ERROR_NON_SYN];
1778                       next0 = NAT44_ED_OUT2IN_NEXT_DROP;
1779                       goto trace0;
1780                     }
1781
1782                   /* Create session initiated by host from external network */
1783                   s0 = create_session_for_static_mapping_ed (sm, b0, l_key0,
1784                                                              e_key0, node,
1785                                                              thread_index,
1786                                                              twice_nat0, lb0,
1787                                                              now);
1788                   if (!s0)
1789                     {
1790                       b0->error =
1791                         node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
1792                       next0 = NAT44_ED_OUT2IN_NEXT_DROP;
1793                       goto trace0;
1794                     }
1795                   reass0->sess_index = s0 - per_thread_data->sessions;
1796                   reass0->thread_index = thread_index;
1797                 }
1798               else
1799                 {
1800                   s0 = pool_elt_at_index (per_thread_data->sessions,
1801                                           value0.value);
1802                   reass0->sess_index = value0.value;
1803                 }
1804               nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1805             }
1806           else
1807             {
1808               if (reass0->flags & NAT_REASS_FLAG_ED_DONT_TRANSLATE)
1809                 goto trace0;
1810               if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
1811                 {
1812                   if (nat_ip4_reass_add_fragment
1813                       (thread_index, reass0, bi0, &fragments_to_drop))
1814                     {
1815                       b0->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_FRAG];
1816                       nat_log_notice
1817                         ("maximum fragments per reassembly exceeded");
1818                       next0 = NAT44_ED_OUT2IN_NEXT_DROP;
1819                       goto trace0;
1820                     }
1821                   cached0 = 1;
1822                   goto trace0;
1823                 }
1824               s0 = pool_elt_at_index (per_thread_data->sessions,
1825                                       reass0->sess_index);
1826             }
1827
1828           old_addr0 = ip0->dst_address.as_u32;
1829           ip0->dst_address = s0->in2out.addr;
1830           new_addr0 = ip0->dst_address.as_u32;
1831           vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1832
1833           sum0 = ip0->checksum;
1834           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1835                                  ip4_header_t,
1836                                  dst_address /* changed member */ );
1837           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1838             sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
1839                                    s0->ext_host_nat_addr.as_u32, ip4_header_t,
1840                                    src_address);
1841           ip0->checksum = ip_csum_fold (sum0);
1842
1843           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1844             {
1845               if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1846                 {
1847                   old_port0 = tcp0->dst_port;
1848                   tcp0->dst_port = s0->in2out.port;
1849                   new_port0 = tcp0->dst_port;
1850
1851                   sum0 = tcp0->checksum;
1852                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1853                                          ip4_header_t,
1854                                          dst_address /* changed member */ );
1855
1856                   sum0 = ip_csum_update (sum0, old_port0, new_port0,
1857                                          ip4_header_t /* cheat */ ,
1858                                          length /* changed member */ );
1859                   if (is_twice_nat_session (s0))
1860                     {
1861                       sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
1862                                              s0->ext_host_nat_addr.as_u32,
1863                                              ip4_header_t, dst_address);
1864                       sum0 = ip_csum_update (sum0, tcp0->src_port,
1865                                              s0->ext_host_nat_port,
1866                                              ip4_header_t, length);
1867                       tcp0->src_port = s0->ext_host_nat_port;
1868                       ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
1869                     }
1870                   tcp0->checksum = ip_csum_fold (sum0);
1871                 }
1872               else
1873                 {
1874                   old_port0 = udp0->dst_port;
1875                   udp0->dst_port = s0->in2out.port;
1876                   if (is_twice_nat_session (s0))
1877                     {
1878                       udp0->src_port = s0->ext_host_nat_port;
1879                       ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
1880                     }
1881                   udp0->checksum = 0;
1882                 }
1883             }
1884
1885           /* Accounting */
1886           nat44_session_update_counters (s0, now,
1887                                          vlib_buffer_length_in_chain (vm,
1888                                                                       b0));
1889           /* Per-user LRU list maintenance */
1890           nat44_session_update_lru (sm, s0, thread_index);
1891
1892         trace0:
1893           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1894                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1895             {
1896               nat44_reass_trace_t *t =
1897                 vlib_add_trace (vm, node, b0, sizeof (*t));
1898               t->cached = cached0;
1899               t->sw_if_index = sw_if_index0;
1900               t->next_index = next0;
1901             }
1902
1903           if (cached0)
1904             {
1905               n_left_to_next++;
1906               to_next--;
1907             }
1908           else
1909             {
1910               pkts_processed += next0 != NAT44_ED_OUT2IN_NEXT_DROP;
1911
1912               /* verify speculative enqueue, maybe switch current next frame */
1913               vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1914                                                to_next, n_left_to_next,
1915                                                bi0, next0);
1916             }
1917
1918           if (n_left_from == 0 && vec_len (fragments_to_loopback))
1919             {
1920               from = vlib_frame_vector_args (frame);
1921               u32 len = vec_len (fragments_to_loopback);
1922               if (len <= VLIB_FRAME_SIZE)
1923                 {
1924                   clib_memcpy_fast (from, fragments_to_loopback,
1925                                     sizeof (u32) * len);
1926                   n_left_from = len;
1927                   vec_reset_length (fragments_to_loopback);
1928                 }
1929               else
1930                 {
1931                   clib_memcpy_fast (from, fragments_to_loopback +
1932                                     (len - VLIB_FRAME_SIZE),
1933                                     sizeof (u32) * VLIB_FRAME_SIZE);
1934                   n_left_from = VLIB_FRAME_SIZE;
1935                   _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1936                 }
1937             }
1938         }
1939
1940       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1941     }
1942
1943   vlib_node_increment_counter (vm, sm->ed_out2in_reass_node_index,
1944                                NAT_OUT2IN_ED_ERROR_OUT2IN_PACKETS,
1945                                pkts_processed);
1946
1947   nat_send_all_to_node (vm, fragments_to_drop, node,
1948                         &node->errors[NAT_OUT2IN_ED_ERROR_DROP_FRAGMENT],
1949                         NAT44_ED_OUT2IN_NEXT_DROP);
1950
1951   vec_free (fragments_to_drop);
1952   vec_free (fragments_to_loopback);
1953   return frame->n_vectors;
1954 }
1955
1956 /* *INDENT-OFF* */
1957 VLIB_REGISTER_NODE (nat44_ed_out2in_reass_node) = {
1958   .name = "nat44-ed-out2in-reass",
1959   .vector_size = sizeof (u32),
1960   .format_trace = format_nat44_reass_trace,
1961   .type = VLIB_NODE_TYPE_INTERNAL,
1962   .n_errors = ARRAY_LEN(nat_out2in_ed_error_strings),
1963   .error_strings = nat_out2in_ed_error_strings,
1964   .n_next_nodes = NAT44_ED_OUT2IN_N_NEXT,
1965   .next_nodes = {
1966     [NAT44_ED_OUT2IN_NEXT_DROP] = "error-drop",
1967     [NAT44_ED_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1968     [NAT44_ED_OUT2IN_NEXT_SLOW_PATH] = "nat44-ed-out2in-slowpath",
1969     [NAT44_ED_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1970     [NAT44_ED_OUT2IN_NEXT_IN2OUT] = "nat44-ed-in2out",
1971     [NAT44_ED_OUT2IN_NEXT_REASS] = "nat44-ed-out2in-reass",
1972   },
1973 };
1974 /* *INDENT-ON* */
1975
1976 /*
1977  * fd.io coding-style-patch-verification: ON
1978  *
1979  * Local Variables:
1980  * eval: (c-set-style "gnu")
1981  * End:
1982  */