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