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