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