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