e597191d4d272925a80a2e83d27fb688c3db20a0
[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_inlines.h>
31 #include <nat/nat44/inlines.h>
32 #include <nat/nat_syslog.h>
33 #include <nat/nat_ha.h>
34 #include <nat/nat44/ed_inlines.h>
35
36 static char *nat_out2in_ed_error_strings[] = {
37 #define _(sym,string) string,
38   foreach_nat_out2in_ed_error
39 #undef _
40 };
41
42 typedef struct
43 {
44   u32 sw_if_index;
45   u32 next_index;
46   u32 session_index;
47   u32 is_slow_path;
48 } nat44_ed_out2in_trace_t;
49
50 static u8 *
51 format_nat44_ed_out2in_trace (u8 * s, va_list * args)
52 {
53   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
54   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
55   nat44_ed_out2in_trace_t *t = va_arg (*args, nat44_ed_out2in_trace_t *);
56   char *tag;
57
58   tag =
59     t->is_slow_path ? "NAT44_OUT2IN_ED_SLOW_PATH" :
60     "NAT44_OUT2IN_ED_FAST_PATH";
61
62   s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
63               t->sw_if_index, t->next_index, t->session_index);
64
65   return s;
66 }
67
68 static inline u32
69 icmp_out2in_ed_slow_path (snat_main_t * sm, vlib_buffer_t * b0,
70                           ip4_header_t * ip0, icmp46_header_t * icmp0,
71                           u32 sw_if_index0, u32 rx_fib_index0,
72                           vlib_node_runtime_t * node, u32 next0, f64 now,
73                           u32 thread_index, snat_session_t ** p_s0)
74 {
75   vlib_main_t *vm = vlib_get_main ();
76
77   next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
78                        next0, thread_index, p_s0, 0);
79   snat_session_t *s0 = *p_s0;
80   if (PREDICT_TRUE (next0 != NAT_NEXT_DROP && s0))
81     {
82       /* Accounting */
83       nat44_session_update_counters (s0, now,
84                                      vlib_buffer_length_in_chain
85                                      (vm, b0), thread_index);
86       /* Per-user LRU list maintenance */
87       nat44_session_update_lru (sm, s0, thread_index);
88     }
89   return next0;
90 }
91
92 #ifndef CLIB_MARCH_VARIANT
93 int
94 nat44_o2i_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
95 {
96   snat_main_t *sm = &snat_main;
97   nat44_is_idle_session_ctx_t *ctx = arg;
98   snat_session_t *s;
99   u64 sess_timeout_time;
100   u8 proto;
101   u16 r_port, l_port;
102   ip4_address_t *l_addr, *r_addr;
103   u32 fib_index;
104   clib_bihash_kv_16_8_t ed_kv;
105   int i;
106   snat_address_t *a;
107   snat_session_key_t key;
108   snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
109                                                        ctx->thread_index);
110
111   s = pool_elt_at_index (tsm->sessions, kv->value);
112   sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
113   if (ctx->now >= sess_timeout_time)
114     {
115       l_addr = &s->in2out.addr;
116       r_addr = &s->ext_host_addr;
117       fib_index = s->in2out.fib_index;
118       if (snat_is_unk_proto_session (s))
119         {
120           proto = s->in2out.port;
121           r_port = 0;
122           l_port = 0;
123         }
124       else
125         {
126           proto = nat_proto_to_ip_proto (s->in2out.protocol);
127           l_port = s->in2out.port;
128           r_port = s->ext_host_port;
129         }
130       if (is_twice_nat_session (s))
131         {
132           r_addr = &s->ext_host_nat_addr;
133           r_port = s->ext_host_nat_port;
134         }
135       make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
136                   &ed_kv);
137       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
138         nat_elog_warn ("in2out_ed key del failed");
139
140       if (snat_is_unk_proto_session (s))
141         goto delete;
142
143       snat_ipfix_logging_nat44_ses_delete (ctx->thread_index,
144                                            s->in2out.addr.as_u32,
145                                            s->out2in.addr.as_u32,
146                                            s->in2out.protocol,
147                                            s->in2out.port,
148                                            s->out2in.port,
149                                            s->in2out.fib_index);
150
151       nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
152                              &s->in2out.addr, s->in2out.port,
153                              &s->ext_host_nat_addr, s->ext_host_nat_port,
154                              &s->out2in.addr, s->out2in.port,
155                              &s->ext_host_addr, s->ext_host_port,
156                              s->in2out.protocol, is_twice_nat_session (s));
157
158       nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
159                    s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
160                    ctx->thread_index);
161
162       if (is_twice_nat_session (s))
163         {
164           for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
165             {
166               key.protocol = s->in2out.protocol;
167               key.port = s->ext_host_nat_port;
168               a = sm->twice_nat_addresses + i;
169               if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
170                 {
171                   snat_free_outside_address_and_port (sm->twice_nat_addresses,
172                                                       ctx->thread_index,
173                                                       &key);
174                   break;
175                 }
176             }
177         }
178
179       if (snat_is_session_static (s))
180         goto delete;
181
182       snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
183                                           &s->out2in);
184     delete:
185       nat_ed_session_delete (sm, s, ctx->thread_index, 1);
186       return 1;
187     }
188
189   return 0;
190 }
191 #endif
192
193 static snat_session_t *
194 create_session_for_static_mapping_ed (snat_main_t * sm,
195                                       vlib_buffer_t * b,
196                                       snat_session_key_t l_key,
197                                       snat_session_key_t e_key,
198                                       vlib_node_runtime_t * node,
199                                       u32 rx_fib_index,
200                                       u32 thread_index,
201                                       twice_nat_type_t twice_nat,
202                                       lb_nat_type_t lb_nat, f64 now)
203 {
204   snat_session_t *s;
205   ip4_header_t *ip;
206   udp_header_t *udp;
207   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
208   clib_bihash_kv_16_8_t kv;
209   snat_session_key_t eh_key;
210   nat44_is_idle_session_ctx_t ctx;
211
212   if (PREDICT_FALSE
213       (nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index)))
214     {
215       b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
216       nat_elog_notice ("maximum sessions exceeded");
217       return 0;
218     }
219
220   s = nat_ed_session_alloc (sm, thread_index, now, e_key.protocol);
221   if (!s)
222     {
223       b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_USER_SESS_EXCEEDED];
224       nat_elog_warn ("create NAT session failed");
225       return 0;
226     }
227
228   ip = vlib_buffer_get_current (b);
229   udp = ip4_next_header (ip);
230
231   s->ext_host_addr.as_u32 = ip->src_address.as_u32;
232   s->ext_host_port = e_key.protocol == NAT_PROTOCOL_ICMP ? 0 : udp->src_port;
233   s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
234   if (lb_nat)
235     s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
236   if (lb_nat == AFFINITY_LB_NAT)
237     s->flags |= SNAT_SESSION_FLAG_AFFINITY;
238   s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
239   s->out2in = e_key;
240   s->in2out = l_key;
241   s->in2out.protocol = s->out2in.protocol;
242
243   /* Add to lookup tables */
244   make_ed_kv (&e_key.addr, &s->ext_host_addr, ip->protocol,
245               e_key.fib_index, e_key.port, s->ext_host_port,
246               s - tsm->sessions, &kv);
247   ctx.now = now;
248   ctx.thread_index = thread_index;
249   if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->out2in_ed, &kv,
250                                                nat44_o2i_ed_is_idle_session_cb,
251                                                &ctx))
252     nat_elog_notice ("out2in-ed key add failed");
253
254   if (twice_nat == TWICE_NAT || (twice_nat == TWICE_NAT_SELF &&
255                                  ip->src_address.as_u32 == l_key.addr.as_u32))
256     {
257       eh_key.protocol = e_key.protocol;
258       if (snat_alloc_outside_address_and_port (sm->twice_nat_addresses, 0,
259                                                thread_index, &eh_key,
260                                                sm->port_per_thread,
261                                                tsm->snat_thread_index))
262         {
263           b->error = node->errors[NAT_OUT2IN_ED_ERROR_OUT_OF_PORTS];
264           nat_ed_session_delete (sm, s, thread_index, 1);
265           if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 0))
266             nat_elog_notice ("out2in-ed key del failed");
267           return 0;
268         }
269       s->ext_host_nat_addr.as_u32 = eh_key.addr.as_u32;
270       s->ext_host_nat_port = eh_key.port;
271       s->flags |= SNAT_SESSION_FLAG_TWICE_NAT;
272       make_ed_kv (&l_key.addr, &s->ext_host_nat_addr, ip->protocol,
273                   l_key.fib_index, l_key.port, s->ext_host_nat_port,
274                   s - tsm->sessions, &kv);
275     }
276   else
277     {
278       make_ed_kv (&l_key.addr, &s->ext_host_addr, ip->protocol,
279                   l_key.fib_index, l_key.port, s->ext_host_port,
280                   s - tsm->sessions, &kv);
281     }
282   if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, &kv,
283                                                nat44_i2o_ed_is_idle_session_cb,
284                                                &ctx))
285     nat_elog_notice ("in2out-ed key add failed");
286
287   snat_ipfix_logging_nat44_ses_create (thread_index,
288                                        s->in2out.addr.as_u32,
289                                        s->out2in.addr.as_u32,
290                                        s->in2out.protocol,
291                                        s->in2out.port,
292                                        s->out2in.port, s->in2out.fib_index);
293
294   nat_syslog_nat44_sadd (s->user_index, s->in2out.fib_index,
295                          &s->in2out.addr, s->in2out.port,
296                          &s->ext_host_nat_addr, s->ext_host_nat_port,
297                          &s->out2in.addr, s->out2in.port,
298                          &s->ext_host_addr, s->ext_host_port,
299                          s->in2out.protocol, is_twice_nat_session (s));
300
301   nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
302                s->out2in.port, &s->ext_host_addr, s->ext_host_port,
303                &s->ext_host_nat_addr, s->ext_host_nat_port,
304                s->in2out.protocol, s->in2out.fib_index, s->flags,
305                thread_index, 0);
306
307   return s;
308 }
309
310 static int
311 next_src_nat (snat_main_t * sm, ip4_header_t * ip, u16 src_port,
312               u16 dst_port, u32 thread_index, u32 rx_fib_index)
313 {
314   clib_bihash_kv_16_8_t kv, value;
315   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
316
317   make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol,
318               rx_fib_index, src_port, dst_port, ~0ULL, &kv);
319   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
320     return 1;
321
322   return 0;
323 }
324
325 static void
326 create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip,
327                        u32 rx_fib_index, u32 thread_index)
328 {
329   clib_bihash_kv_16_8_t kv, value;
330   udp_header_t *udp;
331   snat_session_t *s = 0;
332   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
333   vlib_main_t *vm = vlib_get_main ();
334   f64 now = vlib_time_now (vm);
335   u16 l_port, r_port;
336
337   if (ip->protocol == IP_PROTOCOL_ICMP)
338     {
339       if (get_icmp_o2i_ed_key
340           (b, ip, rx_fib_index, ~0ULL, 0, &l_port, &r_port, &kv))
341         return;
342     }
343   else
344     {
345       if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
346         {
347           udp = ip4_next_header (ip);
348           l_port = udp->dst_port;
349           r_port = udp->src_port;
350         }
351       else
352         {
353           l_port = 0;
354           r_port = 0;
355         }
356       make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol,
357                   rx_fib_index, l_port, r_port, ~0ULL, &kv);
358     }
359
360   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
361     {
362       s = pool_elt_at_index (tsm->sessions, value.value);
363     }
364   else
365     {
366       u32 proto;
367
368       if (PREDICT_FALSE
369           (nat44_ed_maximum_sessions_exceeded
370            (sm, rx_fib_index, thread_index)))
371         return;
372
373       s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
374       if (!s)
375         {
376           nat_elog_warn ("create NAT session failed");
377           return;
378         }
379
380       proto = ip_proto_to_nat_proto (ip->protocol);
381
382       s->ext_host_addr = ip->src_address;
383       s->ext_host_port = r_port;
384       s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS;
385       s->out2in.addr = ip->dst_address;
386       s->out2in.port = l_port;
387       s->out2in.protocol = proto;
388       if (proto == NAT_PROTOCOL_OTHER)
389         {
390           s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
391           s->out2in.port = ip->protocol;
392         }
393       s->out2in.fib_index = 0;
394       s->in2out = s->out2in;
395
396       kv.value = s - tsm->sessions;
397       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
398         nat_elog_notice ("in2out_ed key add failed");
399     }
400
401   if (ip->protocol == IP_PROTOCOL_TCP)
402     {
403       tcp_header_t *tcp = ip4_next_header (ip);
404       if (nat44_set_tcp_session_state_o2i
405           (sm, now, s, tcp->flags, tcp->ack_number, tcp->seq_number,
406            thread_index))
407         return;
408     }
409
410   /* Accounting */
411   nat44_session_update_counters (s, now, 0, thread_index);
412   /* Per-user LRU list maintenance */
413   nat44_session_update_lru (sm, s, thread_index);
414 }
415
416 static inline void
417 create_bypass_for_fwd_worker (snat_main_t * sm, vlib_buffer_t * b,
418                               ip4_header_t * ip, u32 rx_fib_index)
419 {
420   ip4_header_t ip_wkr = {
421     .src_address = ip->dst_address,
422   };
423   u32 thread_index = sm->worker_in2out_cb (&ip_wkr, rx_fib_index, 0);
424
425   create_bypass_for_fwd (sm, b, ip, rx_fib_index, thread_index);
426 }
427
428 #ifndef CLIB_MARCH_VARIANT
429 u32
430 icmp_match_out2in_ed (snat_main_t * sm, vlib_node_runtime_t * node,
431                       u32 thread_index, vlib_buffer_t * b, ip4_header_t * ip,
432                       u8 * p_proto, snat_session_key_t * p_value,
433                       u8 * p_dont_translate, void *d, void *e)
434 {
435   u32 next = ~0, sw_if_index, rx_fib_index;
436   clib_bihash_kv_16_8_t kv, value;
437   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
438   snat_session_t *s = 0;
439   u8 dont_translate = 0, is_addr_only, identity_nat;
440   snat_session_key_t e_key, l_key;
441   u16 l_port, r_port;
442   vlib_main_t *vm = vlib_get_main ();
443
444   sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
445   rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
446
447   if (get_icmp_o2i_ed_key
448       (b, ip, rx_fib_index, ~0ULL, p_proto, &l_port, &r_port, &kv))
449     {
450       b->error = node->errors[NAT_OUT2IN_ED_ERROR_UNSUPPORTED_PROTOCOL];
451       next = NAT_NEXT_DROP;
452       goto out;
453     }
454
455   if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
456     {
457       /* Try to match static mapping */
458       e_key.addr = ip->dst_address;
459       e_key.port = l_port;
460       e_key.protocol = ip_proto_to_nat_proto (ip->protocol);
461       e_key.fib_index = rx_fib_index;
462       if (snat_static_mapping_match
463           (sm, e_key, &l_key, 1, &is_addr_only, 0, 0, 0, &identity_nat))
464         {
465           if (!sm->forwarding_enabled)
466             {
467               /* Don't NAT packet aimed at the intfc address */
468               if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index,
469                                                     ip->dst_address.as_u32)))
470                 {
471                   dont_translate = 1;
472                   goto out;
473                 }
474               b->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
475               next = NAT_NEXT_DROP;
476               goto out;
477             }
478           else
479             {
480               dont_translate = 1;
481               if (next_src_nat (sm, ip, l_port, r_port,
482                                 thread_index, rx_fib_index))
483                 {
484                   next = NAT_NEXT_IN2OUT_ED_FAST_PATH;
485                   goto out;
486                 }
487               if (sm->num_workers > 1)
488                 create_bypass_for_fwd_worker (sm, b, ip, rx_fib_index);
489               else
490                 create_bypass_for_fwd (sm, b, ip, rx_fib_index, thread_index);
491               goto out;
492             }
493         }
494
495       if (PREDICT_FALSE
496           (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
497            ICMP4_echo_reply
498            && (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
499                ICMP4_echo_request || !is_addr_only)))
500         {
501           b->error = node->errors[NAT_OUT2IN_ED_ERROR_BAD_ICMP_TYPE];
502           next = NAT_NEXT_DROP;
503           goto out;
504         }
505
506       if (PREDICT_FALSE (identity_nat))
507         {
508           dont_translate = 1;
509           goto out;
510         }
511
512       /* Create session initiated by host from external network */
513       s = create_session_for_static_mapping_ed (sm, b, l_key, e_key, node,
514                                                 rx_fib_index, thread_index, 0,
515                                                 0, vlib_time_now (vm));
516
517       if (!s)
518         {
519           next = NAT_NEXT_DROP;
520           goto out;
521         }
522     }
523   else
524     {
525       if (PREDICT_FALSE
526           (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
527            ICMP4_echo_reply
528            && vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
529            ICMP4_echo_request
530            && !icmp_type_is_error_message (vnet_buffer (b)->ip.
531                                            reass.icmp_type_or_tcp_flags)))
532         {
533           b->error = node->errors[NAT_OUT2IN_ED_ERROR_BAD_ICMP_TYPE];
534           next = NAT_NEXT_DROP;
535           goto out;
536         }
537
538       s = pool_elt_at_index (tsm->sessions, value.value);
539     }
540 out:
541   if (s)
542     *p_value = s->in2out;
543   *p_dont_translate = dont_translate;
544   if (d)
545     *(snat_session_t **) d = s;
546   return next;
547 }
548 #endif
549
550 static snat_session_t *
551 nat44_ed_out2in_unknown_proto (snat_main_t * sm,
552                                vlib_buffer_t * b,
553                                ip4_header_t * ip,
554                                u32 rx_fib_index,
555                                u32 thread_index,
556                                f64 now,
557                                vlib_main_t * vm, vlib_node_runtime_t * node)
558 {
559   clib_bihash_kv_8_8_t kv, value;
560   clib_bihash_kv_16_8_t s_kv, s_value;
561   snat_static_mapping_t *m;
562   u32 old_addr, new_addr;
563   ip_csum_t sum;
564   snat_session_t *s;
565   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
566
567   old_addr = ip->dst_address.as_u32;
568
569   make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol, rx_fib_index,
570               0, 0, ~0ULL, &s_kv);
571
572   if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
573     {
574       s = pool_elt_at_index (tsm->sessions, s_value.value);
575       new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
576     }
577   else
578     {
579       if (PREDICT_FALSE
580           (nat44_ed_maximum_sessions_exceeded
581            (sm, rx_fib_index, thread_index)))
582         {
583           b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
584           nat_elog_notice ("maximum sessions exceeded");
585           return 0;
586         }
587
588       make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
589       if (clib_bihash_search_8_8
590           (&sm->static_mapping_by_external, &kv, &value))
591         {
592           b->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
593           return 0;
594         }
595
596       m = pool_elt_at_index (sm->static_mappings, value.value);
597
598       new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
599
600       /* Create a new session */
601       s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
602       if (!s)
603         {
604           b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_USER_SESS_EXCEEDED];
605           nat_elog_warn ("create NAT session failed");
606           return 0;
607         }
608
609       s->ext_host_addr.as_u32 = ip->src_address.as_u32;
610       s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
611       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
612       s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
613       s->out2in.addr.as_u32 = old_addr;
614       s->out2in.fib_index = rx_fib_index;
615       s->in2out.addr.as_u32 = new_addr;
616       s->in2out.fib_index = m->fib_index;
617       s->in2out.port = s->out2in.port = ip->protocol;
618
619       /* Add to lookup tables */
620       s_kv.value = s - tsm->sessions;
621       if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1))
622         nat_elog_notice ("out2in key add failed");
623
624       make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol,
625                   m->fib_index, 0, 0, s - tsm->sessions, &s_kv);
626       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
627         nat_elog_notice ("in2out key add failed");
628     }
629
630   /* Update IP checksum */
631   sum = ip->checksum;
632   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
633   ip->checksum = ip_csum_fold (sum);
634
635   vnet_buffer (b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
636
637   /* Accounting */
638   nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b),
639                                  thread_index);
640   /* Per-user LRU list maintenance */
641   nat44_session_update_lru (sm, s, thread_index);
642
643   return s;
644 }
645
646 static inline uword
647 nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
648                                           vlib_node_runtime_t * node,
649                                           vlib_frame_t * frame)
650 {
651   u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
652   nat_next_t next_index;
653   snat_main_t *sm = &snat_main;
654   f64 now = vlib_time_now (vm);
655   u32 thread_index = vm->thread_index;
656   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
657   u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
658     0, fragments = 0;
659
660   stats_node_index = sm->ed_out2in_node_index;
661
662   from = vlib_frame_vector_args (frame);
663   n_left_from = frame->n_vectors;
664   next_index = node->cached_next_index;
665
666   while (n_left_from > 0)
667     {
668       u32 n_left_to_next;
669
670       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
671
672       while (n_left_from > 0 && n_left_to_next > 0)
673         {
674           u32 bi0;
675           vlib_buffer_t *b0;
676           u32 next0, sw_if_index0, rx_fib_index0, proto0, old_addr0,
677             new_addr0;
678           u16 old_port0, new_port0;
679           ip4_header_t *ip0;
680           udp_header_t *udp0;
681           tcp_header_t *tcp0;
682           snat_session_t *s0 = 0;
683           clib_bihash_kv_16_8_t kv0, value0;
684           ip_csum_t sum0;
685
686           /* speculatively enqueue b0 to the current next frame */
687           bi0 = from[0];
688           to_next[0] = bi0;
689           from += 1;
690           to_next += 1;
691           n_left_from -= 1;
692           n_left_to_next -= 1;
693
694           b0 = vlib_get_buffer (vm, bi0);
695           next0 = vnet_buffer2 (b0)->nat.arc_next;
696
697           vnet_buffer (b0)->snat.flags = 0;
698           ip0 = vlib_buffer_get_current (b0);
699
700           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
701           rx_fib_index0 =
702             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
703                                                  sw_if_index0);
704
705           if (PREDICT_FALSE (ip0->ttl == 1))
706             {
707               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
708               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
709                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
710                                            0);
711               next0 = NAT_NEXT_ICMP_ERROR;
712               goto trace0;
713             }
714
715           udp0 = ip4_next_header (ip0);
716           tcp0 = (tcp_header_t *) udp0;
717           proto0 = ip_proto_to_nat_proto (ip0->protocol);
718
719           if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
720             {
721               next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
722               goto trace0;
723             }
724
725           if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
726             {
727               next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
728               goto trace0;
729             }
730
731           make_ed_kv (&ip0->dst_address, &ip0->src_address,
732                       ip0->protocol, rx_fib_index0,
733                       vnet_buffer (b0)->ip.reass.l4_dst_port,
734                       vnet_buffer (b0)->ip.reass.l4_src_port, ~0ULL, &kv0);
735
736           if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
737             {
738               next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
739               goto trace0;
740             }
741           s0 = pool_elt_at_index (tsm->sessions, value0.value);
742
743           if (s0->tcp_closed_timestamp)
744             {
745               if (now >= s0->tcp_closed_timestamp)
746                 {
747                   // session is closed, go slow path
748                   next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
749                 }
750               else
751                 {
752                   // session in transitory timeout, drop
753                   b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TCP_CLOSED];
754                   next0 = NAT_NEXT_DROP;
755                 }
756               goto trace0;
757             }
758
759           // drop if session expired
760           u64 sess_timeout_time;
761           sess_timeout_time = s0->last_heard +
762             (f64) nat44_session_get_timeout (sm, s0);
763           if (now >= sess_timeout_time)
764             {
765               // session is closed, go slow path
766               nat_free_session_data (sm, s0, thread_index, 0);
767               nat_ed_session_delete (sm, s0, thread_index, 1);
768               next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
769               goto trace0;
770             }
771           //
772
773           old_addr0 = ip0->dst_address.as_u32;
774           new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
775           vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
776
777           sum0 = ip0->checksum;
778           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
779                                  dst_address);
780           if (PREDICT_FALSE (is_twice_nat_session (s0)))
781             sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
782                                    s0->ext_host_nat_addr.as_u32, ip4_header_t,
783                                    src_address);
784           ip0->checksum = ip_csum_fold (sum0);
785
786           old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
787
788           if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
789             {
790               if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
791                 {
792                   new_port0 = udp0->dst_port = s0->in2out.port;
793                   sum0 = tcp0->checksum;
794                   sum0 =
795                     ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
796                                     dst_address);
797                   sum0 =
798                     ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
799                                     length);
800                   if (is_twice_nat_session (s0))
801                     {
802                       sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
803                                              s0->ext_host_nat_addr.as_u32,
804                                              ip4_header_t, dst_address);
805                       sum0 =
806                         ip_csum_update (sum0,
807                                         vnet_buffer (b0)->ip.
808                                         reass.l4_src_port,
809                                         s0->ext_host_nat_port, ip4_header_t,
810                                         length);
811                       tcp0->src_port = s0->ext_host_nat_port;
812                       ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
813                     }
814                   tcp0->checksum = ip_csum_fold (sum0);
815                 }
816               tcp_packets++;
817               if (nat44_set_tcp_session_state_o2i
818                   (sm, now, s0,
819                    vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags,
820                    vnet_buffer (b0)->ip.reass.tcp_ack_number,
821                    vnet_buffer (b0)->ip.reass.tcp_seq_number, thread_index))
822                 goto trace0;
823             }
824           else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
825                    && udp0->checksum)
826             {
827               new_port0 = udp0->dst_port = s0->in2out.port;
828               sum0 = udp0->checksum;
829               sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
830                                      dst_address);
831               sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
832                                      length);
833               if (PREDICT_FALSE (is_twice_nat_session (s0)))
834                 {
835                   sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
836                                          s0->ext_host_nat_addr.as_u32,
837                                          ip4_header_t, dst_address);
838                   sum0 =
839                     ip_csum_update (sum0,
840                                     vnet_buffer (b0)->ip.reass.l4_src_port,
841                                     s0->ext_host_nat_port, ip4_header_t,
842                                     length);
843                   udp0->src_port = s0->ext_host_nat_port;
844                   ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
845                 }
846               udp0->checksum = ip_csum_fold (sum0);
847               udp_packets++;
848             }
849           else
850             {
851               if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
852                 {
853                   new_port0 = udp0->dst_port = s0->in2out.port;
854                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
855                     {
856                       udp0->src_port = s0->ext_host_nat_port;
857                       ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
858                     }
859                 }
860               udp_packets++;
861             }
862
863           /* Accounting */
864           nat44_session_update_counters (s0, now,
865                                          vlib_buffer_length_in_chain (vm, b0),
866                                          thread_index);
867           /* Per-user LRU list maintenance */
868           nat44_session_update_lru (sm, s0, thread_index);
869
870         trace0:
871           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
872                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
873             {
874               nat44_ed_out2in_trace_t *t =
875                 vlib_add_trace (vm, node, b0, sizeof (*t));
876               t->sw_if_index = sw_if_index0;
877               t->next_index = next0;
878               t->is_slow_path = 0;
879
880               if (s0)
881                 t->session_index = s0 - tsm->sessions;
882               else
883                 t->session_index = ~0;
884             }
885
886           pkts_processed += next0 == vnet_buffer2 (b0)->nat.arc_next;
887           /* verify speculative enqueue, maybe switch current next frame */
888           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
889                                            to_next, n_left_to_next,
890                                            bi0, next0);
891         }
892
893       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
894     }
895
896   vlib_node_increment_counter (vm, stats_node_index,
897                                NAT_OUT2IN_ED_ERROR_OUT2IN_PACKETS,
898                                pkts_processed);
899   vlib_node_increment_counter (vm, stats_node_index,
900                                NAT_OUT2IN_ED_ERROR_TCP_PACKETS, tcp_packets);
901   vlib_node_increment_counter (vm, stats_node_index,
902                                NAT_OUT2IN_ED_ERROR_UDP_PACKETS, udp_packets);
903   vlib_node_increment_counter (vm, stats_node_index,
904                                NAT_OUT2IN_ED_ERROR_ICMP_PACKETS,
905                                icmp_packets);
906   vlib_node_increment_counter (vm, stats_node_index,
907                                NAT_OUT2IN_ED_ERROR_OTHER_PACKETS,
908                                other_packets);
909   vlib_node_increment_counter (vm, stats_node_index,
910                                NAT_OUT2IN_ED_ERROR_FRAGMENTS, fragments);
911   return frame->n_vectors;
912 }
913
914 static inline uword
915 nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
916                                           vlib_node_runtime_t * node,
917                                           vlib_frame_t * frame)
918 {
919   u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
920   nat_next_t next_index;
921   snat_main_t *sm = &snat_main;
922   // HERE
923   f64 now = vlib_time_now (vm);
924   u32 thread_index = vm->thread_index;
925   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
926   u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
927     0, fragments = 0;
928
929   stats_node_index = sm->ed_out2in_slowpath_node_index;
930
931   from = vlib_frame_vector_args (frame);
932   n_left_from = frame->n_vectors;
933   next_index = node->cached_next_index;
934
935   while (n_left_from > 0)
936     {
937       u32 n_left_to_next;
938
939       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
940
941       while (n_left_from > 0 && n_left_to_next > 0)
942         {
943           u32 bi0;
944           vlib_buffer_t *b0;
945           u32 next0, sw_if_index0, rx_fib_index0, proto0, old_addr0,
946             new_addr0;
947           u16 old_port0, new_port0;
948           ip4_header_t *ip0;
949           udp_header_t *udp0;
950           tcp_header_t *tcp0;
951           icmp46_header_t *icmp0;
952           snat_session_t *s0 = 0;
953           clib_bihash_kv_16_8_t kv0, value0;
954           ip_csum_t sum0;
955           snat_session_key_t e_key0, l_key0;
956           lb_nat_type_t lb_nat0;
957           twice_nat_type_t twice_nat0;
958           u8 identity_nat0;
959
960           /* speculatively enqueue b0 to the current next frame */
961           bi0 = from[0];
962           to_next[0] = bi0;
963           from += 1;
964           to_next += 1;
965           n_left_from -= 1;
966           n_left_to_next -= 1;
967
968           b0 = vlib_get_buffer (vm, bi0);
969           next0 = vnet_buffer2 (b0)->nat.arc_next;
970
971           vnet_buffer (b0)->snat.flags = 0;
972           ip0 = vlib_buffer_get_current (b0);
973
974           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
975           rx_fib_index0 =
976             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
977                                                  sw_if_index0);
978
979           if (PREDICT_FALSE (ip0->ttl == 1))
980             {
981               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
982               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
983                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
984                                            0);
985               next0 = NAT_NEXT_ICMP_ERROR;
986               goto trace0;
987             }
988
989           udp0 = ip4_next_header (ip0);
990           tcp0 = (tcp_header_t *) udp0;
991           icmp0 = (icmp46_header_t *) udp0;
992           proto0 = ip_proto_to_nat_proto (ip0->protocol);
993
994           if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
995             {
996               s0 =
997                 nat44_ed_out2in_unknown_proto (sm, b0, ip0, rx_fib_index0,
998                                                thread_index, now, vm, node);
999               if (!sm->forwarding_enabled)
1000                 {
1001                   if (!s0)
1002                     next0 = NAT_NEXT_DROP;
1003                 }
1004               other_packets++;
1005               goto trace0;
1006             }
1007
1008           if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1009             {
1010               next0 = icmp_out2in_ed_slow_path
1011                 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1012                  next0, now, thread_index, &s0);
1013               icmp_packets++;
1014               goto trace0;
1015             }
1016
1017           make_ed_kv (&ip0->dst_address, &ip0->src_address,
1018                       ip0->protocol, rx_fib_index0,
1019                       vnet_buffer (b0)->ip.reass.l4_dst_port,
1020                       vnet_buffer (b0)->ip.reass.l4_src_port, ~0ULL, &kv0);
1021
1022           s0 = NULL;
1023           if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
1024             {
1025               s0 = pool_elt_at_index (tsm->sessions, value0.value);
1026
1027               if (s0->tcp_closed_timestamp && now >= s0->tcp_closed_timestamp)
1028                 {
1029                   nat_free_session_data (sm, s0, thread_index, 0);
1030                   nat_ed_session_delete (sm, s0, thread_index, 1);
1031                   s0 = NULL;
1032                 }
1033             }
1034
1035           if (!s0)
1036             {
1037               /* Try to match static mapping by external address and port,
1038                  destination address and port in packet */
1039               e_key0.addr = ip0->dst_address;
1040               e_key0.port = vnet_buffer (b0)->ip.reass.l4_dst_port;
1041               e_key0.protocol = proto0;
1042               e_key0.fib_index = rx_fib_index0;
1043
1044               if (snat_static_mapping_match (sm, e_key0, &l_key0, 1, 0,
1045                                              &twice_nat0, &lb_nat0,
1046                                              &ip0->src_address,
1047                                              &identity_nat0))
1048                 {
1049                   /*
1050                    * Send DHCP packets to the ipv4 stack, or we won't
1051                    * be able to use dhcp client on the outside interface
1052                    */
1053                   if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_UDP
1054                                      && (vnet_buffer (b0)->ip.
1055                                          reass.l4_dst_port ==
1056                                          clib_host_to_net_u16
1057                                          (UDP_DST_PORT_dhcp_to_client))))
1058                     {
1059                       goto trace0;
1060                     }
1061
1062                   if (!sm->forwarding_enabled)
1063                     {
1064                       b0->error =
1065                         node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
1066                       next0 = NAT_NEXT_DROP;
1067                     }
1068                   else
1069                     {
1070                       if (next_src_nat
1071                           (sm, ip0, vnet_buffer (b0)->ip.reass.l4_src_port,
1072                            vnet_buffer (b0)->ip.reass.l4_dst_port,
1073                            thread_index, rx_fib_index0))
1074                         {
1075                           next0 = NAT_NEXT_IN2OUT_ED_FAST_PATH;
1076                           goto trace0;
1077                         }
1078                       if (sm->num_workers > 1)
1079                         create_bypass_for_fwd_worker (sm, b0, ip0,
1080                                                       rx_fib_index0);
1081                       else
1082                         create_bypass_for_fwd (sm, b0, ip0, rx_fib_index0,
1083                                                thread_index);
1084                     }
1085                   goto trace0;
1086                 }
1087
1088               if (PREDICT_FALSE (identity_nat0))
1089                 goto trace0;
1090
1091               if ((proto0 == NAT_PROTOCOL_TCP)
1092                   && !tcp_flags_is_init (vnet_buffer (b0)->ip.
1093                                          reass.icmp_type_or_tcp_flags))
1094                 {
1095                   b0->error = node->errors[NAT_OUT2IN_ED_ERROR_NON_SYN];
1096                   next0 = NAT_NEXT_DROP;
1097                   goto trace0;
1098                 }
1099
1100               /* Create session initiated by host from external network */
1101               s0 = create_session_for_static_mapping_ed (sm, b0, l_key0,
1102                                                          e_key0, node,
1103                                                          rx_fib_index0,
1104                                                          thread_index,
1105                                                          twice_nat0,
1106                                                          lb_nat0, now);
1107               if (!s0)
1108                 {
1109                   next0 = NAT_NEXT_DROP;
1110                   goto trace0;
1111                 }
1112             }
1113
1114           old_addr0 = ip0->dst_address.as_u32;
1115           new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
1116           vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1117
1118           sum0 = ip0->checksum;
1119           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1120                                  dst_address);
1121           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1122             sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
1123                                    s0->ext_host_nat_addr.as_u32, ip4_header_t,
1124                                    src_address);
1125           ip0->checksum = ip_csum_fold (sum0);
1126
1127           old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
1128
1129           if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1130             {
1131               if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1132                 {
1133                   new_port0 = udp0->dst_port = s0->in2out.port;
1134                   sum0 = tcp0->checksum;
1135                   sum0 =
1136                     ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1137                                     dst_address);
1138                   sum0 =
1139                     ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1140                                     length);
1141                   if (is_twice_nat_session (s0))
1142                     {
1143                       sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
1144                                              s0->ext_host_nat_addr.as_u32,
1145                                              ip4_header_t, dst_address);
1146                       sum0 =
1147                         ip_csum_update (sum0,
1148                                         vnet_buffer (b0)->ip.
1149                                         reass.l4_src_port,
1150                                         s0->ext_host_nat_port, ip4_header_t,
1151                                         length);
1152                       tcp0->src_port = s0->ext_host_nat_port;
1153                       ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
1154                     }
1155                   tcp0->checksum = ip_csum_fold (sum0);
1156                 }
1157               tcp_packets++;
1158               if (nat44_set_tcp_session_state_o2i
1159                   (sm, now, s0,
1160                    vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags,
1161                    vnet_buffer (b0)->ip.reass.tcp_ack_number,
1162                    vnet_buffer (b0)->ip.reass.tcp_seq_number, thread_index))
1163                 goto trace0;
1164             }
1165           else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
1166                    && udp0->checksum)
1167             {
1168               new_port0 = udp0->dst_port = s0->in2out.port;
1169               sum0 = udp0->checksum;
1170               sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1171                                      dst_address);
1172               sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1173                                      length);
1174               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1175                 {
1176                   sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
1177                                          s0->ext_host_nat_addr.as_u32,
1178                                          ip4_header_t, dst_address);
1179                   sum0 =
1180                     ip_csum_update (sum0,
1181                                     vnet_buffer (b0)->ip.reass.l4_src_port,
1182                                     s0->ext_host_nat_port, ip4_header_t,
1183                                     length);
1184                   udp0->src_port = s0->ext_host_nat_port;
1185                   ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
1186                 }
1187               udp0->checksum = ip_csum_fold (sum0);
1188               udp_packets++;
1189             }
1190           else
1191             {
1192               if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1193                 {
1194                   new_port0 = udp0->dst_port = s0->in2out.port;
1195                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
1196                     {
1197                       udp0->src_port = s0->ext_host_nat_port;
1198                       ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
1199                     }
1200                 }
1201               udp_packets++;
1202             }
1203
1204           /* Accounting */
1205           nat44_session_update_counters (s0, now,
1206                                          vlib_buffer_length_in_chain (vm, b0),
1207                                          thread_index);
1208           /* Per-user LRU list maintenance */
1209           nat44_session_update_lru (sm, s0, thread_index);
1210
1211         trace0:
1212           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1213                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1214             {
1215               nat44_ed_out2in_trace_t *t =
1216                 vlib_add_trace (vm, node, b0, sizeof (*t));
1217               t->sw_if_index = sw_if_index0;
1218               t->next_index = next0;
1219               t->is_slow_path = 1;
1220
1221               if (s0)
1222                 t->session_index = s0 - tsm->sessions;
1223               else
1224                 t->session_index = ~0;
1225             }
1226
1227           pkts_processed += next0 == vnet_buffer2 (b0)->nat.arc_next;
1228           /* verify speculative enqueue, maybe switch current next frame */
1229           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1230                                            to_next, n_left_to_next,
1231                                            bi0, next0);
1232         }
1233
1234       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1235     }
1236
1237   vlib_node_increment_counter (vm, stats_node_index,
1238                                NAT_OUT2IN_ED_ERROR_OUT2IN_PACKETS,
1239                                pkts_processed);
1240   vlib_node_increment_counter (vm, stats_node_index,
1241                                NAT_OUT2IN_ED_ERROR_TCP_PACKETS, tcp_packets);
1242   vlib_node_increment_counter (vm, stats_node_index,
1243                                NAT_OUT2IN_ED_ERROR_UDP_PACKETS, udp_packets);
1244   vlib_node_increment_counter (vm, stats_node_index,
1245                                NAT_OUT2IN_ED_ERROR_ICMP_PACKETS,
1246                                icmp_packets);
1247   vlib_node_increment_counter (vm, stats_node_index,
1248                                NAT_OUT2IN_ED_ERROR_OTHER_PACKETS,
1249                                other_packets);
1250   vlib_node_increment_counter (vm, stats_node_index,
1251                                NAT_OUT2IN_ED_ERROR_FRAGMENTS, fragments);
1252   return frame->n_vectors;
1253 }
1254
1255 VLIB_NODE_FN (nat44_ed_out2in_node) (vlib_main_t * vm,
1256                                      vlib_node_runtime_t * node,
1257                                      vlib_frame_t * frame)
1258 {
1259   return nat44_ed_out2in_fast_path_node_fn_inline (vm, node, frame);
1260 }
1261
1262 /* *INDENT-OFF* */
1263 VLIB_REGISTER_NODE (nat44_ed_out2in_node) = {
1264   .name = "nat44-ed-out2in",
1265   .vector_size = sizeof (u32),
1266   .sibling_of = "nat-default",
1267   .format_trace = format_nat44_ed_out2in_trace,
1268   .type = VLIB_NODE_TYPE_INTERNAL,
1269   .n_errors = ARRAY_LEN(nat_out2in_ed_error_strings),
1270   .error_strings = nat_out2in_ed_error_strings,
1271   .runtime_data_bytes = sizeof (snat_runtime_t),
1272 };
1273 /* *INDENT-ON* */
1274
1275 VLIB_NODE_FN (nat44_ed_out2in_slowpath_node) (vlib_main_t * vm,
1276                                               vlib_node_runtime_t * node,
1277                                               vlib_frame_t * frame)
1278 {
1279   return nat44_ed_out2in_slow_path_node_fn_inline (vm, node, frame);
1280 }
1281
1282 /* *INDENT-OFF* */
1283 VLIB_REGISTER_NODE (nat44_ed_out2in_slowpath_node) = {
1284   .name = "nat44-ed-out2in-slowpath",
1285   .vector_size = sizeof (u32),
1286   .sibling_of = "nat-default",
1287   .format_trace = format_nat44_ed_out2in_trace,
1288   .type = VLIB_NODE_TYPE_INTERNAL,
1289   .n_errors = ARRAY_LEN(nat_out2in_ed_error_strings),
1290   .error_strings = nat_out2in_ed_error_strings,
1291   .runtime_data_bytes = sizeof (snat_runtime_t),
1292 };
1293 /* *INDENT-ON* */
1294
1295 static u8 *
1296 format_nat_pre_trace (u8 * s, va_list * args)
1297 {
1298   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1299   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1300   nat_pre_trace_t *t = va_arg (*args, nat_pre_trace_t *);
1301   return format (s, "out2in next_index %d arc_next_index %d", t->next_index,
1302                  t->arc_next_index);
1303 }
1304
1305 VLIB_NODE_FN (nat_pre_out2in_node) (vlib_main_t * vm,
1306                                     vlib_node_runtime_t * node,
1307                                     vlib_frame_t * frame)
1308 {
1309   return nat_pre_node_fn_inline (vm, node, frame,
1310                                  NAT_NEXT_OUT2IN_ED_FAST_PATH);
1311 }
1312
1313 /* *INDENT-OFF* */
1314 VLIB_REGISTER_NODE (nat_pre_out2in_node) = {
1315   .name = "nat-pre-out2in",
1316   .vector_size = sizeof (u32),
1317   .sibling_of = "nat-default",
1318   .format_trace = format_nat_pre_trace,
1319   .type = VLIB_NODE_TYPE_INTERNAL,
1320   .n_errors = 0,
1321  };
1322 /* *INDENT-ON* */
1323
1324 /*
1325  * fd.io coding-style-patch-verification: ON
1326  *
1327  * Local Variables:
1328  * eval: (c-set-style "gnu")
1329  * End:
1330  */