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