abd704579aad14ca041b74f9db0fcb1def403e15
[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, ~0, ~0,
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, thread_index,
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 (&sm->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 (&sm->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                   thread_index, 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, thread_index,
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, ~0, ~0, &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, ~0, ~0, 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, ~0, ~0, &kv);
358     }
359
360   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
361     {
362       ASSERT (thread_index == ed_value_get_thread_index (&value));
363       s =
364         pool_elt_at_index (tsm->sessions,
365                            ed_value_get_session_index (&value));
366     }
367   else
368     {
369       u32 proto;
370
371       if (PREDICT_FALSE
372           (nat44_ed_maximum_sessions_exceeded
373            (sm, rx_fib_index, thread_index)))
374         return;
375
376       s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
377       if (!s)
378         {
379           nat_elog_warn ("create NAT session failed");
380           return;
381         }
382
383       proto = ip_proto_to_nat_proto (ip->protocol);
384
385       s->ext_host_addr = ip->src_address;
386       s->ext_host_port = r_port;
387       s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS;
388       s->out2in.addr = ip->dst_address;
389       s->out2in.port = l_port;
390       s->out2in.protocol = proto;
391       if (proto == NAT_PROTOCOL_OTHER)
392         {
393           s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
394           s->out2in.port = ip->protocol;
395         }
396       s->out2in.fib_index = 0;
397       s->in2out = s->out2in;
398
399       kv.value = s - tsm->sessions;
400       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
401         nat_elog_notice ("in2out_ed key add failed");
402     }
403
404   if (ip->protocol == IP_PROTOCOL_TCP)
405     {
406       tcp_header_t *tcp = ip4_next_header (ip);
407       if (nat44_set_tcp_session_state_o2i
408           (sm, now, s, tcp->flags, tcp->ack_number, tcp->seq_number,
409            thread_index))
410         return;
411     }
412
413   /* Accounting */
414   nat44_session_update_counters (s, now, 0, thread_index);
415   /* Per-user LRU list maintenance */
416   nat44_session_update_lru (sm, s, thread_index);
417 }
418
419 static inline void
420 create_bypass_for_fwd_worker (snat_main_t * sm, vlib_buffer_t * b,
421                               ip4_header_t * ip, u32 rx_fib_index)
422 {
423   ip4_header_t ip_wkr = {
424     .src_address = ip->dst_address,
425   };
426   u32 thread_index = sm->worker_in2out_cb (&ip_wkr, rx_fib_index, 0);
427
428   create_bypass_for_fwd (sm, b, ip, rx_fib_index, thread_index);
429 }
430
431 #ifndef CLIB_MARCH_VARIANT
432 u32
433 icmp_match_out2in_ed (snat_main_t * sm, vlib_node_runtime_t * node,
434                       u32 thread_index, vlib_buffer_t * b, ip4_header_t * ip,
435                       u8 * p_proto, snat_session_key_t * p_value,
436                       u8 * p_dont_translate, void *d, void *e)
437 {
438   u32 next = ~0, sw_if_index, rx_fib_index;
439   clib_bihash_kv_16_8_t kv, value;
440   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
441   snat_session_t *s = 0;
442   u8 dont_translate = 0, is_addr_only, identity_nat;
443   snat_session_key_t e_key, l_key;
444   u16 l_port, r_port;
445   vlib_main_t *vm = vlib_get_main ();
446
447   sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
448   rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
449
450   if (get_icmp_o2i_ed_key
451       (b, ip, rx_fib_index, ~0, ~0, p_proto, &l_port, &r_port, &kv))
452     {
453       b->error = node->errors[NAT_OUT2IN_ED_ERROR_UNSUPPORTED_PROTOCOL];
454       next = NAT_NEXT_DROP;
455       goto out;
456     }
457
458   if (clib_bihash_search_16_8 (&sm->out2in_ed, &kv, &value))
459     {
460       /* Try to match static mapping */
461       e_key.addr = ip->dst_address;
462       e_key.port = l_port;
463       e_key.protocol = ip_proto_to_nat_proto (ip->protocol);
464       e_key.fib_index = rx_fib_index;
465       if (snat_static_mapping_match
466           (sm, e_key, &l_key, 1, &is_addr_only, 0, 0, 0, &identity_nat))
467         {
468           if (!sm->forwarding_enabled)
469             {
470               /* Don't NAT packet aimed at the intfc address */
471               if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index,
472                                                     ip->dst_address.as_u32)))
473                 {
474                   dont_translate = 1;
475                   goto out;
476                 }
477               b->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
478               next = NAT_NEXT_DROP;
479               goto out;
480             }
481           else
482             {
483               dont_translate = 1;
484               if (next_src_nat (sm, ip, l_port, r_port,
485                                 thread_index, rx_fib_index))
486                 {
487                   next = NAT_NEXT_IN2OUT_ED_FAST_PATH;
488                   goto out;
489                 }
490               if (sm->num_workers > 1)
491                 create_bypass_for_fwd_worker (sm, b, ip, rx_fib_index);
492               else
493                 create_bypass_for_fwd (sm, b, ip, rx_fib_index, thread_index);
494               goto out;
495             }
496         }
497
498       if (PREDICT_FALSE
499           (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
500            ICMP4_echo_reply
501            && (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
502                ICMP4_echo_request || !is_addr_only)))
503         {
504           b->error = node->errors[NAT_OUT2IN_ED_ERROR_BAD_ICMP_TYPE];
505           next = NAT_NEXT_DROP;
506           goto out;
507         }
508
509       if (PREDICT_FALSE (identity_nat))
510         {
511           dont_translate = 1;
512           goto out;
513         }
514
515       /* Create session initiated by host from external network */
516       s = create_session_for_static_mapping_ed (sm, b, l_key, e_key, node,
517                                                 rx_fib_index, thread_index, 0,
518                                                 0, vlib_time_now (vm));
519
520       if (!s)
521         {
522           next = NAT_NEXT_DROP;
523           goto out;
524         }
525     }
526   else
527     {
528       if (PREDICT_FALSE
529           (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
530            ICMP4_echo_reply
531            && vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
532            ICMP4_echo_request
533            && !icmp_type_is_error_message (vnet_buffer (b)->ip.
534                                            reass.icmp_type_or_tcp_flags)))
535         {
536           b->error = node->errors[NAT_OUT2IN_ED_ERROR_BAD_ICMP_TYPE];
537           next = NAT_NEXT_DROP;
538           goto out;
539         }
540
541       ASSERT (thread_index == ed_value_get_thread_index (&value));
542       s =
543         pool_elt_at_index (tsm->sessions,
544                            ed_value_get_session_index (&value));
545     }
546 out:
547   if (s)
548     *p_value = s->in2out;
549   *p_dont_translate = dont_translate;
550   if (d)
551     *(snat_session_t **) d = s;
552   return next;
553 }
554 #endif
555
556 static snat_session_t *
557 nat44_ed_out2in_unknown_proto (snat_main_t * sm,
558                                vlib_buffer_t * b,
559                                ip4_header_t * ip,
560                                u32 rx_fib_index,
561                                u32 thread_index,
562                                f64 now,
563                                vlib_main_t * vm, vlib_node_runtime_t * node)
564 {
565   clib_bihash_kv_8_8_t kv, value;
566   clib_bihash_kv_16_8_t s_kv, s_value;
567   snat_static_mapping_t *m;
568   u32 old_addr, new_addr;
569   ip_csum_t sum;
570   snat_session_t *s;
571   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
572
573   old_addr = ip->dst_address.as_u32;
574
575   make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol, rx_fib_index,
576               0, 0, ~0, ~0, &s_kv);
577
578   if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
579     {
580       ASSERT (thread_index == ed_value_get_thread_index (&s_value));
581       s =
582         pool_elt_at_index (tsm->sessions,
583                            ed_value_get_session_index (&s_value));
584       new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
585     }
586   else
587     {
588       if (PREDICT_FALSE
589           (nat44_ed_maximum_sessions_exceeded
590            (sm, rx_fib_index, thread_index)))
591         {
592           b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
593           nat_elog_notice ("maximum sessions exceeded");
594           return 0;
595         }
596
597       make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
598       if (clib_bihash_search_8_8
599           (&sm->static_mapping_by_external, &kv, &value))
600         {
601           b->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
602           return 0;
603         }
604
605       m = pool_elt_at_index (sm->static_mappings, value.value);
606
607       new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
608
609       /* Create a new session */
610       s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
611       if (!s)
612         {
613           b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_USER_SESS_EXCEEDED];
614           nat_elog_warn ("create NAT session failed");
615           return 0;
616         }
617
618       s->ext_host_addr.as_u32 = ip->src_address.as_u32;
619       s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
620       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
621       s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
622       s->out2in.addr.as_u32 = old_addr;
623       s->out2in.fib_index = rx_fib_index;
624       s->in2out.addr.as_u32 = new_addr;
625       s->in2out.fib_index = m->fib_index;
626       s->in2out.port = s->out2in.port = ip->protocol;
627
628       /* Add to lookup tables */
629       s_kv.value = s - tsm->sessions;
630       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
631         nat_elog_notice ("out2in key add failed");
632
633       make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol,
634                   m->fib_index, 0, 0, thread_index, s - tsm->sessions, &s_kv);
635       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
636         nat_elog_notice ("in2out key add failed");
637     }
638
639   /* Update IP checksum */
640   sum = ip->checksum;
641   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
642   ip->checksum = ip_csum_fold (sum);
643
644   vnet_buffer (b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
645
646   /* Accounting */
647   nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b),
648                                  thread_index);
649   /* Per-user LRU list maintenance */
650   nat44_session_update_lru (sm, s, thread_index);
651
652   return s;
653 }
654
655 static inline uword
656 nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
657                                           vlib_node_runtime_t * node,
658                                           vlib_frame_t * frame,
659                                           int is_multi_worker)
660 {
661   u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
662   nat_next_t next_index;
663   snat_main_t *sm = &snat_main;
664   f64 now = vlib_time_now (vm);
665   u32 thread_index = vm->thread_index;
666   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
667   u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
668     0, fragments = 0;
669
670   stats_node_index = sm->ed_out2in_node_index;
671
672   from = vlib_frame_vector_args (frame);
673   n_left_from = frame->n_vectors;
674   next_index = node->cached_next_index;
675
676   while (n_left_from > 0)
677     {
678       u32 n_left_to_next;
679
680       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
681
682       while (n_left_from > 0 && n_left_to_next > 0)
683         {
684           u32 bi0;
685           vlib_buffer_t *b0;
686           u32 next0, sw_if_index0, rx_fib_index0, proto0, old_addr0,
687             new_addr0;
688           u16 old_port0, new_port0;
689           ip4_header_t *ip0;
690           udp_header_t *udp0;
691           tcp_header_t *tcp0;
692           snat_session_t *s0 = 0;
693           clib_bihash_kv_16_8_t kv0, value0;
694           ip_csum_t sum0;
695
696           /* speculatively enqueue b0 to the current next frame */
697           bi0 = from[0];
698           to_next[0] = bi0;
699           from += 1;
700           to_next += 1;
701           n_left_from -= 1;
702           n_left_to_next -= 1;
703
704           b0 = vlib_get_buffer (vm, bi0);
705           next0 = vnet_buffer2 (b0)->nat.arc_next;
706
707           vnet_buffer (b0)->snat.flags = 0;
708           ip0 = vlib_buffer_get_current (b0);
709
710           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
711           rx_fib_index0 =
712             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
713                                                  sw_if_index0);
714
715           if (PREDICT_FALSE (ip0->ttl == 1))
716             {
717               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
718               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
719                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
720                                            0);
721               next0 = NAT_NEXT_ICMP_ERROR;
722               goto trace0;
723             }
724
725           udp0 = ip4_next_header (ip0);
726           tcp0 = (tcp_header_t *) udp0;
727           proto0 = ip_proto_to_nat_proto (ip0->protocol);
728
729           if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
730             {
731               next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
732               goto trace0;
733             }
734
735           if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
736             {
737               next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
738               goto trace0;
739             }
740
741           make_ed_kv (&ip0->dst_address, &ip0->src_address,
742                       ip0->protocol, rx_fib_index0,
743                       vnet_buffer (b0)->ip.reass.l4_dst_port,
744                       vnet_buffer (b0)->ip.reass.l4_src_port, ~0, ~0, &kv0);
745
746           /* there is a stashed index in vnet_buffer2 from handoff node,
747            * see if we can use it */
748           if (is_multi_worker && PREDICT_TRUE
749               (!pool_is_free_index
750                (tsm->sessions,
751                 vnet_buffer2 (b0)->nat.ed_out2in_nat_session_index)))
752             {
753               s0 = pool_elt_at_index (tsm->sessions,
754                                       vnet_buffer2 (b0)->
755                                       nat.ed_out2in_nat_session_index);
756               if (PREDICT_TRUE
757                   (s0->out2in.addr.as_u32 == ip0->dst_address.as_u32
758                    && s0->out2in.port ==
759                    vnet_buffer (b0)->ip.reass.l4_dst_port
760                    && s0->out2in.protocol ==
761                    ip_proto_to_nat_proto (ip0->protocol)
762                    && s0->out2in.fib_index == rx_fib_index0
763                    && s0->ext_host_addr.as_u32 == ip0->src_address.as_u32
764                    && s0->ext_host_port ==
765                    vnet_buffer (b0)->ip.reass.l4_src_port))
766                 {
767                   /* yes, this is the droid we're looking for */
768                   goto skip_lookup;
769                 }
770             }
771
772           if (clib_bihash_search_16_8 (&sm->out2in_ed, &kv0, &value0))
773             {
774               next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
775               goto trace0;
776             }
777           ASSERT (thread_index == ed_value_get_thread_index (&value0));
778           s0 =
779             pool_elt_at_index (tsm->sessions,
780                                ed_value_get_session_index (&value0));
781
782         skip_lookup:
783           if (s0->tcp_closed_timestamp)
784             {
785               if (now >= s0->tcp_closed_timestamp)
786                 {
787                   // session is closed, go slow path
788                   next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
789                 }
790               else
791                 {
792                   // session in transitory timeout, drop
793                   b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TCP_CLOSED];
794                   next0 = NAT_NEXT_DROP;
795                 }
796               goto trace0;
797             }
798
799           // drop if session expired
800           u64 sess_timeout_time;
801           sess_timeout_time = s0->last_heard +
802             (f64) nat44_session_get_timeout (sm, s0);
803           if (now >= sess_timeout_time)
804             {
805               // session is closed, go slow path
806               nat_free_session_data (sm, s0, thread_index, 0);
807               nat_ed_session_delete (sm, s0, thread_index, 1);
808               next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
809               goto trace0;
810             }
811           //
812
813           old_addr0 = ip0->dst_address.as_u32;
814           new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
815           vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
816
817           sum0 = ip0->checksum;
818           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
819                                  dst_address);
820           if (PREDICT_FALSE (is_twice_nat_session (s0)))
821             sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
822                                    s0->ext_host_nat_addr.as_u32, ip4_header_t,
823                                    src_address);
824           ip0->checksum = ip_csum_fold (sum0);
825
826           old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
827
828           if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
829             {
830               if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
831                 {
832                   new_port0 = udp0->dst_port = s0->in2out.port;
833                   sum0 = tcp0->checksum;
834                   sum0 =
835                     ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
836                                     dst_address);
837                   sum0 =
838                     ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
839                                     length);
840                   if (is_twice_nat_session (s0))
841                     {
842                       sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
843                                              s0->ext_host_nat_addr.as_u32,
844                                              ip4_header_t, dst_address);
845                       sum0 =
846                         ip_csum_update (sum0,
847                                         vnet_buffer (b0)->ip.
848                                         reass.l4_src_port,
849                                         s0->ext_host_nat_port, ip4_header_t,
850                                         length);
851                       tcp0->src_port = s0->ext_host_nat_port;
852                       ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
853                     }
854                   tcp0->checksum = ip_csum_fold (sum0);
855                 }
856               tcp_packets++;
857               if (nat44_set_tcp_session_state_o2i
858                   (sm, now, s0,
859                    vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags,
860                    vnet_buffer (b0)->ip.reass.tcp_ack_number,
861                    vnet_buffer (b0)->ip.reass.tcp_seq_number, thread_index))
862                 goto trace0;
863             }
864           else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
865                    && udp0->checksum)
866             {
867               new_port0 = udp0->dst_port = s0->in2out.port;
868               sum0 = udp0->checksum;
869               sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
870                                      dst_address);
871               sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
872                                      length);
873               if (PREDICT_FALSE (is_twice_nat_session (s0)))
874                 {
875                   sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
876                                          s0->ext_host_nat_addr.as_u32,
877                                          ip4_header_t, dst_address);
878                   sum0 =
879                     ip_csum_update (sum0,
880                                     vnet_buffer (b0)->ip.reass.l4_src_port,
881                                     s0->ext_host_nat_port, ip4_header_t,
882                                     length);
883                   udp0->src_port = s0->ext_host_nat_port;
884                   ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
885                 }
886               udp0->checksum = ip_csum_fold (sum0);
887               udp_packets++;
888             }
889           else
890             {
891               if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
892                 {
893                   new_port0 = udp0->dst_port = s0->in2out.port;
894                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
895                     {
896                       udp0->src_port = s0->ext_host_nat_port;
897                       ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
898                     }
899                 }
900               udp_packets++;
901             }
902
903           /* Accounting */
904           nat44_session_update_counters (s0, now,
905                                          vlib_buffer_length_in_chain (vm, b0),
906                                          thread_index);
907           /* Per-user LRU list maintenance */
908           nat44_session_update_lru (sm, s0, thread_index);
909
910         trace0:
911           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
912                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
913             {
914               nat44_ed_out2in_trace_t *t =
915                 vlib_add_trace (vm, node, b0, sizeof (*t));
916               t->sw_if_index = sw_if_index0;
917               t->next_index = next0;
918               t->is_slow_path = 0;
919
920               if (s0)
921                 t->session_index = s0 - tsm->sessions;
922               else
923                 t->session_index = ~0;
924             }
925
926           pkts_processed += next0 == vnet_buffer2 (b0)->nat.arc_next;
927           /* verify speculative enqueue, maybe switch current next frame */
928           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
929                                            to_next, n_left_to_next,
930                                            bi0, next0);
931         }
932
933       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
934     }
935
936   vlib_node_increment_counter (vm, stats_node_index,
937                                NAT_OUT2IN_ED_ERROR_OUT2IN_PACKETS,
938                                pkts_processed);
939   vlib_node_increment_counter (vm, stats_node_index,
940                                NAT_OUT2IN_ED_ERROR_TCP_PACKETS, tcp_packets);
941   vlib_node_increment_counter (vm, stats_node_index,
942                                NAT_OUT2IN_ED_ERROR_UDP_PACKETS, udp_packets);
943   vlib_node_increment_counter (vm, stats_node_index,
944                                NAT_OUT2IN_ED_ERROR_ICMP_PACKETS,
945                                icmp_packets);
946   vlib_node_increment_counter (vm, stats_node_index,
947                                NAT_OUT2IN_ED_ERROR_OTHER_PACKETS,
948                                other_packets);
949   vlib_node_increment_counter (vm, stats_node_index,
950                                NAT_OUT2IN_ED_ERROR_FRAGMENTS, fragments);
951   return frame->n_vectors;
952 }
953
954 static inline uword
955 nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
956                                           vlib_node_runtime_t * node,
957                                           vlib_frame_t * frame)
958 {
959   u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
960   nat_next_t next_index;
961   snat_main_t *sm = &snat_main;
962   // HERE
963   f64 now = vlib_time_now (vm);
964   u32 thread_index = vm->thread_index;
965   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
966   u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
967     0, fragments = 0;
968
969   stats_node_index = sm->ed_out2in_slowpath_node_index;
970
971   from = vlib_frame_vector_args (frame);
972   n_left_from = frame->n_vectors;
973   next_index = node->cached_next_index;
974
975   while (n_left_from > 0)
976     {
977       u32 n_left_to_next;
978
979       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
980
981       while (n_left_from > 0 && n_left_to_next > 0)
982         {
983           u32 bi0;
984           vlib_buffer_t *b0;
985           u32 next0, sw_if_index0, rx_fib_index0, proto0, old_addr0,
986             new_addr0;
987           u16 old_port0, new_port0;
988           ip4_header_t *ip0;
989           udp_header_t *udp0;
990           tcp_header_t *tcp0;
991           icmp46_header_t *icmp0;
992           snat_session_t *s0 = 0;
993           clib_bihash_kv_16_8_t kv0, value0;
994           ip_csum_t sum0;
995           snat_session_key_t e_key0, l_key0;
996           lb_nat_type_t lb_nat0;
997           twice_nat_type_t twice_nat0;
998           u8 identity_nat0;
999
1000           /* speculatively enqueue b0 to the current next frame */
1001           bi0 = from[0];
1002           to_next[0] = bi0;
1003           from += 1;
1004           to_next += 1;
1005           n_left_from -= 1;
1006           n_left_to_next -= 1;
1007
1008           b0 = vlib_get_buffer (vm, bi0);
1009           next0 = vnet_buffer2 (b0)->nat.arc_next;
1010
1011           vnet_buffer (b0)->snat.flags = 0;
1012           ip0 = vlib_buffer_get_current (b0);
1013
1014           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1015           rx_fib_index0 =
1016             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1017                                                  sw_if_index0);
1018
1019           if (PREDICT_FALSE (ip0->ttl == 1))
1020             {
1021               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1022               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1023                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1024                                            0);
1025               next0 = NAT_NEXT_ICMP_ERROR;
1026               goto trace0;
1027             }
1028
1029           udp0 = ip4_next_header (ip0);
1030           tcp0 = (tcp_header_t *) udp0;
1031           icmp0 = (icmp46_header_t *) udp0;
1032           proto0 = ip_proto_to_nat_proto (ip0->protocol);
1033
1034           if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1035             {
1036               s0 =
1037                 nat44_ed_out2in_unknown_proto (sm, b0, ip0, rx_fib_index0,
1038                                                thread_index, now, vm, node);
1039               if (!sm->forwarding_enabled)
1040                 {
1041                   if (!s0)
1042                     next0 = NAT_NEXT_DROP;
1043                 }
1044               other_packets++;
1045               goto trace0;
1046             }
1047
1048           if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1049             {
1050               next0 = icmp_out2in_ed_slow_path
1051                 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1052                  next0, now, thread_index, &s0);
1053               icmp_packets++;
1054               goto trace0;
1055             }
1056
1057           make_ed_kv (&ip0->dst_address, &ip0->src_address,
1058                       ip0->protocol, rx_fib_index0,
1059                       vnet_buffer (b0)->ip.reass.l4_dst_port,
1060                       vnet_buffer (b0)->ip.reass.l4_src_port, ~0, ~0, &kv0);
1061
1062           s0 = NULL;
1063           if (!clib_bihash_search_16_8 (&sm->out2in_ed, &kv0, &value0))
1064             {
1065               ASSERT (thread_index == ed_value_get_thread_index (&value0));
1066               s0 =
1067                 pool_elt_at_index (tsm->sessions,
1068                                    ed_value_get_session_index (&value0));
1069
1070               if (s0->tcp_closed_timestamp && now >= s0->tcp_closed_timestamp)
1071                 {
1072                   nat_free_session_data (sm, s0, thread_index, 0);
1073                   nat_ed_session_delete (sm, s0, thread_index, 1);
1074                   s0 = NULL;
1075                 }
1076             }
1077
1078           if (!s0)
1079             {
1080               /* Try to match static mapping by external address and port,
1081                  destination address and port in packet */
1082               e_key0.addr = ip0->dst_address;
1083               e_key0.port = vnet_buffer (b0)->ip.reass.l4_dst_port;
1084               e_key0.protocol = proto0;
1085               e_key0.fib_index = rx_fib_index0;
1086
1087               if (snat_static_mapping_match (sm, e_key0, &l_key0, 1, 0,
1088                                              &twice_nat0, &lb_nat0,
1089                                              &ip0->src_address,
1090                                              &identity_nat0))
1091                 {
1092                   /*
1093                    * Send DHCP packets to the ipv4 stack, or we won't
1094                    * be able to use dhcp client on the outside interface
1095                    */
1096                   if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_UDP
1097                                      && (vnet_buffer (b0)->ip.
1098                                          reass.l4_dst_port ==
1099                                          clib_host_to_net_u16
1100                                          (UDP_DST_PORT_dhcp_to_client))))
1101                     {
1102                       goto trace0;
1103                     }
1104
1105                   if (!sm->forwarding_enabled)
1106                     {
1107                       b0->error =
1108                         node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
1109                       next0 = NAT_NEXT_DROP;
1110                     }
1111                   else
1112                     {
1113                       if (next_src_nat
1114                           (sm, ip0, vnet_buffer (b0)->ip.reass.l4_src_port,
1115                            vnet_buffer (b0)->ip.reass.l4_dst_port,
1116                            thread_index, rx_fib_index0))
1117                         {
1118                           next0 = NAT_NEXT_IN2OUT_ED_FAST_PATH;
1119                           goto trace0;
1120                         }
1121                       if (sm->num_workers > 1)
1122                         create_bypass_for_fwd_worker (sm, b0, ip0,
1123                                                       rx_fib_index0);
1124                       else
1125                         create_bypass_for_fwd (sm, b0, ip0, rx_fib_index0,
1126                                                thread_index);
1127                     }
1128                   goto trace0;
1129                 }
1130
1131               if (PREDICT_FALSE (identity_nat0))
1132                 goto trace0;
1133
1134               if ((proto0 == NAT_PROTOCOL_TCP)
1135                   && !tcp_flags_is_init (vnet_buffer (b0)->ip.
1136                                          reass.icmp_type_or_tcp_flags))
1137                 {
1138                   b0->error = node->errors[NAT_OUT2IN_ED_ERROR_NON_SYN];
1139                   next0 = NAT_NEXT_DROP;
1140                   goto trace0;
1141                 }
1142
1143               /* Create session initiated by host from external network */
1144               s0 = create_session_for_static_mapping_ed (sm, b0, l_key0,
1145                                                          e_key0, node,
1146                                                          rx_fib_index0,
1147                                                          thread_index,
1148                                                          twice_nat0,
1149                                                          lb_nat0, now);
1150               if (!s0)
1151                 {
1152                   next0 = NAT_NEXT_DROP;
1153                   goto trace0;
1154                 }
1155             }
1156
1157           old_addr0 = ip0->dst_address.as_u32;
1158           new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
1159           vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1160
1161           sum0 = ip0->checksum;
1162           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1163                                  dst_address);
1164           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1165             sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
1166                                    s0->ext_host_nat_addr.as_u32, ip4_header_t,
1167                                    src_address);
1168           ip0->checksum = ip_csum_fold (sum0);
1169
1170           old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
1171
1172           if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1173             {
1174               if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1175                 {
1176                   new_port0 = udp0->dst_port = s0->in2out.port;
1177                   sum0 = tcp0->checksum;
1178                   sum0 =
1179                     ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1180                                     dst_address);
1181                   sum0 =
1182                     ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1183                                     length);
1184                   if (is_twice_nat_session (s0))
1185                     {
1186                       sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
1187                                              s0->ext_host_nat_addr.as_u32,
1188                                              ip4_header_t, dst_address);
1189                       sum0 =
1190                         ip_csum_update (sum0,
1191                                         vnet_buffer (b0)->ip.
1192                                         reass.l4_src_port,
1193                                         s0->ext_host_nat_port, ip4_header_t,
1194                                         length);
1195                       tcp0->src_port = s0->ext_host_nat_port;
1196                       ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
1197                     }
1198                   tcp0->checksum = ip_csum_fold (sum0);
1199                 }
1200               tcp_packets++;
1201               if (nat44_set_tcp_session_state_o2i
1202                   (sm, now, s0,
1203                    vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags,
1204                    vnet_buffer (b0)->ip.reass.tcp_ack_number,
1205                    vnet_buffer (b0)->ip.reass.tcp_seq_number, thread_index))
1206                 goto trace0;
1207             }
1208           else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
1209                    && udp0->checksum)
1210             {
1211               new_port0 = udp0->dst_port = s0->in2out.port;
1212               sum0 = udp0->checksum;
1213               sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1214                                      dst_address);
1215               sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1216                                      length);
1217               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1218                 {
1219                   sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
1220                                          s0->ext_host_nat_addr.as_u32,
1221                                          ip4_header_t, dst_address);
1222                   sum0 =
1223                     ip_csum_update (sum0,
1224                                     vnet_buffer (b0)->ip.reass.l4_src_port,
1225                                     s0->ext_host_nat_port, ip4_header_t,
1226                                     length);
1227                   udp0->src_port = s0->ext_host_nat_port;
1228                   ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
1229                 }
1230               udp0->checksum = ip_csum_fold (sum0);
1231               udp_packets++;
1232             }
1233           else
1234             {
1235               if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1236                 {
1237                   new_port0 = udp0->dst_port = s0->in2out.port;
1238                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
1239                     {
1240                       udp0->src_port = s0->ext_host_nat_port;
1241                       ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
1242                     }
1243                 }
1244               udp_packets++;
1245             }
1246
1247           /* Accounting */
1248           nat44_session_update_counters (s0, now,
1249                                          vlib_buffer_length_in_chain (vm, b0),
1250                                          thread_index);
1251           /* Per-user LRU list maintenance */
1252           nat44_session_update_lru (sm, s0, thread_index);
1253
1254         trace0:
1255           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1256                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1257             {
1258               nat44_ed_out2in_trace_t *t =
1259                 vlib_add_trace (vm, node, b0, sizeof (*t));
1260               t->sw_if_index = sw_if_index0;
1261               t->next_index = next0;
1262               t->is_slow_path = 1;
1263
1264               if (s0)
1265                 t->session_index = s0 - tsm->sessions;
1266               else
1267                 t->session_index = ~0;
1268             }
1269
1270           pkts_processed += next0 == vnet_buffer2 (b0)->nat.arc_next;
1271           /* verify speculative enqueue, maybe switch current next frame */
1272           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1273                                            to_next, n_left_to_next,
1274                                            bi0, next0);
1275         }
1276
1277       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1278     }
1279
1280   vlib_node_increment_counter (vm, stats_node_index,
1281                                NAT_OUT2IN_ED_ERROR_OUT2IN_PACKETS,
1282                                pkts_processed);
1283   vlib_node_increment_counter (vm, stats_node_index,
1284                                NAT_OUT2IN_ED_ERROR_TCP_PACKETS, tcp_packets);
1285   vlib_node_increment_counter (vm, stats_node_index,
1286                                NAT_OUT2IN_ED_ERROR_UDP_PACKETS, udp_packets);
1287   vlib_node_increment_counter (vm, stats_node_index,
1288                                NAT_OUT2IN_ED_ERROR_ICMP_PACKETS,
1289                                icmp_packets);
1290   vlib_node_increment_counter (vm, stats_node_index,
1291                                NAT_OUT2IN_ED_ERROR_OTHER_PACKETS,
1292                                other_packets);
1293   vlib_node_increment_counter (vm, stats_node_index,
1294                                NAT_OUT2IN_ED_ERROR_FRAGMENTS, fragments);
1295   return frame->n_vectors;
1296 }
1297
1298 VLIB_NODE_FN (nat44_ed_out2in_node) (vlib_main_t * vm,
1299                                      vlib_node_runtime_t * node,
1300                                      vlib_frame_t * frame)
1301 {
1302   if (snat_main.num_workers > 1)
1303     {
1304       return nat44_ed_out2in_fast_path_node_fn_inline (vm, node, frame, 1);
1305     }
1306   else
1307     {
1308       return nat44_ed_out2in_fast_path_node_fn_inline (vm, node, frame, 0);
1309     }
1310 }
1311
1312 /* *INDENT-OFF* */
1313 VLIB_REGISTER_NODE (nat44_ed_out2in_node) = {
1314   .name = "nat44-ed-out2in",
1315   .vector_size = sizeof (u32),
1316   .sibling_of = "nat-default",
1317   .format_trace = format_nat44_ed_out2in_trace,
1318   .type = VLIB_NODE_TYPE_INTERNAL,
1319   .n_errors = ARRAY_LEN(nat_out2in_ed_error_strings),
1320   .error_strings = nat_out2in_ed_error_strings,
1321   .runtime_data_bytes = sizeof (snat_runtime_t),
1322 };
1323 /* *INDENT-ON* */
1324
1325 VLIB_NODE_FN (nat44_ed_out2in_slowpath_node) (vlib_main_t * vm,
1326                                               vlib_node_runtime_t * node,
1327                                               vlib_frame_t * frame)
1328 {
1329   return nat44_ed_out2in_slow_path_node_fn_inline (vm, node, frame);
1330 }
1331
1332 /* *INDENT-OFF* */
1333 VLIB_REGISTER_NODE (nat44_ed_out2in_slowpath_node) = {
1334   .name = "nat44-ed-out2in-slowpath",
1335   .vector_size = sizeof (u32),
1336   .sibling_of = "nat-default",
1337   .format_trace = format_nat44_ed_out2in_trace,
1338   .type = VLIB_NODE_TYPE_INTERNAL,
1339   .n_errors = ARRAY_LEN(nat_out2in_ed_error_strings),
1340   .error_strings = nat_out2in_ed_error_strings,
1341   .runtime_data_bytes = sizeof (snat_runtime_t),
1342 };
1343 /* *INDENT-ON* */
1344
1345 static u8 *
1346 format_nat_pre_trace (u8 * s, va_list * args)
1347 {
1348   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1349   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1350   nat_pre_trace_t *t = va_arg (*args, nat_pre_trace_t *);
1351   return format (s, "out2in next_index %d arc_next_index %d", t->next_index,
1352                  t->arc_next_index);
1353 }
1354
1355 VLIB_NODE_FN (nat_pre_out2in_node) (vlib_main_t * vm,
1356                                     vlib_node_runtime_t * node,
1357                                     vlib_frame_t * frame)
1358 {
1359   return nat_pre_node_fn_inline (vm, node, frame,
1360                                  NAT_NEXT_OUT2IN_ED_FAST_PATH);
1361 }
1362
1363 /* *INDENT-OFF* */
1364 VLIB_REGISTER_NODE (nat_pre_out2in_node) = {
1365   .name = "nat-pre-out2in",
1366   .vector_size = sizeof (u32),
1367   .sibling_of = "nat-default",
1368   .format_trace = format_nat_pre_trace,
1369   .type = VLIB_NODE_TYPE_INTERNAL,
1370   .n_errors = 0,
1371  };
1372 /* *INDENT-ON* */
1373
1374 /*
1375  * fd.io coding-style-patch-verification: ON
1376  *
1377  * Local Variables:
1378  * eval: (c-set-style "gnu")
1379  * End:
1380  */