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