nat: nat44-ei hairpinning code cleanup
[vpp.git] / src / plugins / nat / nat44-ei / nat44_ei_out2in.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 outside to inside 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/nat44-ei/nat44_ei_inlines.h>
35 #include <nat/nat44-ei/nat44_ei.h>
36
37 typedef struct
38 {
39   u32 sw_if_index;
40   u32 next_index;
41   u32 session_index;
42 } nat44_ei_out2in_trace_t;
43
44 /* packet trace format function */
45 static u8 *
46 format_nat44_ei_out2in_trace (u8 *s, va_list *args)
47 {
48   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
49   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
50   nat44_ei_out2in_trace_t *t = va_arg (*args, nat44_ei_out2in_trace_t *);
51
52   s =
53     format (s,
54             "NAT44_OUT2IN: sw_if_index %d, next index %d, session index %d",
55             t->sw_if_index, t->next_index, t->session_index);
56   return s;
57 }
58
59 #define foreach_nat44_ei_out2in_error                                         \
60   _ (UNSUPPORTED_PROTOCOL, "unsupported protocol")                            \
61   _ (OUT_OF_PORTS, "out of ports")                                            \
62   _ (BAD_ICMP_TYPE, "unsupported ICMP type")                                  \
63   _ (NO_TRANSLATION, "no translation")                                        \
64   _ (MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded")                      \
65   _ (CANNOT_CREATE_USER, "cannot create NAT user")
66
67 typedef enum
68 {
69 #define _(sym, str) NAT44_EI_OUT2IN_ERROR_##sym,
70   foreach_nat44_ei_out2in_error
71 #undef _
72     NAT44_EI_OUT2IN_N_ERROR,
73 } nat44_ei_out2in_error_t;
74
75 static char *nat44_ei_out2in_error_strings[] = {
76 #define _(sym,string) string,
77   foreach_nat44_ei_out2in_error
78 #undef _
79 };
80
81 typedef enum
82 {
83   NAT44_EI_OUT2IN_NEXT_DROP,
84   NAT44_EI_OUT2IN_NEXT_LOOKUP,
85   NAT44_EI_OUT2IN_NEXT_ICMP_ERROR,
86   NAT44_EI_OUT2IN_N_NEXT,
87 } nat44_ei_out2in_next_t;
88
89 #ifndef CLIB_MARCH_VARIANT
90 int
91 nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
92 {
93   nat44_ei_main_t *nm = &nat44_ei_main;
94   nat44_ei_is_idle_session_ctx_t *ctx = arg;
95   nat44_ei_session_t *s;
96   u64 sess_timeout_time;
97   nat44_ei_main_per_thread_data_t *tnm =
98     vec_elt_at_index (nm->per_thread_data, ctx->thread_index);
99   clib_bihash_kv_8_8_t s_kv;
100
101   if (ctx->thread_index != nat_value_get_thread_index (kv))
102     {
103       return 0;
104     }
105
106   s = pool_elt_at_index (tnm->sessions, nat_value_get_session_index (kv));
107   sess_timeout_time = s->last_heard + (f64) nat_session_get_timeout (
108                                         &nm->timeouts, s->nat_proto, s->state);
109   if (ctx->now >= sess_timeout_time)
110     {
111       init_nat_i2o_k (&s_kv, s);
112       if (clib_bihash_add_del_8_8 (&nm->in2out, &s_kv, 0))
113         nat_elog_warn (nm, "out2in key del failed");
114
115       nat_ipfix_logging_nat44_ses_delete (
116         ctx->thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
117         nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
118         s->in2out.fib_index);
119
120       nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
121                                &s->in2out.addr, s->in2out.port,
122                                &s->out2in.addr, s->out2in.port, s->nat_proto);
123
124       nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
125                    s->ext_host_port, s->nat_proto, s->out2in.fib_index,
126                    ctx->thread_index);
127
128       if (!nat44_ei_is_session_static (s))
129         nat44_ei_free_outside_address_and_port (
130           nm->addresses, ctx->thread_index, &s->out2in.addr, s->out2in.port,
131           s->nat_proto);
132
133       nat44_ei_delete_session (nm, s, ctx->thread_index);
134       return 1;
135     }
136
137   return 0;
138 }
139 #endif
140
141 /**
142  * @brief Create session for static mapping.
143  *
144  * Create NAT session initiated by host from external network with static
145  * mapping.
146  *
147  * @param nm     NAT main.
148  * @param b0     Vlib buffer.
149  * @param in2out In2out NAT44 session key.
150  * @param out2in Out2in NAT44 session key.
151  * @param node   Vlib node.
152  *
153  * @returns NAT44_EI session if successfully created otherwise 0.
154  */
155 static inline nat44_ei_session_t *
156 create_session_for_static_mapping (
157   nat44_ei_main_t *nm, vlib_buffer_t *b0, ip4_address_t i2o_addr, u16 i2o_port,
158   u32 i2o_fib_index, ip4_address_t o2i_addr, u16 o2i_port, u32 o2i_fib_index,
159   nat_protocol_t proto, vlib_node_runtime_t *node, u32 thread_index, f64 now)
160 {
161   nat44_ei_user_t *u;
162   nat44_ei_session_t *s;
163   clib_bihash_kv_8_8_t kv0;
164   ip4_header_t *ip0;
165   udp_header_t *udp0;
166   nat44_ei_is_idle_session_ctx_t ctx0;
167
168   if (PREDICT_FALSE (nat44_ei_maximum_sessions_exceeded (nm, thread_index)))
169     {
170       b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
171       nat_elog_notice (nm, "maximum sessions exceeded");
172       return 0;
173     }
174
175   ip0 = vlib_buffer_get_current (b0);
176   udp0 = ip4_next_header (ip0);
177
178   u = nat44_ei_user_get_or_create (nm, &i2o_addr, i2o_fib_index, thread_index);
179   if (!u)
180     {
181       b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_CANNOT_CREATE_USER];
182       return 0;
183     }
184
185   s = nat44_ei_session_alloc_or_recycle (nm, u, thread_index, now);
186   if (!s)
187     {
188       nat44_ei_delete_user_with_no_session (nm, u, thread_index);
189       nat_elog_warn (nm, "create NAT session failed");
190       return 0;
191     }
192
193   s->flags |= NAT44_EI_SESSION_FLAG_STATIC_MAPPING;
194   s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
195   s->ext_host_port = udp0->src_port;
196   nat44_ei_user_session_increment (nm, u, 1 /* static */);
197   s->in2out.addr = i2o_addr;
198   s->in2out.port = i2o_port;
199   s->in2out.fib_index = i2o_fib_index;
200   s->out2in.addr = o2i_addr;
201   s->out2in.port = o2i_port;
202   s->out2in.fib_index = o2i_fib_index;
203   s->nat_proto = proto;
204
205   /* Add to translation hashes */
206   ctx0.now = now;
207   ctx0.thread_index = thread_index;
208   init_nat_i2o_kv (&kv0, s, thread_index,
209                    s - nm->per_thread_data[thread_index].sessions);
210   if (clib_bihash_add_or_overwrite_stale_8_8 (
211         &nm->in2out, &kv0, nat44_i2o_is_idle_session_cb, &ctx0))
212     nat_elog_notice (nm, "in2out key add failed");
213
214   init_nat_o2i_kv (&kv0, s, thread_index,
215                    s - nm->per_thread_data[thread_index].sessions);
216   if (clib_bihash_add_or_overwrite_stale_8_8 (
217         &nm->out2in, &kv0, nat44_o2i_is_idle_session_cb, &ctx0))
218     nat_elog_notice (nm, "out2in key add failed");
219
220   /* log NAT event */
221   nat_ipfix_logging_nat44_ses_create (
222     thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
223     nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
224     s->in2out.fib_index);
225
226   nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index,
227                            &s->in2out.addr, s->in2out.port, &s->out2in.addr,
228                            s->out2in.port, s->nat_proto);
229
230   nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
231                s->out2in.port, &s->ext_host_addr, s->ext_host_port,
232                &s->ext_host_nat_addr, s->ext_host_nat_port,
233                s->nat_proto, s->in2out.fib_index, s->flags, thread_index, 0);
234
235   return s;
236 }
237
238 #ifndef CLIB_MARCH_VARIANT
239 static_always_inline nat44_ei_out2in_error_t
240 icmp_get_key (vlib_buffer_t *b, ip4_header_t *ip0, ip4_address_t *addr,
241               u16 *port, nat_protocol_t *nat_proto)
242 {
243   icmp46_header_t *icmp0;
244   icmp_echo_header_t *echo0, *inner_echo0 = 0;
245   ip4_header_t *inner_ip0;
246   void *l4_header = 0;
247   icmp46_header_t *inner_icmp0;
248
249   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
250   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
251
252   if (!icmp_type_is_error_message
253       (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
254     {
255       *nat_proto = NAT_PROTOCOL_ICMP;
256       *addr = ip0->dst_address;
257       *port = vnet_buffer (b)->ip.reass.l4_src_port;
258     }
259   else
260     {
261       inner_ip0 = (ip4_header_t *) (echo0 + 1);
262       l4_header = ip4_next_header (inner_ip0);
263       *nat_proto = ip_proto_to_nat_proto (inner_ip0->protocol);
264       *addr = inner_ip0->src_address;
265       switch (*nat_proto)
266         {
267         case NAT_PROTOCOL_ICMP:
268           inner_icmp0 = (icmp46_header_t *) l4_header;
269           inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
270           *port = inner_echo0->identifier;
271           break;
272         case NAT_PROTOCOL_UDP:
273         case NAT_PROTOCOL_TCP:
274           *port = ((tcp_udp_header_t *) l4_header)->src_port;
275           break;
276         default:
277           return NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
278         }
279     }
280   return -1;                    /* success */
281 }
282
283 /**
284  * Get address and port values to be used for ICMP packet translation
285  * and create session if needed
286  *
287  * @param[in,out] nm             NAT main
288  * @param[in,out] node           NAT node runtime
289  * @param[in] thread_index       thread index
290  * @param[in,out] b0             buffer containing packet to be translated
291  * @param[in,out] ip0            ip header
292  * @param[out] p_proto           protocol used for matching
293  * @param[out] p_value           address and port after NAT translation
294  * @param[out] p_dont_translate  if packet should not be translated
295  * @param d                      optional parameter
296  * @param e                      optional parameter
297  */
298 u32
299 nat44_ei_icmp_match_out2in_slow (vlib_node_runtime_t *node, u32 thread_index,
300                                  vlib_buffer_t *b0, ip4_header_t *ip0,
301                                  ip4_address_t *addr, u16 *port,
302                                  u32 *fib_index, nat_protocol_t *proto,
303                                  nat44_ei_session_t **p_s0, u8 *dont_translate)
304 {
305   nat44_ei_main_t *nm = &nat44_ei_main;
306   nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
307   u32 sw_if_index0;
308   nat44_ei_session_t *s0 = 0;
309   clib_bihash_kv_8_8_t kv0, value0;
310   u8 is_addr_only;
311   u32 next0 = ~0;
312   int err;
313   u8 identity_nat;
314   vlib_main_t *vm = vlib_get_main ();
315   *dont_translate = 0;
316
317   sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
318   *fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
319
320   *proto = 0;
321
322   err = icmp_get_key (b0, ip0, addr, port, proto);
323   if (err != -1)
324     {
325       b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
326       next0 = NAT44_EI_OUT2IN_NEXT_DROP;
327       goto out;
328     }
329
330   ip4_address_t mapping_addr;
331   u16 mapping_port;
332   u32 mapping_fib_index;
333
334   init_nat_k (&kv0, *addr, *port, *fib_index, *proto);
335   if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
336     {
337       /* Try to match static mapping by external address and port,
338          destination address and port in packet */
339       if (nat44_ei_static_mapping_match (
340             *addr, *port, *fib_index, *proto, &mapping_addr, &mapping_port,
341             &mapping_fib_index, 1, &is_addr_only, &identity_nat))
342         {
343           if (!nm->forwarding_enabled)
344             {
345               /* Don't NAT packet aimed at the intfc address */
346               if (PREDICT_FALSE (nat44_ei_is_interface_addr (
347                     nm->ip4_main, node, sw_if_index0,
348                     ip0->dst_address.as_u32)))
349                 {
350                   *dont_translate = 1;
351                   goto out;
352                 }
353               b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
354               next0 = NAT44_EI_OUT2IN_NEXT_DROP;
355               goto out;
356             }
357           else
358             {
359               *dont_translate = 1;
360               goto out;
361             }
362         }
363
364       if (PREDICT_FALSE
365           (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
366            ICMP4_echo_reply
367            && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
368                ICMP4_echo_request || !is_addr_only)))
369         {
370           b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
371           next0 = NAT44_EI_OUT2IN_NEXT_DROP;
372           goto out;
373         }
374
375       if (PREDICT_FALSE (identity_nat))
376         {
377           *dont_translate = 1;
378           goto out;
379         }
380       /* Create session initiated by host from external network */
381       s0 = create_session_for_static_mapping (
382         nm, b0, mapping_addr, mapping_port, mapping_fib_index, *addr, *port,
383         *fib_index, *proto, node, thread_index, vlib_time_now (vm));
384
385       if (!s0)
386         {
387           next0 = NAT44_EI_OUT2IN_NEXT_DROP;
388           goto out;
389         }
390     }
391   else
392     {
393       if (PREDICT_FALSE
394           (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
395            ICMP4_echo_reply
396            && vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
397            ICMP4_echo_request
398            && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
399                                            reass.icmp_type_or_tcp_flags)))
400         {
401           b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
402           next0 = NAT44_EI_OUT2IN_NEXT_DROP;
403           goto out;
404         }
405
406       s0 = pool_elt_at_index (tnm->sessions,
407                               nat_value_get_session_index (&value0));
408     }
409
410 out:
411   if (s0)
412     {
413       *addr = s0->in2out.addr;
414       *port = s0->in2out.port;
415       *fib_index = s0->in2out.fib_index;
416     }
417   if (p_s0)
418     *p_s0 = s0;
419   return next0;
420 }
421 #endif
422
423 #ifndef CLIB_MARCH_VARIANT
424 u32
425 nat44_ei_icmp_match_out2in_fast (vlib_node_runtime_t *node, u32 thread_index,
426                                  vlib_buffer_t *b0, ip4_header_t *ip0,
427                                  ip4_address_t *mapping_addr,
428                                  u16 *mapping_port, u32 *mapping_fib_index,
429                                  nat_protocol_t *proto,
430                                  nat44_ei_session_t **p_s0, u8 *dont_translate)
431 {
432   nat44_ei_main_t *nm = &nat44_ei_main;
433   u32 sw_if_index0;
434   u32 rx_fib_index0;
435   u8 is_addr_only;
436   u32 next0 = ~0;
437   int err;
438   ip4_address_t addr;
439   u16 port;
440   *dont_translate = 0;
441
442   sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
443   rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
444
445   err = icmp_get_key (b0, ip0, &addr, &port, proto);
446   if (err != -1)
447     {
448       b0->error = node->errors[err];
449       next0 = NAT44_EI_OUT2IN_NEXT_DROP;
450       goto out;
451     }
452   if (nat44_ei_static_mapping_match (addr, port, rx_fib_index0, *proto,
453                                      mapping_addr, mapping_port,
454                                      mapping_fib_index, 1, &is_addr_only, 0))
455     {
456       /* Don't NAT packet aimed at the intfc address */
457       if (nat44_ei_is_interface_addr (nm->ip4_main, node, sw_if_index0,
458                                       ip0->dst_address.as_u32))
459         {
460           *dont_translate = 1;
461           goto out;
462         }
463       b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
464       next0 = NAT44_EI_OUT2IN_NEXT_DROP;
465       goto out;
466     }
467
468   if (PREDICT_FALSE
469       (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_reply
470        && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
471            ICMP4_echo_request || !is_addr_only)
472        && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
473                                        reass.icmp_type_or_tcp_flags)))
474     {
475       b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
476       next0 = NAT44_EI_OUT2IN_NEXT_DROP;
477       goto out;
478     }
479
480 out:
481   return next0;
482 }
483 #endif
484
485 u32 nat44_ei_icmp_out2in (vlib_buffer_t *b0, ip4_header_t *ip0,
486                           icmp46_header_t *icmp0, u32 sw_if_index0,
487                           u32 rx_fib_index0, vlib_node_runtime_t *node,
488                           u32 next0, u32 thread_index,
489                           nat44_ei_session_t **p_s0);
490
491 #ifndef CLIB_MARCH_VARIANT
492 u32
493 nat44_ei_icmp_out2in (vlib_buffer_t *b0, ip4_header_t *ip0,
494                       icmp46_header_t *icmp0, u32 sw_if_index0,
495                       u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0,
496                       u32 thread_index, nat44_ei_session_t **p_s0)
497 {
498   nat44_ei_main_t *nm = &nat44_ei_main;
499   icmp_echo_header_t *echo0, *inner_echo0 = 0;
500   ip4_header_t *inner_ip0 = 0;
501   void *l4_header = 0;
502   icmp46_header_t *inner_icmp0;
503   u8 dont_translate;
504   u32 new_addr0, old_addr0;
505   u16 old_id0, new_id0;
506   ip_csum_t sum0;
507   u16 checksum0;
508   u32 next0_tmp;
509   vlib_main_t *vm = vlib_get_main ();
510   ip4_address_t addr;
511   u16 port;
512   u32 fib_index;
513   nat_protocol_t proto;
514
515   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
516
517   if (PREDICT_TRUE (nm->pat))
518     {
519       next0_tmp = nat44_ei_icmp_match_out2in_slow (
520         node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
521         &dont_translate);
522     }
523   else
524     {
525       next0_tmp = nat44_ei_icmp_match_out2in_fast (
526         node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
527         &dont_translate);
528     }
529
530   if (next0_tmp != ~0)
531     next0 = next0_tmp;
532   if (next0 == NAT44_EI_OUT2IN_NEXT_DROP || dont_translate)
533     goto out;
534
535   if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
536     {
537       sum0 =
538         ip_incremental_checksum_buffer (vm, b0,
539                                         (u8 *) icmp0 -
540                                         (u8 *) vlib_buffer_get_current (b0),
541                                         ntohs (ip0->length) -
542                                         ip4_header_bytes (ip0), 0);
543       checksum0 = ~ip_csum_fold (sum0);
544       if (checksum0 != 0 && checksum0 != 0xffff)
545         {
546           next0 = NAT44_EI_OUT2IN_NEXT_DROP;
547           goto out;
548         }
549     }
550
551   old_addr0 = ip0->dst_address.as_u32;
552   new_addr0 = ip0->dst_address.as_u32 = addr.as_u32;
553   vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
554
555   sum0 = ip0->checksum;
556   sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
557                          dst_address /* changed member */ );
558   ip0->checksum = ip_csum_fold (sum0);
559
560
561   if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
562     {
563       if (icmp0->checksum == 0)
564         icmp0->checksum = 0xffff;
565
566       if (!icmp_type_is_error_message (icmp0->type))
567         {
568           new_id0 = port;
569           if (PREDICT_FALSE (new_id0 != echo0->identifier))
570             {
571               old_id0 = echo0->identifier;
572               new_id0 = port;
573               echo0->identifier = new_id0;
574
575               sum0 = icmp0->checksum;
576               sum0 =
577                 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
578                                 identifier /* changed member */ );
579               icmp0->checksum = ip_csum_fold (sum0);
580             }
581         }
582       else
583         {
584           inner_ip0 = (ip4_header_t *) (echo0 + 1);
585           l4_header = ip4_next_header (inner_ip0);
586
587           if (!ip4_header_checksum_is_valid (inner_ip0))
588             {
589               next0 = NAT44_EI_OUT2IN_NEXT_DROP;
590               goto out;
591             }
592
593           old_addr0 = inner_ip0->src_address.as_u32;
594           inner_ip0->src_address = addr;
595           new_addr0 = inner_ip0->src_address.as_u32;
596
597           sum0 = icmp0->checksum;
598           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
599                                  src_address /* changed member */ );
600           icmp0->checksum = ip_csum_fold (sum0);
601
602           switch (proto)
603             {
604             case NAT_PROTOCOL_ICMP:
605               inner_icmp0 = (icmp46_header_t *) l4_header;
606               inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
607
608               old_id0 = inner_echo0->identifier;
609               new_id0 = port;
610               inner_echo0->identifier = new_id0;
611
612               sum0 = icmp0->checksum;
613               sum0 =
614                 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
615                                 identifier);
616               icmp0->checksum = ip_csum_fold (sum0);
617               break;
618             case NAT_PROTOCOL_UDP:
619             case NAT_PROTOCOL_TCP:
620               old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
621               new_id0 = port;
622               ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
623
624               sum0 = icmp0->checksum;
625               sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
626                                      src_port);
627               icmp0->checksum = ip_csum_fold (sum0);
628               break;
629             default:
630               ASSERT (0);
631             }
632         }
633     }
634
635 out:
636   return next0;
637 }
638 #endif
639
640 static inline u32
641 nat44_ei_icmp_out2in_slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0,
642                                 ip4_header_t *ip0, icmp46_header_t *icmp0,
643                                 u32 sw_if_index0, u32 rx_fib_index0,
644                                 vlib_node_runtime_t *node, u32 next0, f64 now,
645                                 u32 thread_index, nat44_ei_session_t **p_s0)
646 {
647   vlib_main_t *vm = vlib_get_main ();
648
649   next0 = nat44_ei_icmp_out2in (b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
650                                 node, next0, thread_index, p_s0);
651   nat44_ei_session_t *s0 = *p_s0;
652   if (PREDICT_TRUE (next0 != NAT44_EI_OUT2IN_NEXT_DROP && s0))
653     {
654       /* Accounting */
655       nat44_ei_session_update_counters (
656         s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
657       /* Per-user LRU list maintenance */
658       nat44_ei_session_update_lru (nm, s0, thread_index);
659     }
660   return next0;
661 }
662
663 static int
664 nat_out2in_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b,
665                              ip4_header_t *ip, u32 rx_fib_index)
666 {
667   clib_bihash_kv_8_8_t kv, value;
668   nat44_ei_static_mapping_t *m;
669   u32 old_addr, new_addr;
670   ip_csum_t sum;
671
672   init_nat_k (&kv, ip->dst_address, 0, 0, 0);
673   if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
674     return 1;
675
676   m = pool_elt_at_index (nm->static_mappings, value.value);
677
678   old_addr = ip->dst_address.as_u32;
679   new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
680   sum = ip->checksum;
681   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
682   ip->checksum = ip_csum_fold (sum);
683
684   vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
685   return 0;
686 }
687
688 VLIB_NODE_FN (nat44_ei_out2in_node)
689 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
690 {
691   u32 n_left_from, *from;
692   nat44_ei_main_t *nm = &nat44_ei_main;
693   f64 now = vlib_time_now (vm);
694   u32 thread_index = vm->thread_index;
695   nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
696
697   from = vlib_frame_vector_args (frame);
698   n_left_from = frame->n_vectors;
699
700   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
701   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
702   vlib_get_buffers (vm, from, b, n_left_from);
703
704   while (n_left_from >= 2)
705     {
706       vlib_buffer_t *b0, *b1;
707       u32 next0 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
708       u32 next1 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
709       u32 sw_if_index0, sw_if_index1;
710       ip4_header_t *ip0, *ip1;
711       ip_csum_t sum0, sum1;
712       u32 new_addr0, old_addr0;
713       u16 new_port0, old_port0;
714       u32 new_addr1, old_addr1;
715       u16 new_port1, old_port1;
716       udp_header_t *udp0, *udp1;
717       tcp_header_t *tcp0, *tcp1;
718       icmp46_header_t *icmp0, *icmp1;
719       u32 rx_fib_index0, rx_fib_index1;
720       u32 proto0, proto1;
721       nat44_ei_session_t *s0 = 0, *s1 = 0;
722       clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
723       u8 identity_nat0, identity_nat1;
724       ip4_address_t sm_addr0, sm_addr1;
725       u16 sm_port0, sm_port1;
726       u32 sm_fib_index0, sm_fib_index1;
727
728       b0 = *b;
729       b++;
730       b1 = *b;
731       b++;
732
733       /* Prefetch next iteration. */
734       if (PREDICT_TRUE (n_left_from >= 4))
735         {
736           vlib_buffer_t *p2, *p3;
737
738           p2 = *b;
739           p3 = *(b + 1);
740
741           vlib_prefetch_buffer_header (p2, LOAD);
742           vlib_prefetch_buffer_header (p3, LOAD);
743
744           clib_prefetch_load (p2->data);
745           clib_prefetch_load (p3->data);
746         }
747
748       vnet_buffer (b0)->snat.flags = 0;
749       vnet_buffer (b1)->snat.flags = 0;
750
751       ip0 = vlib_buffer_get_current (b0);
752       udp0 = ip4_next_header (ip0);
753       tcp0 = (tcp_header_t *) udp0;
754       icmp0 = (icmp46_header_t *) udp0;
755
756       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
757       rx_fib_index0 =
758         vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
759
760       if (PREDICT_FALSE (ip0->ttl == 1))
761         {
762           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
763           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
764                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
765                                        0);
766           next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
767           goto trace0;
768         }
769
770       proto0 = ip_proto_to_nat_proto (ip0->protocol);
771
772       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
773         {
774           if (nat_out2in_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
775             {
776               if (!nm->forwarding_enabled)
777                 {
778                   b0->error =
779                     node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
780                   next0 = NAT44_EI_OUT2IN_NEXT_DROP;
781                 }
782             }
783           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
784                                          thread_index, sw_if_index0, 1);
785
786           goto trace0;
787         }
788
789       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
790         {
791           next0 = nat44_ei_icmp_out2in_slow_path (
792             nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0, now,
793             thread_index, &s0);
794           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
795                                          thread_index, sw_if_index0, 1);
796           goto trace0;
797         }
798
799       init_nat_k (&kv0, ip0->dst_address,
800                   vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
801                   proto0);
802       if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
803         {
804           /* Try to match static mapping by external address and port,
805              destination address and port in packet */
806           if (nat44_ei_static_mapping_match (
807                 ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port,
808                 rx_fib_index0, proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1,
809                 0, &identity_nat0))
810             {
811               /*
812                * Send DHCP packets to the ipv4 stack, or we won't
813                * be able to use dhcp client on the outside interface
814                */
815               if (PREDICT_FALSE
816                   (proto0 == NAT_PROTOCOL_UDP
817                    && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
818                        clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
819                 {
820                   vnet_feature_next (&next0, b0);
821                   goto trace0;
822                 }
823
824               if (!nm->forwarding_enabled)
825                 {
826                   b0->error =
827                     node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
828                   next0 = NAT44_EI_OUT2IN_NEXT_DROP;
829                 }
830               goto trace0;
831             }
832
833           if (PREDICT_FALSE (identity_nat0))
834             goto trace0;
835
836           /* Create session initiated by host from external network */
837           s0 = create_session_for_static_mapping (
838             nm, b0, sm_addr0, sm_port0, sm_fib_index0, ip0->dst_address,
839             vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0,
840             node, thread_index, now);
841           if (!s0)
842             {
843               next0 = NAT44_EI_OUT2IN_NEXT_DROP;
844               goto trace0;
845             }
846         }
847       else
848         s0 = pool_elt_at_index (tnm->sessions,
849                                 nat_value_get_session_index (&value0));
850
851       old_addr0 = ip0->dst_address.as_u32;
852       ip0->dst_address = s0->in2out.addr;
853       new_addr0 = ip0->dst_address.as_u32;
854       vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
855
856       sum0 = ip0->checksum;
857       sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
858                              ip4_header_t, dst_address /* changed member */ );
859       ip0->checksum = ip_csum_fold (sum0);
860
861       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
862         {
863           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
864             {
865               old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
866               new_port0 = udp0->dst_port = s0->in2out.port;
867               sum0 = tcp0->checksum;
868               sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
869                                      ip4_header_t,
870                                      dst_address /* changed member */ );
871
872               sum0 = ip_csum_update (sum0, old_port0, new_port0,
873                                      ip4_header_t /* cheat */ ,
874                                      length /* changed member */ );
875               tcp0->checksum = ip_csum_fold (sum0);
876             }
877           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
878                                          thread_index, sw_if_index0, 1);
879         }
880       else
881         {
882           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
883             {
884               old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
885               new_port0 = udp0->dst_port = s0->in2out.port;
886               if (PREDICT_FALSE (udp0->checksum))
887                 {
888                   sum0 = udp0->checksum;
889                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address  /* changed member */
890                     );
891                   sum0 =
892                     ip_csum_update (sum0, old_port0, new_port0,
893                                     ip4_header_t /* cheat */ ,
894                                     length /* changed member */ );
895                   udp0->checksum = ip_csum_fold (sum0);
896                 }
897             }
898           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
899                                          thread_index, sw_if_index0, 1);
900         }
901
902       /* Accounting */
903       nat44_ei_session_update_counters (
904         s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
905       /* Per-user LRU list maintenance */
906       nat44_ei_session_update_lru (nm, s0, thread_index);
907     trace0:
908
909       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
910                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
911         {
912           nat44_ei_out2in_trace_t *t =
913             vlib_add_trace (vm, node, b0, sizeof (*t));
914           t->sw_if_index = sw_if_index0;
915           t->next_index = next0;
916           t->session_index = ~0;
917           if (s0)
918             t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
919         }
920
921       if (next0 == NAT44_EI_OUT2IN_NEXT_DROP)
922         {
923           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
924                                          thread_index, sw_if_index0, 1);
925         }
926
927
928       ip1 = vlib_buffer_get_current (b1);
929       udp1 = ip4_next_header (ip1);
930       tcp1 = (tcp_header_t *) udp1;
931       icmp1 = (icmp46_header_t *) udp1;
932
933       sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
934       rx_fib_index1 =
935         vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index1);
936
937       if (PREDICT_FALSE (ip1->ttl == 1))
938         {
939           vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
940           icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
941                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
942                                        0);
943           next1 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
944           goto trace1;
945         }
946
947       proto1 = ip_proto_to_nat_proto (ip1->protocol);
948
949       if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
950         {
951           if (nat_out2in_sm_unknown_proto (nm, b1, ip1, rx_fib_index1))
952             {
953               if (!nm->forwarding_enabled)
954                 {
955                   b1->error =
956                     node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
957                   next1 = NAT44_EI_OUT2IN_NEXT_DROP;
958                 }
959             }
960           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
961                                          thread_index, sw_if_index1, 1);
962           goto trace1;
963         }
964
965       if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
966         {
967           next1 = nat44_ei_icmp_out2in_slow_path (
968             nm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, next1, now,
969             thread_index, &s1);
970           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
971                                          thread_index, sw_if_index1, 1);
972           goto trace1;
973         }
974
975       init_nat_k (&kv1, ip1->dst_address,
976                   vnet_buffer (b1)->ip.reass.l4_dst_port, rx_fib_index1,
977                   proto1);
978       if (clib_bihash_search_8_8 (&nm->out2in, &kv1, &value1))
979         {
980           /* Try to match static mapping by external address and port,
981              destination address and port in packet */
982           if (nat44_ei_static_mapping_match (
983                 ip1->dst_address, vnet_buffer (b1)->ip.reass.l4_dst_port,
984                 rx_fib_index1, proto1, &sm_addr1, &sm_port1, &sm_fib_index1, 1,
985                 0, &identity_nat1))
986             {
987               /*
988                * Send DHCP packets to the ipv4 stack, or we won't
989                * be able to use dhcp client on the outside interface
990                */
991               if (PREDICT_FALSE
992                   (proto1 == NAT_PROTOCOL_UDP
993                    && (vnet_buffer (b1)->ip.reass.l4_dst_port ==
994                        clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
995                 {
996                   vnet_feature_next (&next1, b1);
997                   goto trace1;
998                 }
999
1000               if (!nm->forwarding_enabled)
1001                 {
1002                   b1->error =
1003                     node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
1004                   next1 = NAT44_EI_OUT2IN_NEXT_DROP;
1005                 }
1006               goto trace1;
1007             }
1008
1009           if (PREDICT_FALSE (identity_nat1))
1010             goto trace1;
1011
1012           /* Create session initiated by host from external network */
1013           s1 = create_session_for_static_mapping (
1014             nm, b1, sm_addr1, sm_port1, sm_fib_index1, ip1->dst_address,
1015             vnet_buffer (b1)->ip.reass.l4_dst_port, rx_fib_index1, proto1,
1016             node, thread_index, now);
1017           if (!s1)
1018             {
1019               next1 = NAT44_EI_OUT2IN_NEXT_DROP;
1020               goto trace1;
1021             }
1022         }
1023       else
1024         s1 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
1025                                 nat_value_get_session_index (&value1));
1026
1027       old_addr1 = ip1->dst_address.as_u32;
1028       ip1->dst_address = s1->in2out.addr;
1029       new_addr1 = ip1->dst_address.as_u32;
1030       vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1031
1032       sum1 = ip1->checksum;
1033       sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1034                              ip4_header_t, dst_address /* changed member */ );
1035       ip1->checksum = ip_csum_fold (sum1);
1036
1037       if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
1038         {
1039           if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1040             {
1041               old_port1 = vnet_buffer (b1)->ip.reass.l4_dst_port;
1042               new_port1 = udp1->dst_port = s1->in2out.port;
1043
1044               sum1 = tcp1->checksum;
1045               sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1046                                      ip4_header_t,
1047                                      dst_address /* changed member */ );
1048
1049               sum1 = ip_csum_update (sum1, old_port1, new_port1,
1050                                      ip4_header_t /* cheat */ ,
1051                                      length /* changed member */ );
1052               tcp1->checksum = ip_csum_fold (sum1);
1053             }
1054           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
1055                                          thread_index, sw_if_index1, 1);
1056         }
1057       else
1058         {
1059           if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1060             {
1061               old_port1 = vnet_buffer (b1)->ip.reass.l4_dst_port;
1062               new_port1 = udp1->dst_port = s1->in2out.port;
1063               if (PREDICT_FALSE (udp1->checksum))
1064                 {
1065
1066                   sum1 = udp1->checksum;
1067                   sum1 =
1068                     ip_csum_update (sum1, old_addr1, new_addr1,
1069                                     ip4_header_t,
1070                                     dst_address /* changed member */ );
1071                   sum1 =
1072                     ip_csum_update (sum1, old_port1, new_port1,
1073                                     ip4_header_t /* cheat */ ,
1074                                     length /* changed member */ );
1075                   udp1->checksum = ip_csum_fold (sum1);
1076                 }
1077             }
1078           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
1079                                          thread_index, sw_if_index1, 1);
1080         }
1081
1082       /* Accounting */
1083       nat44_ei_session_update_counters (
1084         s1, now, vlib_buffer_length_in_chain (vm, b1), thread_index);
1085       /* Per-user LRU list maintenance */
1086       nat44_ei_session_update_lru (nm, s1, thread_index);
1087     trace1:
1088
1089       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1090                          && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1091         {
1092           nat44_ei_out2in_trace_t *t =
1093             vlib_add_trace (vm, node, b1, sizeof (*t));
1094           t->sw_if_index = sw_if_index1;
1095           t->next_index = next1;
1096           t->session_index = ~0;
1097           if (s1)
1098             t->session_index = s1 - nm->per_thread_data[thread_index].sessions;
1099         }
1100
1101       if (next1 == NAT44_EI_OUT2IN_NEXT_DROP)
1102         {
1103           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
1104                                          thread_index, sw_if_index1, 1);
1105         }
1106
1107       n_left_from -= 2;
1108       next[0] = next0;
1109       next[1] = next1;
1110       next += 2;
1111     }
1112
1113   while (n_left_from > 0)
1114     {
1115       vlib_buffer_t *b0;
1116       u32 next0 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
1117       u32 sw_if_index0;
1118       ip4_header_t *ip0;
1119       ip_csum_t sum0;
1120       u32 new_addr0, old_addr0;
1121       u16 new_port0, old_port0;
1122       udp_header_t *udp0;
1123       tcp_header_t *tcp0;
1124       icmp46_header_t *icmp0;
1125       u32 rx_fib_index0;
1126       u32 proto0;
1127       nat44_ei_session_t *s0 = 0;
1128       clib_bihash_kv_8_8_t kv0, value0;
1129       u8 identity_nat0;
1130       ip4_address_t sm_addr0;
1131       u16 sm_port0;
1132       u32 sm_fib_index0;
1133
1134       b0 = *b;
1135       ++b;
1136
1137       vnet_buffer (b0)->snat.flags = 0;
1138
1139       ip0 = vlib_buffer_get_current (b0);
1140       udp0 = ip4_next_header (ip0);
1141       tcp0 = (tcp_header_t *) udp0;
1142       icmp0 = (icmp46_header_t *) udp0;
1143
1144       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1145       rx_fib_index0 =
1146         vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
1147
1148       proto0 = ip_proto_to_nat_proto (ip0->protocol);
1149
1150       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1151         {
1152           if (nat_out2in_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
1153             {
1154               if (!nm->forwarding_enabled)
1155                 {
1156                   b0->error =
1157                     node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1158                   next0 = NAT44_EI_OUT2IN_NEXT_DROP;
1159                 }
1160             }
1161           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
1162                                          thread_index, sw_if_index0, 1);
1163           goto trace00;
1164         }
1165
1166       if (PREDICT_FALSE (ip0->ttl == 1))
1167         {
1168           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1169           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1170                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
1171                                        0);
1172           next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
1173           goto trace00;
1174         }
1175
1176       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1177         {
1178           next0 = nat44_ei_icmp_out2in_slow_path (
1179             nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0, now,
1180             thread_index, &s0);
1181           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
1182                                          thread_index, sw_if_index0, 1);
1183           goto trace00;
1184         }
1185
1186       init_nat_k (&kv0, ip0->dst_address,
1187                   vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
1188                   proto0);
1189
1190       if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
1191         {
1192           /* Try to match static mapping by external address and port,
1193              destination address and port in packet */
1194           if (nat44_ei_static_mapping_match (
1195                 ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port,
1196                 rx_fib_index0, proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1,
1197                 0, &identity_nat0))
1198             {
1199               /*
1200                * Send DHCP packets to the ipv4 stack, or we won't
1201                * be able to use dhcp client on the outside interface
1202                */
1203               if (PREDICT_FALSE
1204                   (proto0 == NAT_PROTOCOL_UDP
1205                    && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1206                        clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
1207                 {
1208                   vnet_feature_next (&next0, b0);
1209                   goto trace00;
1210                 }
1211
1212               if (!nm->forwarding_enabled)
1213                 {
1214                   b0->error =
1215                     node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
1216                   next0 = NAT44_EI_OUT2IN_NEXT_DROP;
1217                 }
1218               goto trace00;
1219             }
1220
1221           if (PREDICT_FALSE (identity_nat0))
1222             goto trace00;
1223
1224           /* Create session initiated by host from external network */
1225           s0 = create_session_for_static_mapping (
1226             nm, b0, sm_addr0, sm_port0, sm_fib_index0, ip0->dst_address,
1227             vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0,
1228             node, thread_index, now);
1229           if (!s0)
1230             {
1231               next0 = NAT44_EI_OUT2IN_NEXT_DROP;
1232               goto trace00;
1233             }
1234         }
1235       else
1236         s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
1237                                 nat_value_get_session_index (&value0));
1238
1239       old_addr0 = ip0->dst_address.as_u32;
1240       ip0->dst_address = s0->in2out.addr;
1241       new_addr0 = ip0->dst_address.as_u32;
1242       vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1243
1244       sum0 = ip0->checksum;
1245       sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1246                              ip4_header_t, dst_address /* changed member */ );
1247       ip0->checksum = ip_csum_fold (sum0);
1248
1249       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1250         {
1251           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1252             {
1253               old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
1254               new_port0 = udp0->dst_port = s0->in2out.port;
1255
1256               sum0 = tcp0->checksum;
1257               sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1258                                      ip4_header_t,
1259                                      dst_address /* changed member */ );
1260
1261               sum0 = ip_csum_update (sum0, old_port0, new_port0,
1262                                      ip4_header_t /* cheat */ ,
1263                                      length /* changed member */ );
1264               tcp0->checksum = ip_csum_fold (sum0);
1265             }
1266           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
1267                                          thread_index, sw_if_index0, 1);
1268         }
1269       else
1270         {
1271           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1272             {
1273               old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
1274               new_port0 = udp0->dst_port = s0->in2out.port;
1275               if (PREDICT_FALSE (udp0->checksum))
1276                 {
1277                   sum0 = udp0->checksum;
1278                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address  /* changed member */
1279                     );
1280                   sum0 =
1281                     ip_csum_update (sum0, old_port0, new_port0,
1282                                     ip4_header_t /* cheat */ ,
1283                                     length /* changed member */ );
1284                   udp0->checksum = ip_csum_fold (sum0);
1285                 }
1286             }
1287           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
1288                                          thread_index, sw_if_index0, 1);
1289         }
1290
1291       /* Accounting */
1292       nat44_ei_session_update_counters (
1293         s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
1294       /* Per-user LRU list maintenance */
1295       nat44_ei_session_update_lru (nm, s0, thread_index);
1296     trace00:
1297
1298       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1299                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1300         {
1301           nat44_ei_out2in_trace_t *t =
1302             vlib_add_trace (vm, node, b0, sizeof (*t));
1303           t->sw_if_index = sw_if_index0;
1304           t->next_index = next0;
1305           t->session_index = ~0;
1306           if (s0)
1307             t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
1308         }
1309
1310       if (next0 == NAT44_EI_OUT2IN_NEXT_DROP)
1311         {
1312           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
1313                                          thread_index, sw_if_index0, 1);
1314         }
1315
1316       n_left_from--;
1317       next[0] = next0;
1318       next++;
1319     }
1320
1321   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1322                                frame->n_vectors);
1323
1324   return frame->n_vectors;
1325 }
1326
1327 VLIB_REGISTER_NODE (nat44_ei_out2in_node) = {
1328   .name = "nat44-ei-out2in",
1329   .vector_size = sizeof (u32),
1330   .format_trace = format_nat44_ei_out2in_trace,
1331   .type = VLIB_NODE_TYPE_INTERNAL,
1332
1333   .n_errors = ARRAY_LEN(nat44_ei_out2in_error_strings),
1334   .error_strings = nat44_ei_out2in_error_strings,
1335
1336   .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
1337
1338   .n_next_nodes = NAT44_EI_OUT2IN_N_NEXT,
1339
1340   /* edit / add dispositions here */
1341   .next_nodes = {
1342     [NAT44_EI_OUT2IN_NEXT_DROP] = "error-drop",
1343     [NAT44_EI_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1344     [NAT44_EI_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1345   },
1346 };
1347
1348 /*
1349  * fd.io coding-style-patch-verification: ON
1350  *
1351  * Local Variables:
1352  * eval: (c-set-style "gnu")
1353  * End:
1354  */