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