nat: fix error counters
[vpp.git] / src / plugins / nat / in2out_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 inside to outside 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
35 static char *nat_in2out_ed_error_strings[] = {
36 #define _(sym,string) string,
37   foreach_nat_in2out_ed_error
38 #undef _
39 };
40
41 typedef struct
42 {
43   u32 sw_if_index;
44   u32 next_index;
45   u32 session_index;
46   u32 is_slow_path;
47 } nat_in2out_ed_trace_t;
48
49 static u8 *
50 format_nat_in2out_ed_trace (u8 * s, va_list * args)
51 {
52   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
53   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
54   nat_in2out_ed_trace_t *t = va_arg (*args, nat_in2out_ed_trace_t *);
55   char *tag;
56
57   tag =
58     t->is_slow_path ? "NAT44_IN2OUT_ED_SLOW_PATH" :
59     "NAT44_IN2OUT_ED_FAST_PATH";
60
61   s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
62               t->sw_if_index, t->next_index, t->session_index);
63
64   return s;
65 }
66
67 #ifndef CLIB_MARCH_VARIANT
68 int
69 nat44_i2o_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
70 {
71   snat_main_t *sm = &snat_main;
72   nat44_is_idle_session_ctx_t *ctx = arg;
73   snat_session_t *s;
74   u64 sess_timeout_time;
75   nat_ed_ses_key_t ed_key;
76   clib_bihash_kv_16_8_t ed_kv;
77   int i;
78   snat_address_t *a;
79   snat_session_key_t key;
80   snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
81                                                        ctx->thread_index);
82
83   s = pool_elt_at_index (tsm->sessions, kv->value);
84   sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
85   if (ctx->now >= sess_timeout_time)
86     {
87       if (is_fwd_bypass_session (s))
88         goto delete;
89
90       ed_key.l_addr = s->out2in.addr;
91       ed_key.r_addr = s->ext_host_addr;
92       ed_key.fib_index = s->out2in.fib_index;
93       if (snat_is_unk_proto_session (s))
94         {
95           ed_key.proto = s->in2out.port;
96           ed_key.r_port = 0;
97           ed_key.l_port = 0;
98         }
99       else
100         {
101           ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
102           ed_key.l_port = s->out2in.port;
103           ed_key.r_port = s->ext_host_port;
104         }
105       ed_kv.key[0] = ed_key.as_u64[0];
106       ed_kv.key[1] = ed_key.as_u64[1];
107       if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
108         nat_elog_warn ("out2in_ed key del failed");
109
110       if (snat_is_unk_proto_session (s))
111         goto delete;
112
113       snat_ipfix_logging_nat44_ses_delete (ctx->thread_index,
114                                            s->in2out.addr.as_u32,
115                                            s->out2in.addr.as_u32,
116                                            s->in2out.protocol,
117                                            s->in2out.port,
118                                            s->out2in.port,
119                                            s->in2out.fib_index);
120
121       nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
122                              &s->in2out.addr, s->in2out.port,
123                              &s->ext_host_nat_addr, s->ext_host_nat_port,
124                              &s->out2in.addr, s->out2in.port,
125                              &s->ext_host_addr, s->ext_host_port,
126                              s->in2out.protocol, is_twice_nat_session (s));
127
128       nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
129                    s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
130                    ctx->thread_index);
131
132       if (is_twice_nat_session (s))
133         {
134           for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
135             {
136               key.protocol = s->in2out.protocol;
137               key.port = s->ext_host_nat_port;
138               a = sm->twice_nat_addresses + i;
139               if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
140                 {
141                   snat_free_outside_address_and_port (sm->twice_nat_addresses,
142                                                       ctx->thread_index,
143                                                       &key);
144                   break;
145                 }
146             }
147         }
148
149       if (snat_is_session_static (s))
150         goto delete;
151
152       snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
153                                           &s->out2in);
154     delete:
155       nat44_delete_session (sm, s, ctx->thread_index);
156       return 1;
157     }
158
159   return 0;
160 }
161 #endif
162
163 static inline u32
164 icmp_in2out_ed_slow_path (snat_main_t * sm, vlib_buffer_t * b0,
165                           ip4_header_t * ip0, icmp46_header_t * icmp0,
166                           u32 sw_if_index0, u32 rx_fib_index0,
167                           vlib_node_runtime_t * node, u32 next0, f64 now,
168                           u32 thread_index, snat_session_t ** p_s0)
169 {
170   next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
171                        next0, thread_index, p_s0, 0);
172   snat_session_t *s0 = *p_s0;
173   if (PREDICT_TRUE (next0 != NAT_NEXT_DROP && s0))
174     {
175       /* Accounting */
176       nat44_session_update_counters (s0, now,
177                                      vlib_buffer_length_in_chain
178                                      (sm->vlib_main, b0), thread_index);
179       /* Per-user LRU list maintenance */
180       nat44_session_update_lru (sm, s0, thread_index);
181     }
182   return next0;
183 }
184
185 static u32
186 slow_path_ed (snat_main_t * sm,
187               vlib_buffer_t * b,
188               u32 rx_fib_index,
189               clib_bihash_kv_16_8_t * kv,
190               snat_session_t ** sessionp,
191               vlib_node_runtime_t * node, u32 next, u32 thread_index, f64 now)
192 {
193   snat_session_t *s = 0;
194   snat_user_t *u;
195   snat_session_key_t key0, key1;
196   lb_nat_type_t lb = 0, is_sm = 0;
197   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
198   nat_ed_ses_key_t *key = (nat_ed_ses_key_t *) kv->key;
199   u32 proto = ip_proto_to_snat_proto (key->proto);
200   nat_outside_fib_t *outside_fib;
201   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
202   u8 identity_nat;
203   fib_prefix_t pfx = {
204     .fp_proto = FIB_PROTOCOL_IP4,
205     .fp_len = 32,
206     .fp_addr = {
207                 .ip4.as_u32 = key->r_addr.as_u32,
208                 },
209   };
210   nat44_is_idle_session_ctx_t ctx;
211
212   u32 cleared = 0;
213
214   if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
215     {
216       if (PREDICT_FALSE
217           (!(cleared = nat44_users_cleanup (thread_index, now))))
218         {
219           b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
220           nat_ipfix_logging_max_sessions (thread_index, sm->max_translations);
221           nat_elog_notice ("maximum sessions exceeded");
222           return NAT_NEXT_DROP;
223         }
224     }
225
226   key0.addr = key->l_addr;
227   key0.port = key->l_port;
228   key1.protocol = key0.protocol = proto;
229   key0.fib_index = rx_fib_index;
230   key1.fib_index = sm->outside_fib_index;
231
232   /* First try to match static mapping by local address and port */
233   if (snat_static_mapping_match
234       (sm, key0, &key1, 0, 0, 0, &lb, 0, &identity_nat))
235     {
236       /* Try to create dynamic translation */
237       if (snat_alloc_outside_address_and_port (sm->addresses, rx_fib_index,
238                                                thread_index, &key1,
239                                                sm->port_per_thread,
240                                                tsm->snat_thread_index))
241         {
242           if (cleared || !nat44_out_of_ports_cleanup (thread_index, now) ||
243               snat_alloc_outside_address_and_port (sm->addresses,
244                                                    rx_fib_index, thread_index,
245                                                    &key1, sm->port_per_thread,
246                                                    tsm->snat_thread_index))
247             {
248               nat_elog_notice ("addresses exhausted");
249               b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
250               return NAT_NEXT_DROP;
251             }
252         }
253     }
254   else
255     {
256       if (PREDICT_FALSE (identity_nat))
257         {
258           *sessionp = s;
259           return next;
260         }
261       is_sm = 1;
262     }
263
264   if (PREDICT_TRUE (proto == SNAT_PROTOCOL_TCP))
265     {
266       if (PREDICT_FALSE
267           (!tcp_flags_is_init
268            (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)))
269         {
270           b->error = node->errors[NAT_IN2OUT_ED_ERROR_NON_SYN];
271           if (!is_sm)
272             snat_free_outside_address_and_port (sm->addresses,
273                                                 thread_index, &key1);
274           return NAT_NEXT_DROP;
275         }
276     }
277
278   u = nat_user_get_or_create (sm, &key->l_addr, rx_fib_index, thread_index);
279   if (!u)
280     {
281       nat_elog_warn ("create NAT user failed");
282       if (!is_sm)
283         snat_free_outside_address_and_port (sm->addresses,
284                                             thread_index, &key1);
285       b->error = node->errors[NAT_IN2OUT_ED_ERROR_CANNOT_CREATE_USER];
286       return NAT_NEXT_DROP;
287     }
288
289   s = nat_ed_session_alloc (sm, u, thread_index, now);
290   if (!s)
291     {
292       nat44_delete_user_with_no_session (sm, u, thread_index);
293       nat_elog_warn ("create NAT session failed");
294       if (!is_sm)
295         snat_free_outside_address_and_port (sm->addresses,
296                                             thread_index, &key1);
297       b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_USER_SESS_EXCEEDED];
298       return NAT_NEXT_DROP;
299     }
300
301   user_session_increment (sm, u, is_sm);
302   if (is_sm)
303     s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
304   if (lb)
305     s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
306   s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
307   s->ext_host_addr = key->r_addr;
308   s->ext_host_port = key->r_port;
309   s->in2out = key0;
310   s->out2in = key1;
311   s->out2in.protocol = key0.protocol;
312
313   switch (vec_len (sm->outside_fibs))
314     {
315     case 0:
316       s->out2in.fib_index = sm->outside_fib_index;
317       break;
318     case 1:
319       s->out2in.fib_index = sm->outside_fibs[0].fib_index;
320       break;
321     default:
322       /* *INDENT-OFF* */
323       vec_foreach (outside_fib, sm->outside_fibs)
324        {
325           fei = fib_table_lookup (outside_fib->fib_index, &pfx);
326           if (FIB_NODE_INDEX_INVALID != fei)
327             {
328               if (fib_entry_get_resolving_interface (fei) != ~0)
329                 {
330                   s->out2in.fib_index = outside_fib->fib_index;
331                   break;
332                 }
333             }
334         }
335       /* *INDENT-ON* */
336       break;
337     }
338
339   /* Add to lookup tables */
340   kv->value = s - tsm->sessions;
341   ctx.now = now;
342   ctx.thread_index = thread_index;
343   if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, kv,
344                                                nat44_i2o_ed_is_idle_session_cb,
345                                                &ctx))
346     nat_elog_notice ("in2out-ed key add failed");
347
348   make_ed_kv (kv, &key1.addr, &key->r_addr, key->proto, s->out2in.fib_index,
349               key1.port, key->r_port);
350   kv->value = s - tsm->sessions;
351   if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->out2in_ed, kv,
352                                                nat44_o2i_ed_is_idle_session_cb,
353                                                &ctx))
354     nat_elog_notice ("out2in-ed key add failed");
355
356   *sessionp = s;
357
358   /* log NAT event */
359   snat_ipfix_logging_nat44_ses_create (thread_index,
360                                        s->in2out.addr.as_u32,
361                                        s->out2in.addr.as_u32,
362                                        s->in2out.protocol,
363                                        s->in2out.port,
364                                        s->out2in.port, s->in2out.fib_index);
365
366   nat_syslog_nat44_sadd (s->user_index, s->in2out.fib_index,
367                          &s->in2out.addr, s->in2out.port,
368                          &s->ext_host_nat_addr, s->ext_host_nat_port,
369                          &s->out2in.addr, s->out2in.port,
370                          &s->ext_host_addr, s->ext_host_port,
371                          s->in2out.protocol, 0);
372
373   nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
374                s->out2in.port, &s->ext_host_addr, s->ext_host_port,
375                &s->ext_host_nat_addr, s->ext_host_nat_port,
376                s->in2out.protocol, s->in2out.fib_index, s->flags,
377                thread_index, 0);
378
379   return next;
380 }
381
382 static_always_inline int
383 nat44_ed_not_translate (snat_main_t * sm, vlib_node_runtime_t * node,
384                         u32 sw_if_index, ip4_header_t * ip, u32 proto,
385                         u32 rx_fib_index, u32 thread_index)
386 {
387   udp_header_t *udp = ip4_next_header (ip);
388   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
389   clib_bihash_kv_16_8_t kv, value;
390   snat_session_key_t key0, key1;
391
392   make_ed_kv (&kv, &ip->dst_address, &ip->src_address, ip->protocol,
393               sm->outside_fib_index, udp->dst_port, udp->src_port);
394
395   /* NAT packet aimed at external address if */
396   /* has active sessions */
397   if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
398     {
399       key0.addr = ip->dst_address;
400       key0.port = udp->dst_port;
401       key0.protocol = proto;
402       key0.fib_index = sm->outside_fib_index;
403       /* or is static mappings */
404       if (!snat_static_mapping_match (sm, key0, &key1, 1, 0, 0, 0, 0, 0))
405         return 0;
406     }
407   else
408     return 0;
409
410   if (sm->forwarding_enabled)
411     return 1;
412
413   return snat_not_translate_fast (sm, node, sw_if_index, ip, proto,
414                                   rx_fib_index);
415 }
416
417 static_always_inline int
418 nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
419                                       u32 thread_index, f64 now,
420                                       vlib_main_t * vm, vlib_buffer_t * b)
421 {
422   nat_ed_ses_key_t key;
423   clib_bihash_kv_16_8_t kv, value;
424   snat_session_t *s = 0;
425   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
426
427   if (!sm->forwarding_enabled)
428     return 0;
429
430   if (ip->protocol == IP_PROTOCOL_ICMP)
431     {
432       key.as_u64[0] = key.as_u64[1] = 0;
433       if (get_icmp_i2o_ed_key (b, ip, &key))
434         return 0;
435       key.fib_index = 0;
436       kv.key[0] = key.as_u64[0];
437       kv.key[1] = key.as_u64[1];
438     }
439   else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
440     {
441       make_ed_kv (&kv, &ip->src_address, &ip->dst_address, ip->protocol, 0,
442                   vnet_buffer (b)->ip.reass.l4_src_port,
443                   vnet_buffer (b)->ip.reass.l4_dst_port);
444     }
445   else
446     {
447       make_ed_kv (&kv, &ip->src_address, &ip->dst_address, ip->protocol, 0, 0,
448                   0);
449     }
450
451   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
452     {
453       s = pool_elt_at_index (tsm->sessions, value.value);
454       if (is_fwd_bypass_session (s))
455         {
456           if (ip->protocol == IP_PROTOCOL_TCP)
457             {
458               if (nat44_set_tcp_session_state_i2o (sm, s, b, thread_index))
459                 return 1;
460             }
461           /* Accounting */
462           nat44_session_update_counters (s, now,
463                                          vlib_buffer_length_in_chain (vm, b),
464                                          thread_index);
465           /* Per-user LRU list maintenance */
466           nat44_session_update_lru (sm, s, thread_index);
467           return 1;
468         }
469       else
470         return 0;
471     }
472
473   return 0;
474 }
475
476 static_always_inline int
477 nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip,
478                                        u8 proto, u16 src_port, u16 dst_port,
479                                        u32 thread_index, u32 rx_sw_if_index,
480                                        u32 tx_sw_if_index)
481 {
482   clib_bihash_kv_16_8_t kv, value;
483   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
484   snat_interface_t *i;
485   snat_session_t *s;
486   u32 rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (rx_sw_if_index);
487   u32 tx_fib_index = ip4_fib_table_get_index_for_sw_if_index (tx_sw_if_index);
488
489   /* src NAT check */
490   make_ed_kv (&kv, &ip->src_address, &ip->dst_address, proto, tx_fib_index,
491               src_port, dst_port);
492   if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
493     {
494       s = pool_elt_at_index (tsm->sessions, value.value);
495       if (nat44_is_ses_closed (s))
496         {
497           nat_free_session_data (sm, s, thread_index, 0);
498           nat44_delete_session (sm, s, thread_index);
499         }
500       else
501         s->flags |= SNAT_SESSION_FLAG_OUTPUT_FEATURE;
502       return 1;
503     }
504
505   /* dst NAT check */
506   make_ed_kv (&kv, &ip->dst_address, &ip->src_address, proto, rx_fib_index,
507               dst_port, src_port);
508   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
509     {
510       s = pool_elt_at_index (tsm->sessions, value.value);
511       if (is_fwd_bypass_session (s))
512         return 0;
513
514       /* hairpinning */
515       /* *INDENT-OFF* */
516       pool_foreach (i, sm->output_feature_interfaces,
517       ({
518         if ((nat_interface_is_inside (i)) && (rx_sw_if_index == i->sw_if_index))
519            return 0;
520       }));
521       /* *INDENT-ON* */
522       return 1;
523     }
524
525   return 0;
526 }
527
528 #ifndef CLIB_MARCH_VARIANT
529 u32
530 icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node,
531                       u32 thread_index, vlib_buffer_t * b, ip4_header_t * ip,
532                       u8 * p_proto, snat_session_key_t * p_value,
533                       u8 * p_dont_translate, void *d, void *e)
534 {
535   u32 sw_if_index;
536   u32 rx_fib_index;
537   nat_ed_ses_key_t key;
538   snat_session_t *s = 0;
539   u8 dont_translate = 0;
540   clib_bihash_kv_16_8_t kv, value;
541   u32 next = ~0;
542   int err;
543   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
544
545   sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
546   rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
547
548   key.as_u64[0] = key.as_u64[1] = 0;
549   err = get_icmp_i2o_ed_key (b, ip, &key);
550   if (err != 0)
551     {
552       b->error = node->errors[err];
553       next = NAT_NEXT_DROP;
554       goto out;
555     }
556   key.fib_index = rx_fib_index;
557
558   kv.key[0] = key.as_u64[0];
559   kv.key[1] = key.as_u64[1];
560
561   if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
562     {
563       if (vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0)
564         {
565           if (PREDICT_FALSE
566               (nat44_ed_not_translate_output_feature
567                (sm, ip, key.proto, key.l_port, key.r_port, thread_index,
568                 sw_if_index, vnet_buffer (b)->sw_if_index[VLIB_TX])))
569             {
570               dont_translate = 1;
571               goto out;
572             }
573         }
574       else
575         {
576           if (PREDICT_FALSE (nat44_ed_not_translate (sm, node, sw_if_index,
577                                                      ip, SNAT_PROTOCOL_ICMP,
578                                                      rx_fib_index,
579                                                      thread_index)))
580             {
581               dont_translate = 1;
582               goto out;
583             }
584         }
585
586       if (PREDICT_FALSE
587           (icmp_type_is_error_message
588            (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)))
589         {
590           b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
591           next = NAT_NEXT_DROP;
592           goto out;
593         }
594
595       next = slow_path_ed (sm, b, rx_fib_index, &kv, &s, node, next,
596                            thread_index, vlib_time_now (sm->vlib_main));
597
598       if (PREDICT_FALSE (next == NAT_NEXT_DROP))
599         goto out;
600
601       if (!s)
602         {
603           dont_translate = 1;
604           goto out;
605         }
606     }
607   else
608     {
609       if (PREDICT_FALSE
610           (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
611            ICMP4_echo_request
612            && vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
613            ICMP4_echo_reply
614            && !icmp_type_is_error_message (vnet_buffer (b)->ip.
615                                            reass.icmp_type_or_tcp_flags)))
616         {
617           b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
618           next = NAT_NEXT_DROP;
619           goto out;
620         }
621
622       s = pool_elt_at_index (tsm->sessions, value.value);
623     }
624
625   *p_proto = ip_proto_to_snat_proto (key.proto);
626 out:
627   if (s)
628     *p_value = s->out2in;
629   *p_dont_translate = dont_translate;
630   if (d)
631     *(snat_session_t **) d = s;
632   return next;
633 }
634 #endif
635
636 static snat_session_t *
637 nat44_ed_in2out_unknown_proto (snat_main_t * sm,
638                                vlib_buffer_t * b,
639                                ip4_header_t * ip,
640                                u32 rx_fib_index,
641                                u32 thread_index,
642                                f64 now,
643                                vlib_main_t * vm, vlib_node_runtime_t * node)
644 {
645   clib_bihash_kv_8_8_t kv, value;
646   clib_bihash_kv_16_8_t s_kv, s_value;
647   snat_static_mapping_t *m;
648   u32 old_addr, new_addr = 0;
649   ip_csum_t sum;
650   snat_user_t *u;
651   dlist_elt_t *head, *elt;
652   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
653   u32 elt_index, head_index, ses_index;
654   snat_session_t *s;
655   u32 outside_fib_index = sm->outside_fib_index;
656   int i;
657   u8 is_sm = 0;
658   nat_outside_fib_t *outside_fib;
659   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
660   fib_prefix_t pfx = {
661     .fp_proto = FIB_PROTOCOL_IP4,
662     .fp_len = 32,
663     .fp_addr = {
664                 .ip4.as_u32 = ip->dst_address.as_u32,
665                 },
666   };
667
668   switch (vec_len (sm->outside_fibs))
669     {
670     case 0:
671       outside_fib_index = sm->outside_fib_index;
672       break;
673     case 1:
674       outside_fib_index = sm->outside_fibs[0].fib_index;
675       break;
676     default:
677       /* *INDENT-OFF* */
678       vec_foreach (outside_fib, sm->outside_fibs)
679         {
680           fei = fib_table_lookup (outside_fib->fib_index, &pfx);
681           if (FIB_NODE_INDEX_INVALID != fei)
682             {
683               if (fib_entry_get_resolving_interface (fei) != ~0)
684                 {
685                   outside_fib_index = outside_fib->fib_index;
686                   break;
687                 }
688             }
689         }
690       /* *INDENT-ON* */
691       break;
692     }
693   old_addr = ip->src_address.as_u32;
694
695   make_ed_kv (&s_kv, &ip->src_address, &ip->dst_address, ip->protocol,
696               rx_fib_index, 0, 0);
697
698   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &s_kv, &s_value))
699     {
700       s = pool_elt_at_index (tsm->sessions, s_value.value);
701       new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
702     }
703   else
704     {
705       if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
706         {
707           b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
708           nat_ipfix_logging_max_sessions (thread_index, sm->max_translations);
709           nat_elog_notice ("maximum sessions exceeded");
710           return 0;
711         }
712
713       u = nat_user_get_or_create (sm, &ip->src_address, rx_fib_index,
714                                   thread_index);
715       if (!u)
716         {
717           b->error = node->errors[NAT_IN2OUT_ED_ERROR_CANNOT_CREATE_USER];
718           nat_elog_warn ("create NAT user failed");
719           return 0;
720         }
721
722       make_sm_kv (&kv, &ip->src_address, 0, rx_fib_index, 0);
723
724       /* Try to find static mapping first */
725       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
726         {
727           m = pool_elt_at_index (sm->static_mappings, value.value);
728           new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
729           is_sm = 1;
730           goto create_ses;
731         }
732       /* Fallback to 3-tuple key */
733       else
734         {
735           /* Choose same out address as for TCP/UDP session to same destination */
736           head_index = u->sessions_per_user_list_head_index;
737           head = pool_elt_at_index (tsm->list_pool, head_index);
738           elt_index = head->next;
739           if (PREDICT_FALSE (elt_index == ~0))
740             ses_index = ~0;
741           else
742             {
743               elt = pool_elt_at_index (tsm->list_pool, elt_index);
744               ses_index = elt->value;
745             }
746
747           while (ses_index != ~0)
748             {
749               s = pool_elt_at_index (tsm->sessions, ses_index);
750               elt_index = elt->next;
751               elt = pool_elt_at_index (tsm->list_pool, elt_index);
752               ses_index = elt->value;
753
754               if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32)
755                 {
756                   new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
757
758                   make_ed_kv (&s_kv, &s->out2in.addr, &ip->dst_address,
759                               ip->protocol, outside_fib_index, 0, 0);
760                   if (clib_bihash_search_16_8
761                       (&tsm->out2in_ed, &s_kv, &s_value))
762                     goto create_ses;
763
764                   break;
765                 }
766             }
767
768           for (i = 0; i < vec_len (sm->addresses); i++)
769             {
770               make_ed_kv (&s_kv, &sm->addresses[i].addr, &ip->dst_address,
771                           ip->protocol, outside_fib_index, 0, 0);
772               if (clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
773                 {
774                   new_addr = ip->src_address.as_u32 =
775                     sm->addresses[i].addr.as_u32;
776                   goto create_ses;
777                 }
778             }
779           return 0;
780         }
781
782     create_ses:
783       s = nat_ed_session_alloc (sm, u, thread_index, now);
784       if (!s)
785         {
786           b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_USER_SESS_EXCEEDED];
787           nat44_delete_user_with_no_session (sm, u, thread_index);
788           nat_elog_warn ("create NAT session failed");
789           return 0;
790         }
791
792       s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
793       s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
794       s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
795       s->out2in.addr.as_u32 = new_addr;
796       s->out2in.fib_index = outside_fib_index;
797       s->in2out.addr.as_u32 = old_addr;
798       s->in2out.fib_index = rx_fib_index;
799       s->in2out.port = s->out2in.port = ip->protocol;
800       if (is_sm)
801         s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
802       user_session_increment (sm, u, is_sm);
803
804       /* Add to lookup tables */
805       make_ed_kv (&s_kv, &s->in2out.addr, &ip->dst_address, ip->protocol,
806                   rx_fib_index, 0, 0);
807       s_kv.value = s - tsm->sessions;
808       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
809         nat_elog_notice ("in2out key add failed");
810
811       make_ed_kv (&s_kv, &s->out2in.addr, &ip->dst_address, ip->protocol,
812                   outside_fib_index, 0, 0);
813       s_kv.value = s - tsm->sessions;
814       if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1))
815         nat_elog_notice ("out2in key add failed");
816     }
817
818   /* Update IP checksum */
819   sum = ip->checksum;
820   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
821   ip->checksum = ip_csum_fold (sum);
822
823   /* Accounting */
824   nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b),
825                                  thread_index);
826   /* Per-user LRU list maintenance */
827   nat44_session_update_lru (sm, s, thread_index);
828
829   /* Hairpinning */
830   if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
831     nat44_ed_hairpinning_unknown_proto (sm, b, ip);
832
833   if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
834     vnet_buffer (b)->sw_if_index[VLIB_TX] = outside_fib_index;
835
836   return s;
837 }
838
839 static inline uword
840 nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
841                                           vlib_node_runtime_t * node,
842                                           vlib_frame_t * frame,
843                                           int is_output_feature)
844 {
845   u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
846   nat_next_t next_index;
847   snat_main_t *sm = &snat_main;
848   f64 now = vlib_time_now (vm);
849   u32 thread_index = vm->thread_index;
850   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
851   u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
852     0, def_slow;
853
854   def_slow = is_output_feature ? NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH :
855     NAT_NEXT_IN2OUT_ED_SLOW_PATH;
856
857   stats_node_index = sm->ed_in2out_node_index;
858
859   from = vlib_frame_vector_args (frame);
860   n_left_from = frame->n_vectors;
861   next_index = node->cached_next_index;
862
863   while (n_left_from > 0)
864     {
865       u32 n_left_to_next;
866
867       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
868
869       while (n_left_from > 0 && n_left_to_next > 0)
870         {
871           u32 bi0;
872           vlib_buffer_t *b0;
873           u32 next0, sw_if_index0, rx_fib_index0, iph_offset0 = 0, proto0,
874             new_addr0, old_addr0;
875           u16 old_port0, new_port0;
876           ip4_header_t *ip0;
877           udp_header_t *udp0;
878           tcp_header_t *tcp0;
879           snat_session_t *s0 = 0;
880           clib_bihash_kv_16_8_t kv0, value0;
881           ip_csum_t sum0;
882
883           /* speculatively enqueue b0 to the current next frame */
884           bi0 = from[0];
885           to_next[0] = bi0;
886           from += 1;
887           to_next += 1;
888           n_left_from -= 1;
889           n_left_to_next -= 1;
890
891           b0 = vlib_get_buffer (vm, bi0);
892
893           if (is_output_feature)
894             {
895               vnet_feature_next (&nat_buffer_opaque (b0)->arc_next, b0);
896               iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
897             }
898
899           next0 = nat_buffer_opaque (b0)->arc_next;
900
901           ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
902                                   iph_offset0);
903
904           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
905           rx_fib_index0 =
906             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
907                                                  sw_if_index0);
908
909           if (PREDICT_FALSE (ip0->ttl == 1))
910             {
911               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
912               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
913                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
914                                            0);
915               next0 = NAT_NEXT_ICMP_ERROR;
916               goto trace0;
917             }
918
919           udp0 = ip4_next_header (ip0);
920           tcp0 = (tcp_header_t *) udp0;
921           proto0 = ip_proto_to_snat_proto (ip0->protocol);
922
923           if (PREDICT_FALSE (proto0 == ~0))
924             {
925               next0 = def_slow;
926               goto trace0;
927             }
928
929           if (is_output_feature)
930             {
931               if (PREDICT_FALSE (nat_not_translate_output_feature_fwd
932                                  (sm, ip0, thread_index, now, vm, b0)))
933                 goto trace0;
934             }
935
936           if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
937             {
938               next0 = def_slow;
939               goto trace0;
940             }
941
942           make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
943                       ip0->protocol, rx_fib_index0,
944                       vnet_buffer (b0)->ip.reass.l4_src_port,
945                       vnet_buffer (b0)->ip.reass.l4_dst_port);
946
947           // lookup for session
948           if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
949             {
950               // session does not exist go slow path
951               next0 = def_slow;
952               goto trace0;
953             }
954           s0 = pool_elt_at_index (tsm->sessions, value0.value);
955
956           // drop if session expired
957           u64 sess_timeout_time;
958           sess_timeout_time = s0->last_heard +
959             (f64) nat44_session_get_timeout (sm, s0);
960           if (now >= sess_timeout_time)
961             {
962               // delete session
963               nat_free_session_data (sm, s0, thread_index, 0);
964               nat44_delete_session (sm, s0, thread_index);
965
966               b0->error = node->errors[NAT_IN2OUT_ED_ERROR_SESS_EXPIRED];
967               next0 = NAT_NEXT_DROP;
968               goto trace0;
969             }
970           //
971
972           b0->flags |= VNET_BUFFER_F_IS_NATED;
973
974           if (!is_output_feature)
975             vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
976
977           old_addr0 = ip0->src_address.as_u32;
978           new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
979           sum0 = ip0->checksum;
980           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
981                                  src_address);
982           if (PREDICT_FALSE (is_twice_nat_session (s0)))
983             sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
984                                    s0->ext_host_addr.as_u32, ip4_header_t,
985                                    dst_address);
986           ip0->checksum = ip_csum_fold (sum0);
987
988           old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
989
990           if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
991             {
992               if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
993                 {
994                   new_port0 = udp0->src_port = s0->out2in.port;
995                   sum0 = tcp0->checksum;
996                   sum0 =
997                     ip_csum_update (sum0, old_addr0, new_addr0,
998                                     ip4_header_t, dst_address);
999                   sum0 =
1000                     ip_csum_update (sum0, old_port0, new_port0,
1001                                     ip4_header_t, length);
1002                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
1003                     {
1004                       sum0 =
1005                         ip_csum_update (sum0, ip0->dst_address.as_u32,
1006                                         s0->ext_host_addr.as_u32,
1007                                         ip4_header_t, dst_address);
1008                       sum0 =
1009                         ip_csum_update (sum0,
1010                                         vnet_buffer (b0)->ip.
1011                                         reass.l4_dst_port, s0->ext_host_port,
1012                                         ip4_header_t, length);
1013                       tcp0->dst_port = s0->ext_host_port;
1014                       ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1015                     }
1016                   mss_clamping (sm, tcp0, &sum0);
1017                   tcp0->checksum = ip_csum_fold (sum0);
1018                 }
1019               tcp_packets++;
1020               if (nat44_set_tcp_session_state_i2o (sm, s0, b0, thread_index))
1021                 goto trace0;
1022             }
1023           else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
1024                    && udp0->checksum)
1025             {
1026               new_port0 = udp0->src_port = s0->out2in.port;
1027               sum0 = udp0->checksum;
1028               sum0 =
1029                 ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1030                                 dst_address);
1031               sum0 =
1032                 ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1033                                 length);
1034               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1035                 {
1036                   sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1037                                          s0->ext_host_addr.as_u32,
1038                                          ip4_header_t, dst_address);
1039                   sum0 =
1040                     ip_csum_update (sum0,
1041                                     vnet_buffer (b0)->ip.reass.l4_dst_port,
1042                                     s0->ext_host_port, ip4_header_t, length);
1043                   udp0->dst_port = s0->ext_host_port;
1044                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1045                 }
1046               udp0->checksum = ip_csum_fold (sum0);
1047               udp_packets++;
1048             }
1049           else
1050             {
1051               if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1052                 {
1053                   new_port0 = udp0->src_port = s0->out2in.port;
1054                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
1055                     {
1056                       udp0->dst_port = s0->ext_host_port;
1057                       ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1058                     }
1059                   udp_packets++;
1060                 }
1061             }
1062
1063           /* Accounting */
1064           nat44_session_update_counters (s0, now,
1065                                          vlib_buffer_length_in_chain
1066                                          (vm, b0), thread_index);
1067           /* Per-user LRU list maintenance */
1068           nat44_session_update_lru (sm, s0, thread_index);
1069
1070         trace0:
1071           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1072                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1073             {
1074               nat_in2out_ed_trace_t *t =
1075                 vlib_add_trace (vm, node, b0, sizeof (*t));
1076               t->sw_if_index = sw_if_index0;
1077               t->next_index = next0;
1078               t->is_slow_path = 0;
1079
1080               if (s0)
1081                 t->session_index = s0 - tsm->sessions;
1082               else
1083                 t->session_index = ~0;
1084             }
1085
1086           pkts_processed += next0 == nat_buffer_opaque (b0)->arc_next;
1087           /* verify speculative enqueue, maybe switch current next frame */
1088           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1089                                            to_next, n_left_to_next,
1090                                            bi0, next0);
1091         }
1092
1093       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1094     }
1095
1096   vlib_node_increment_counter (vm, stats_node_index,
1097                                NAT_IN2OUT_ED_ERROR_IN2OUT_PACKETS,
1098                                pkts_processed);
1099   vlib_node_increment_counter (vm, stats_node_index,
1100                                NAT_IN2OUT_ED_ERROR_TCP_PACKETS, tcp_packets);
1101   vlib_node_increment_counter (vm, stats_node_index,
1102                                NAT_IN2OUT_ED_ERROR_UDP_PACKETS, udp_packets);
1103   vlib_node_increment_counter (vm, stats_node_index,
1104                                NAT_IN2OUT_ED_ERROR_ICMP_PACKETS,
1105                                icmp_packets);
1106   vlib_node_increment_counter (vm, stats_node_index,
1107                                NAT_IN2OUT_ED_ERROR_OTHER_PACKETS,
1108                                other_packets);
1109   return frame->n_vectors;
1110 }
1111
1112 static inline uword
1113 nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm,
1114                                           vlib_node_runtime_t * node,
1115                                           vlib_frame_t * frame,
1116                                           int is_output_feature)
1117 {
1118   u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
1119   nat_next_t next_index;
1120   snat_main_t *sm = &snat_main;
1121   f64 now = vlib_time_now (vm);
1122   u32 thread_index = vm->thread_index;
1123   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1124   u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets = 0;
1125
1126   stats_node_index = sm->ed_in2out_slowpath_node_index;
1127
1128   from = vlib_frame_vector_args (frame);
1129   n_left_from = frame->n_vectors;
1130   next_index = node->cached_next_index;
1131
1132   while (n_left_from > 0)
1133     {
1134       u32 n_left_to_next;
1135
1136       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1137
1138       while (n_left_from > 0 && n_left_to_next > 0)
1139         {
1140           u32 bi0;
1141           vlib_buffer_t *b0;
1142           u32 next0, sw_if_index0, rx_fib_index0, iph_offset0 = 0, proto0,
1143             new_addr0, old_addr0;
1144           u16 old_port0, new_port0;
1145           ip4_header_t *ip0;
1146           udp_header_t *udp0;
1147           tcp_header_t *tcp0;
1148           icmp46_header_t *icmp0;
1149           snat_session_t *s0 = 0;
1150           clib_bihash_kv_16_8_t kv0, value0;
1151           ip_csum_t sum0;
1152
1153           /* speculatively enqueue b0 to the current next frame */
1154           bi0 = from[0];
1155           to_next[0] = bi0;
1156           from += 1;
1157           to_next += 1;
1158           n_left_from -= 1;
1159           n_left_to_next -= 1;
1160
1161           b0 = vlib_get_buffer (vm, bi0);
1162
1163           if (is_output_feature)
1164             iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
1165
1166           next0 = nat_buffer_opaque (b0)->arc_next;
1167
1168           ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1169                                   iph_offset0);
1170
1171           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1172           rx_fib_index0 =
1173             fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1174                                                  sw_if_index0);
1175
1176           if (PREDICT_FALSE (ip0->ttl == 1))
1177             {
1178               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1179               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1180                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1181                                            0);
1182               next0 = NAT_NEXT_ICMP_ERROR;
1183               goto trace0;
1184             }
1185
1186           udp0 = ip4_next_header (ip0);
1187           tcp0 = (tcp_header_t *) udp0;
1188           icmp0 = (icmp46_header_t *) udp0;
1189           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1190
1191           if (PREDICT_FALSE (proto0 == ~0))
1192             {
1193               s0 = nat44_ed_in2out_unknown_proto (sm, b0, ip0,
1194                                                   rx_fib_index0,
1195                                                   thread_index, now,
1196                                                   vm, node);
1197               if (!s0)
1198                 next0 = NAT_NEXT_DROP;
1199
1200               other_packets++;
1201               goto trace0;
1202             }
1203
1204           if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1205             {
1206               next0 = icmp_in2out_ed_slow_path
1207                 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
1208                  node, next0, now, thread_index, &s0);
1209               icmp_packets++;
1210               goto trace0;
1211             }
1212
1213           // move down
1214           make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
1215                       ip0->protocol, rx_fib_index0,
1216                       vnet_buffer (b0)->ip.reass.l4_src_port,
1217                       vnet_buffer (b0)->ip.reass.l4_dst_port);
1218
1219           if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
1220             {
1221
1222               if (is_output_feature)
1223                 {
1224                   if (PREDICT_FALSE
1225                       (nat44_ed_not_translate_output_feature
1226                        (sm, ip0, ip0->protocol,
1227                         vnet_buffer (b0)->ip.reass.l4_src_port,
1228                         vnet_buffer (b0)->ip.reass.l4_dst_port,
1229                         thread_index, sw_if_index0,
1230                         vnet_buffer (b0)->sw_if_index[VLIB_TX])))
1231                     goto trace0;
1232
1233                   /*
1234                    * Send DHCP packets to the ipv4 stack, or we won't
1235                    * be able to use dhcp client on the outside interface
1236                    */
1237                   if (PREDICT_FALSE
1238                       (proto0 == SNAT_PROTOCOL_UDP
1239                        && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1240                            clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_server))
1241                        && ip0->dst_address.as_u32 == 0xffffffff))
1242                     goto trace0;
1243                 }
1244               else
1245                 {
1246                   if (PREDICT_FALSE
1247                       (nat44_ed_not_translate
1248                        (sm, node, sw_if_index0, ip0, proto0, rx_fib_index0,
1249                         thread_index)))
1250                     goto trace0;
1251                 }
1252
1253               next0 = slow_path_ed (sm, b0, rx_fib_index0, &kv0, &s0, node,
1254                                     next0, thread_index, now);
1255
1256               if (PREDICT_FALSE (next0 == NAT_NEXT_DROP))
1257                 goto trace0;
1258
1259               if (PREDICT_FALSE (!s0))
1260                 goto trace0;
1261
1262             }
1263           else
1264             {
1265               s0 = pool_elt_at_index (tsm->sessions, value0.value);
1266             }
1267
1268
1269           b0->flags |= VNET_BUFFER_F_IS_NATED;
1270
1271           if (!is_output_feature)
1272             vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1273
1274           old_addr0 = ip0->src_address.as_u32;
1275           new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
1276           sum0 = ip0->checksum;
1277           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1278                                  src_address);
1279           if (PREDICT_FALSE (is_twice_nat_session (s0)))
1280             sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1281                                    s0->ext_host_addr.as_u32, ip4_header_t,
1282                                    dst_address);
1283           ip0->checksum = ip_csum_fold (sum0);
1284
1285           old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1286
1287           if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1288             {
1289               if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1290                 {
1291                   new_port0 = udp0->src_port = s0->out2in.port;
1292                   sum0 = tcp0->checksum;
1293                   sum0 =
1294                     ip_csum_update (sum0, old_addr0, new_addr0,
1295                                     ip4_header_t, dst_address);
1296                   sum0 =
1297                     ip_csum_update (sum0, old_port0, new_port0,
1298                                     ip4_header_t, length);
1299                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
1300                     {
1301                       sum0 =
1302                         ip_csum_update (sum0, ip0->dst_address.as_u32,
1303                                         s0->ext_host_addr.as_u32,
1304                                         ip4_header_t, dst_address);
1305                       sum0 =
1306                         ip_csum_update (sum0,
1307                                         vnet_buffer (b0)->ip.
1308                                         reass.l4_dst_port, s0->ext_host_port,
1309                                         ip4_header_t, length);
1310                       tcp0->dst_port = s0->ext_host_port;
1311                       ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1312                     }
1313                   mss_clamping (sm, tcp0, &sum0);
1314                   tcp0->checksum = ip_csum_fold (sum0);
1315                 }
1316               tcp_packets++;
1317               if (nat44_set_tcp_session_state_i2o (sm, s0, b0, thread_index))
1318                 goto trace0;
1319             }
1320           else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
1321                    && udp0->checksum)
1322             {
1323               new_port0 = udp0->src_port = s0->out2in.port;
1324               sum0 = udp0->checksum;
1325               sum0 =
1326                 ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1327                                 dst_address);
1328               sum0 =
1329                 ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1330                                 length);
1331               if (PREDICT_FALSE (is_twice_nat_session (s0)))
1332                 {
1333                   sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1334                                          s0->ext_host_addr.as_u32,
1335                                          ip4_header_t, dst_address);
1336                   sum0 =
1337                     ip_csum_update (sum0,
1338                                     vnet_buffer (b0)->ip.reass.l4_dst_port,
1339                                     s0->ext_host_port, ip4_header_t, length);
1340                   udp0->dst_port = s0->ext_host_port;
1341                   ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1342                 }
1343               udp0->checksum = ip_csum_fold (sum0);
1344               udp_packets++;
1345             }
1346           else
1347             {
1348               if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1349                 {
1350                   new_port0 = udp0->src_port = s0->out2in.port;
1351                   if (PREDICT_FALSE (is_twice_nat_session (s0)))
1352                     {
1353                       udp0->dst_port = s0->ext_host_port;
1354                       ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1355                     }
1356                   udp_packets++;
1357                 }
1358             }
1359
1360           /* Accounting */
1361           nat44_session_update_counters (s0, now,
1362                                          vlib_buffer_length_in_chain
1363                                          (vm, b0), thread_index);
1364           /* Per-user LRU list maintenance */
1365           nat44_session_update_lru (sm, s0, thread_index);
1366
1367         trace0:
1368           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1369                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1370             {
1371               nat_in2out_ed_trace_t *t =
1372                 vlib_add_trace (vm, node, b0, sizeof (*t));
1373               t->sw_if_index = sw_if_index0;
1374               t->next_index = next0;
1375               t->is_slow_path = 1;
1376
1377               if (s0)
1378                 t->session_index = s0 - tsm->sessions;
1379               else
1380                 t->session_index = ~0;
1381             }
1382
1383           pkts_processed += next0 == nat_buffer_opaque (b0)->arc_next;
1384
1385           /* verify speculative enqueue, maybe switch current next frame */
1386           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1387                                            to_next, n_left_to_next,
1388                                            bi0, next0);
1389         }
1390
1391       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1392     }
1393
1394   vlib_node_increment_counter (vm, stats_node_index,
1395                                NAT_IN2OUT_ED_ERROR_IN2OUT_PACKETS,
1396                                pkts_processed);
1397   vlib_node_increment_counter (vm, stats_node_index,
1398                                NAT_IN2OUT_ED_ERROR_TCP_PACKETS, tcp_packets);
1399   vlib_node_increment_counter (vm, stats_node_index,
1400                                NAT_IN2OUT_ED_ERROR_UDP_PACKETS, udp_packets);
1401   vlib_node_increment_counter (vm, stats_node_index,
1402                                NAT_IN2OUT_ED_ERROR_ICMP_PACKETS,
1403                                icmp_packets);
1404   vlib_node_increment_counter (vm, stats_node_index,
1405                                NAT_IN2OUT_ED_ERROR_OTHER_PACKETS,
1406                                other_packets);
1407   return frame->n_vectors;
1408 }
1409
1410 VLIB_NODE_FN (nat44_ed_in2out_node) (vlib_main_t * vm,
1411                                      vlib_node_runtime_t * node,
1412                                      vlib_frame_t * frame)
1413 {
1414   return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 0);
1415 }
1416
1417 /* *INDENT-OFF* */
1418 VLIB_REGISTER_NODE (nat44_ed_in2out_node) = {
1419   .name = "nat44-ed-in2out",
1420   .vector_size = sizeof (u32),
1421   .sibling_of = "nat-default",
1422   .format_trace = format_nat_in2out_ed_trace,
1423   .type = VLIB_NODE_TYPE_INTERNAL,
1424   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1425   .error_strings = nat_in2out_ed_error_strings,
1426   .runtime_data_bytes = sizeof (snat_runtime_t),
1427 };
1428 /* *INDENT-ON* */
1429
1430 VLIB_NODE_FN (nat44_ed_in2out_output_node) (vlib_main_t * vm,
1431                                             vlib_node_runtime_t * node,
1432                                             vlib_frame_t * frame)
1433 {
1434   return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 1);
1435 }
1436
1437 /* *INDENT-OFF* */
1438 VLIB_REGISTER_NODE (nat44_ed_in2out_output_node) = {
1439   .name = "nat44-ed-in2out-output",
1440   .vector_size = sizeof (u32),
1441   .sibling_of = "nat-default",
1442   .format_trace = format_nat_in2out_ed_trace,
1443   .type = VLIB_NODE_TYPE_INTERNAL,
1444   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1445   .error_strings = nat_in2out_ed_error_strings,
1446   .runtime_data_bytes = sizeof (snat_runtime_t),
1447 };
1448 /* *INDENT-ON* */
1449
1450 VLIB_NODE_FN (nat44_ed_in2out_slowpath_node) (vlib_main_t * vm,
1451                                               vlib_node_runtime_t *
1452                                               node, vlib_frame_t * frame)
1453 {
1454   return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 0);
1455 }
1456
1457 /* *INDENT-OFF* */
1458 VLIB_REGISTER_NODE (nat44_ed_in2out_slowpath_node) = {
1459   .name = "nat44-ed-in2out-slowpath",
1460   .vector_size = sizeof (u32),
1461   .sibling_of = "nat-default",
1462   .format_trace = format_nat_in2out_ed_trace,
1463   .type = VLIB_NODE_TYPE_INTERNAL,
1464   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1465   .error_strings = nat_in2out_ed_error_strings,
1466   .runtime_data_bytes = sizeof (snat_runtime_t),
1467 };
1468 /* *INDENT-ON* */
1469
1470 VLIB_NODE_FN (nat44_ed_in2out_output_slowpath_node) (vlib_main_t * vm,
1471                                                      vlib_node_runtime_t
1472                                                      * node,
1473                                                      vlib_frame_t * frame)
1474 {
1475   return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 1);
1476 }
1477
1478 /* *INDENT-OFF* */
1479 VLIB_REGISTER_NODE (nat44_ed_in2out_output_slowpath_node) = {
1480   .name = "nat44-ed-in2out-output-slowpath",
1481   .vector_size = sizeof (u32),
1482   .sibling_of = "nat-default",
1483   .format_trace = format_nat_in2out_ed_trace,
1484   .type = VLIB_NODE_TYPE_INTERNAL,
1485   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1486   .error_strings = nat_in2out_ed_error_strings,
1487   .runtime_data_bytes = sizeof (snat_runtime_t),
1488 };
1489 /* *INDENT-ON* */
1490
1491 static u8 *
1492 format_nat_pre_trace (u8 * s, va_list * args)
1493 {
1494   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1495   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1496   nat_pre_trace_t *t = va_arg (*args, nat_pre_trace_t *);
1497   return format (s, "in2out next_index %d", t->next_index);
1498 }
1499
1500 VLIB_NODE_FN (nat_pre_in2out_node)
1501   (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1502 {
1503   return nat_pre_node_fn_inline (vm, node, frame,
1504                                  NAT_NEXT_IN2OUT_ED_FAST_PATH);
1505 }
1506
1507 /* *INDENT-OFF* */
1508 VLIB_REGISTER_NODE (nat_pre_in2out_node) = {
1509   .name = "nat-pre-in2out",
1510   .vector_size = sizeof (u32),
1511   .sibling_of = "nat-default",
1512   .format_trace = format_nat_pre_trace,
1513   .type = VLIB_NODE_TYPE_INTERNAL,
1514   .n_errors = 0,
1515 };
1516 /* *INDENT-ON* */
1517
1518 /*
1519  * fd.io coding-style-patch-verification: ON
1520  *
1521  * Local Variables:
1522  * eval: (c-set-style "gnu")
1523  * End:
1524  */