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