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