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