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