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