FD.io VPP  v19.01.1-17-ge106252
Vector Packet Processing
in2out.c
Go to the documentation of this file.
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 inside to outside 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/ethernet/ethernet.h>
26 #include <vnet/fib/ip4_fib.h>
27 #include <nat/nat.h>
28 #include <nat/nat_ipfix_logging.h>
29 #include <nat/nat_reass.h>
30 #include <nat/nat_inlines.h>
31 #include <nat/nat_syslog.h>
32 
33 #include <vppinfra/hash.h>
34 #include <vppinfra/error.h>
35 #include <vppinfra/elog.h>
36 
37 typedef struct
38 {
44 
45 /* packet trace format function */
46 static u8 *
47 format_snat_in2out_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_in2out_trace_t *t = va_arg (*args, snat_in2out_trace_t *);
52  char *tag;
53 
54  tag = t->is_slow_path ? "NAT44_IN2OUT_SLOW_PATH" : "NAT44_IN2OUT_FAST_PATH";
55 
56  s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
58 
59  return s;
60 }
61 
62 static u8 *
63 format_snat_in2out_fast_trace (u8 * s, va_list * args)
64 {
65  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
66  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
67  snat_in2out_trace_t *t = va_arg (*args, snat_in2out_trace_t *);
68 
69  s = format (s, "NAT44_IN2OUT_FAST: sw_if_index %d, next index %d",
70  t->sw_if_index, t->next_index);
71 
72  return s;
73 }
74 
81 
82 #define foreach_snat_in2out_error \
83 _(UNSUPPORTED_PROTOCOL, "unsupported protocol") \
84 _(IN2OUT_PACKETS, "good in2out packets processed") \
85 _(OUT_OF_PORTS, "out of ports") \
86 _(BAD_OUTSIDE_FIB, "outside VRF ID not found") \
87 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
88 _(NO_TRANSLATION, "no translation") \
89 _(MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded") \
90 _(DROP_FRAGMENT, "drop fragment") \
91 _(MAX_REASS, "maximum reassemblies exceeded") \
92 _(MAX_FRAG, "maximum fragments per reassembly exceeded")\
93 _(TCP_PACKETS, "TCP packets") \
94 _(UDP_PACKETS, "UDP packets") \
95 _(ICMP_PACKETS, "ICMP packets") \
96 _(OTHER_PACKETS, "other protocol packets") \
97 _(FRAGMENTS, "fragments") \
98 _(CACHED_FRAGMENTS, "cached fragments") \
99 _(PROCESSED_FRAGMENTS, "processed fragments")
100 
101 typedef enum
102 {
103 #define _(sym,str) SNAT_IN2OUT_ERROR_##sym,
105 #undef _
108 
109 static char *snat_in2out_error_strings[] = {
110 #define _(sym,string) string,
112 #undef _
113 };
114 
115 typedef enum
116 {
124 
125 static inline int
127  u32 sw_if_index0, ip4_header_t * ip0, u32 proto0,
128  u32 rx_fib_index0, u32 thread_index)
129 {
130  udp_header_t *udp0 = ip4_next_header (ip0);
131  snat_session_key_t key0, sm0;
132  clib_bihash_kv_8_8_t kv0, value0;
133 
134  key0.addr = ip0->dst_address;
135  key0.port = udp0->dst_port;
136  key0.protocol = proto0;
137  key0.fib_index = sm->outside_fib_index;
138  kv0.key = key0.as_u64;
139 
140  /* NAT packet aimed at external address if */
141  /* has active sessions */
142  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
143  &value0))
144  {
145  /* or is static mappings */
146  if (!snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0, 0))
147  return 0;
148  }
149  else
150  return 0;
151 
152  if (sm->forwarding_enabled)
153  return 1;
154 
155  return snat_not_translate_fast (sm, node, sw_if_index0, ip0, proto0,
156  rx_fib_index0);
157 }
158 
159 static inline int
161  u32 proto0, u16 src_port, u16 dst_port,
162  u32 thread_index, u32 sw_if_index)
163 {
164  snat_session_key_t key0;
165  clib_bihash_kv_8_8_t kv0, value0;
167 
168  /* src NAT check */
169  key0.addr = ip0->src_address;
170  key0.port = src_port;
171  key0.protocol = proto0;
173  kv0.key = key0.as_u64;
174 
175  if (!clib_bihash_search_8_8
176  (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
177  return 1;
178 
179  /* dst NAT check */
180  key0.addr = ip0->dst_address;
181  key0.port = dst_port;
182  key0.protocol = proto0;
183  kv0.key = key0.as_u64;
184  if (!clib_bihash_search_8_8
185  (&sm->per_thread_data[thread_index].in2out, &kv0, &value0))
186  {
187  /* hairpinning */
188  /* *INDENT-OFF* */
190  ({
191  if ((nat_interface_is_inside(i)) && (sw_if_index == i->sw_if_index))
192  return 0;
193  }));
194  /* *INDENT-ON* */
195  return 1;
196  }
197 
198  return 0;
199 }
200 
201 int
203 {
204  snat_main_t *sm = &snat_main;
206  snat_session_t *s;
207  u64 sess_timeout_time;
209  ctx->thread_index);
211 
212  s = pool_elt_at_index (tsm->sessions, kv->value);
213  sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
214  if (ctx->now >= sess_timeout_time)
215  {
216  s_kv.key = s->out2in.as_u64;
217  if (clib_bihash_add_del_8_8 (&tsm->out2in, &s_kv, 0))
218  nat_log_warn ("out2in key del failed");
219 
220  snat_ipfix_logging_nat44_ses_delete (s->in2out.addr.as_u32,
221  s->out2in.addr.as_u32,
222  s->in2out.protocol,
223  s->in2out.port,
224  s->out2in.port,
225  s->in2out.fib_index);
226 
227  nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
228  &s->in2out.addr, s->in2out.port,
229  &s->out2in.addr, s->out2in.port,
230  s->in2out.protocol);
231 
232  if (!snat_is_session_static (s))
234  &s->out2in);
235 
236  nat44_delete_session (sm, s, ctx->thread_index);
237  return 1;
238  }
239 
240  return 0;
241 }
242 
243 static u32
245  ip4_header_t * ip0,
246  u32 rx_fib_index0,
247  snat_session_key_t * key0,
248  snat_session_t ** sessionp,
249  vlib_node_runtime_t * node, u32 next0, u32 thread_index, f64 now)
250 {
251  snat_user_t *u;
252  snat_session_t *s = 0;
254  snat_session_key_t key1;
255  udp_header_t *udp0 = ip4_next_header (ip0);
256  u8 is_sm = 0;
257  nat_outside_fib_t *outside_fib;
259  u8 identity_nat;
260  fib_prefix_t pfx = {
262  .fp_len = 32,
263  .fp_addr = {
264  .ip4.as_u32 = ip0->dst_address.as_u32,
265  },
266  };
268 
269  if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
270  {
271  b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
273  nat_log_notice ("maximum sessions exceeded");
274  return SNAT_IN2OUT_NEXT_DROP;
275  }
276 
277  key1.protocol = key0->protocol;
278 
279  /* First try to match static mapping by local address and port */
281  (sm, *key0, &key1, 0, 0, 0, 0, 0, &identity_nat))
282  {
283  /* Try to create dynamic translation */
284  if (snat_alloc_outside_address_and_port (sm->addresses, rx_fib_index0,
285  thread_index, &key1,
286  sm->port_per_thread,
287  sm->per_thread_data
288  [thread_index].snat_thread_index))
289  {
290  b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
291  return SNAT_IN2OUT_NEXT_DROP;
292  }
293  }
294  else
295  {
296  if (PREDICT_FALSE (identity_nat))
297  {
298  *sessionp = s;
299  return next0;
300  }
301 
302  is_sm = 1;
303  }
304 
305  u = nat_user_get_or_create (sm, &ip0->src_address, rx_fib_index0,
306  thread_index);
307  if (!u)
308  {
309  nat_log_warn ("create NAT user failed");
310  return SNAT_IN2OUT_NEXT_DROP;
311  }
312 
313  s = nat_session_alloc_or_recycle (sm, u, thread_index);
314  if (!s)
315  {
316  nat44_delete_user_with_no_session (sm, u, thread_index);
317  nat_log_warn ("create NAT session failed");
318  return SNAT_IN2OUT_NEXT_DROP;
319  }
320 
321  if (is_sm)
323  user_session_increment (sm, u, is_sm);
324  s->in2out = *key0;
325  s->out2in = key1;
326  s->out2in.protocol = key0->protocol;
327  s->out2in.fib_index = sm->outside_fib_index;
328  switch (vec_len (sm->outside_fibs))
329  {
330  case 0:
331  s->out2in.fib_index = sm->outside_fib_index;
332  break;
333  case 1:
334  s->out2in.fib_index = sm->outside_fibs[0].fib_index;
335  break;
336  default:
337  /* *INDENT-OFF* */
338  vec_foreach (outside_fib, sm->outside_fibs)
339  {
340  fei = fib_table_lookup (outside_fib->fib_index, &pfx);
341  if (FIB_NODE_INDEX_INVALID != fei)
342  {
343  if (fib_entry_get_resolving_interface (fei) != ~0)
344  {
345  s->out2in.fib_index = outside_fib->fib_index;
346  break;
347  }
348  }
349  }
350  /* *INDENT-ON* */
351  break;
352  }
353  s->ext_host_addr.as_u32 = ip0->dst_address.as_u32;
354  s->ext_host_port = udp0->dst_port;
355  *sessionp = s;
356 
357  /* Add to translation hashes */
358  ctx0.now = now;
359  ctx0.thread_index = thread_index;
360  kv0.key = s->in2out.as_u64;
361  kv0.value = s - sm->per_thread_data[thread_index].sessions;
362  if (clib_bihash_add_or_overwrite_stale_8_8
363  (&sm->per_thread_data[thread_index].in2out, &kv0,
365  nat_log_notice ("in2out key add failed");
366 
367  kv0.key = s->out2in.as_u64;
368  kv0.value = s - sm->per_thread_data[thread_index].sessions;
369 
370  if (clib_bihash_add_or_overwrite_stale_8_8
371  (&sm->per_thread_data[thread_index].out2in, &kv0,
373  nat_log_notice ("out2in key add failed");
374 
375  /* log NAT event */
376  snat_ipfix_logging_nat44_ses_create (s->in2out.addr.as_u32,
377  s->out2in.addr.as_u32,
378  s->in2out.protocol,
379  s->in2out.port,
380  s->out2in.port, s->in2out.fib_index);
381 
382  nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index,
383  &s->in2out.addr, s->in2out.port, &s->out2in.addr,
384  s->out2in.port, s->in2out.protocol);
385 
386  return next0;
387 }
388 
391  snat_session_key_t * p_key0)
392 {
393  icmp46_header_t *icmp0;
394  snat_session_key_t key0;
395  icmp_echo_header_t *echo0, *inner_echo0 = 0;
396  ip4_header_t *inner_ip0 = 0;
397  void *l4_header = 0;
398  icmp46_header_t *inner_icmp0;
399 
400  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
401  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
402 
403  if (!icmp_is_error_message (icmp0))
404  {
405  key0.protocol = SNAT_PROTOCOL_ICMP;
406  key0.addr = ip0->src_address;
407  key0.port = echo0->identifier;
408  }
409  else
410  {
411  inner_ip0 = (ip4_header_t *) (echo0 + 1);
412  l4_header = ip4_next_header (inner_ip0);
413  key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
414  key0.addr = inner_ip0->dst_address;
415  switch (key0.protocol)
416  {
417  case SNAT_PROTOCOL_ICMP:
418  inner_icmp0 = (icmp46_header_t *) l4_header;
419  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
420  key0.port = inner_echo0->identifier;
421  break;
422  case SNAT_PROTOCOL_UDP:
423  case SNAT_PROTOCOL_TCP:
424  key0.port = ((tcp_udp_header_t *) l4_header)->dst_port;
425  break;
426  default:
427  return SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL;
428  }
429  }
430  *p_key0 = key0;
431  return -1; /* success */
432 }
433 
434 /**
435  * Get address and port values to be used for ICMP packet translation
436  * and create session if needed
437  *
438  * @param[in,out] sm NAT main
439  * @param[in,out] node NAT node runtime
440  * @param[in] thread_index thread index
441  * @param[in,out] b0 buffer containing packet to be translated
442  * @param[out] p_proto protocol used for matching
443  * @param[out] p_value address and port after NAT translation
444  * @param[out] p_dont_translate if packet should not be translated
445  * @param d optional parameter
446  * @param e optional parameter
447  */
448 u32
450  u32 thread_index, vlib_buffer_t * b0,
451  ip4_header_t * ip0, u8 * p_proto,
452  snat_session_key_t * p_value,
453  u8 * p_dont_translate, void *d, void *e)
454 {
455  icmp46_header_t *icmp0;
456  u32 sw_if_index0;
457  u32 rx_fib_index0;
458  snat_session_key_t key0;
459  snat_session_t *s0 = 0;
460  u8 dont_translate = 0;
461  clib_bihash_kv_8_8_t kv0, value0;
462  u32 next0 = ~0;
463  int err;
464 
465  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
466  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
467  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
468 
469  err = icmp_get_key (ip0, &key0);
470  if (err != -1)
471  {
472  b0->error = node->errors[err];
473  next0 = SNAT_IN2OUT_NEXT_DROP;
474  goto out;
475  }
476  key0.fib_index = rx_fib_index0;
477 
478  kv0.key = key0.as_u64;
479 
480  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0,
481  &value0))
482  {
483  if (vnet_buffer (b0)->sw_if_index[VLIB_TX] != ~0)
484  {
486  key0.protocol,
487  key0.port,
488  key0.port,
489  thread_index,
490  sw_if_index0)))
491  {
492  dont_translate = 1;
493  goto out;
494  }
495  }
496  else
497  {
498  if (PREDICT_FALSE (snat_not_translate (sm, node, sw_if_index0,
499  ip0, SNAT_PROTOCOL_ICMP,
500  rx_fib_index0,
501  thread_index)))
502  {
503  dont_translate = 1;
504  goto out;
505  }
506  }
507 
508  if (PREDICT_FALSE (icmp_is_error_message (icmp0)))
509  {
510  b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
511  next0 = SNAT_IN2OUT_NEXT_DROP;
512  goto out;
513  }
514 
515  next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, &s0, node, next0,
516  thread_index, vlib_time_now (sm->vlib_main));
517 
518  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
519  goto out;
520 
521  if (!s0)
522  {
523  dont_translate = 1;
524  goto out;
525  }
526  }
527  else
528  {
529  if (PREDICT_FALSE (icmp0->type != ICMP4_echo_request &&
530  icmp0->type != ICMP4_echo_reply &&
531  !icmp_is_error_message (icmp0)))
532  {
533  b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
534  next0 = SNAT_IN2OUT_NEXT_DROP;
535  goto out;
536  }
537 
538  s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
539  value0.value);
540  }
541 
542 out:
543  *p_proto = key0.protocol;
544  if (s0)
545  *p_value = s0->out2in;
546  *p_dont_translate = dont_translate;
547  if (d)
548  *(snat_session_t **) d = s0;
549  return next0;
550 }
551 
552 /**
553  * Get address and port values to be used for ICMP packet translation
554  *
555  * @param[in] sm NAT main
556  * @param[in,out] node NAT node runtime
557  * @param[in] thread_index thread index
558  * @param[in,out] b0 buffer containing packet to be translated
559  * @param[out] p_proto protocol used for matching
560  * @param[out] p_value address and port after NAT translation
561  * @param[out] p_dont_translate if packet should not be translated
562  * @param d optional parameter
563  * @param e optional parameter
564  */
565 u32
567  u32 thread_index, vlib_buffer_t * b0,
568  ip4_header_t * ip0, u8 * p_proto,
569  snat_session_key_t * p_value,
570  u8 * p_dont_translate, void *d, void *e)
571 {
572  icmp46_header_t *icmp0;
573  u32 sw_if_index0;
574  u32 rx_fib_index0;
575  snat_session_key_t key0;
576  snat_session_key_t sm0;
577  u8 dont_translate = 0;
578  u8 is_addr_only;
579  u32 next0 = ~0;
580  int err;
581 
582  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
583  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
584  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
585 
586  err = icmp_get_key (ip0, &key0);
587  if (err != -1)
588  {
589  b0->error = node->errors[err];
590  next0 = SNAT_IN2OUT_NEXT_DROP;
591  goto out2;
592  }
593  key0.fib_index = rx_fib_index0;
594 
596  (sm, key0, &sm0, 0, &is_addr_only, 0, 0, 0, 0))
597  {
598  if (PREDICT_FALSE (snat_not_translate_fast (sm, node, sw_if_index0, ip0,
599  IP_PROTOCOL_ICMP,
600  rx_fib_index0)))
601  {
602  dont_translate = 1;
603  goto out;
604  }
605 
606  if (icmp_is_error_message (icmp0))
607  {
608  next0 = SNAT_IN2OUT_NEXT_DROP;
609  goto out;
610  }
611 
612  b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
613  next0 = SNAT_IN2OUT_NEXT_DROP;
614  goto out;
615  }
616 
617  if (PREDICT_FALSE (icmp0->type != ICMP4_echo_request &&
618  (icmp0->type != ICMP4_echo_reply || !is_addr_only) &&
619  !icmp_is_error_message (icmp0)))
620  {
621  b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
622  next0 = SNAT_IN2OUT_NEXT_DROP;
623  goto out;
624  }
625 
626 out:
627  *p_value = sm0;
628 out2:
629  *p_proto = key0.protocol;
630  *p_dont_translate = dont_translate;
631  return next0;
632 }
633 
634 u32
636  vlib_buffer_t * b0,
637  ip4_header_t * ip0,
638  icmp46_header_t * icmp0,
639  u32 sw_if_index0,
640  u32 rx_fib_index0,
641  vlib_node_runtime_t * node,
642  u32 next0, u32 thread_index, void *d, void *e)
643 {
644  snat_session_key_t sm0;
645  u8 protocol;
646  icmp_echo_header_t *echo0, *inner_echo0 = 0;
647  ip4_header_t *inner_ip0;
648  void *l4_header = 0;
649  icmp46_header_t *inner_icmp0;
650  u8 dont_translate;
651  u32 new_addr0, old_addr0;
652  u16 old_id0, new_id0;
653  u16 old_checksum0, new_checksum0;
654  ip_csum_t sum0;
655  u16 checksum0;
656  u32 next0_tmp;
657 
658  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
659 
660  next0_tmp = sm->icmp_match_in2out_cb (sm, node, thread_index, b0, ip0,
661  &protocol, &sm0, &dont_translate, d,
662  e);
663  if (next0_tmp != ~0)
664  next0 = next0_tmp;
665  if (next0 == SNAT_IN2OUT_NEXT_DROP || dont_translate)
666  goto out;
667 
668  if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
669  {
670  sum0 = ip_incremental_checksum_buffer (sm->vlib_main, b0, (u8 *) icmp0 -
671  (u8 *)
673  ntohs (ip0->length) -
674  ip4_header_bytes (ip0), 0);
675  checksum0 = ~ip_csum_fold (sum0);
676  if (PREDICT_FALSE (checksum0 != 0 && checksum0 != 0xffff))
677  {
678  next0 = SNAT_IN2OUT_NEXT_DROP;
679  goto out;
680  }
681  }
682 
683  old_addr0 = ip0->src_address.as_u32;
684  new_addr0 = ip0->src_address.as_u32 = sm0.addr.as_u32;
685 
686  sum0 = ip0->checksum;
687  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
688  src_address /* changed member */ );
689  ip0->checksum = ip_csum_fold (sum0);
690 
691  if (icmp0->checksum == 0)
692  icmp0->checksum = 0xffff;
693 
694  if (!icmp_is_error_message (icmp0))
695  {
696  new_id0 = sm0.port;
697  if (PREDICT_FALSE (new_id0 != echo0->identifier))
698  {
699  old_id0 = echo0->identifier;
700  new_id0 = sm0.port;
701  echo0->identifier = new_id0;
702 
703  sum0 = icmp0->checksum;
704  sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
705  identifier);
706  icmp0->checksum = ip_csum_fold (sum0);
707  }
708  }
709  else
710  {
711  inner_ip0 = (ip4_header_t *) (echo0 + 1);
712  l4_header = ip4_next_header (inner_ip0);
713 
714  if (!ip4_header_checksum_is_valid (inner_ip0))
715  {
716  next0 = SNAT_IN2OUT_NEXT_DROP;
717  goto out;
718  }
719 
720  /* update inner destination IP address */
721  old_addr0 = inner_ip0->dst_address.as_u32;
722  inner_ip0->dst_address = sm0.addr;
723  new_addr0 = inner_ip0->dst_address.as_u32;
724  sum0 = icmp0->checksum;
725  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
726  dst_address /* changed member */ );
727  icmp0->checksum = ip_csum_fold (sum0);
728 
729  /* update inner IP header checksum */
730  old_checksum0 = inner_ip0->checksum;
731  sum0 = inner_ip0->checksum;
732  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
733  dst_address /* changed member */ );
734  inner_ip0->checksum = ip_csum_fold (sum0);
735  new_checksum0 = inner_ip0->checksum;
736  sum0 = icmp0->checksum;
737  sum0 = ip_csum_update (sum0, old_checksum0, new_checksum0, ip4_header_t,
738  checksum);
739  icmp0->checksum = ip_csum_fold (sum0);
740 
741  switch (protocol)
742  {
743  case SNAT_PROTOCOL_ICMP:
744  inner_icmp0 = (icmp46_header_t *) l4_header;
745  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
746 
747  old_id0 = inner_echo0->identifier;
748  new_id0 = sm0.port;
749  inner_echo0->identifier = new_id0;
750 
751  sum0 = icmp0->checksum;
752  sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
753  identifier);
754  icmp0->checksum = ip_csum_fold (sum0);
755  break;
756  case SNAT_PROTOCOL_UDP:
757  case SNAT_PROTOCOL_TCP:
758  old_id0 = ((tcp_udp_header_t *) l4_header)->dst_port;
759  new_id0 = sm0.port;
760  ((tcp_udp_header_t *) l4_header)->dst_port = new_id0;
761 
762  sum0 = icmp0->checksum;
763  sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
764  dst_port);
765  icmp0->checksum = ip_csum_fold (sum0);
766  break;
767  default:
768  ASSERT (0);
769  }
770  }
771 
772  if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0)
773  {
774  if (sm->deterministic ||
775  0 != snat_icmp_hairpinning (sm, b0, ip0, icmp0,
776  sm->endpoint_dependent))
777  vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
778  }
779 
780 out:
781  return next0;
782 }
783 
784 static inline u32
786  vlib_buffer_t * b0,
787  ip4_header_t * ip0,
788  icmp46_header_t * icmp0,
789  u32 sw_if_index0,
790  u32 rx_fib_index0,
791  vlib_node_runtime_t * node,
792  u32 next0,
793  f64 now, u32 thread_index, snat_session_t ** p_s0)
794 {
795  next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
796  next0, thread_index, p_s0, 0);
797  snat_session_t *s0 = *p_s0;
798  if (PREDICT_TRUE (next0 != SNAT_IN2OUT_NEXT_DROP && s0))
799  {
800  /* Accounting */
803  (sm->vlib_main, b0));
804  /* Per-user LRU list maintenance */
805  nat44_session_update_lru (sm, s0, thread_index);
806  }
807  return next0;
808 }
809 
810 static int
812  vlib_buffer_t * b,
813  ip4_header_t * ip, u32 rx_fib_index)
814 {
815  clib_bihash_kv_8_8_t kv, value;
817  snat_session_key_t m_key;
818  u32 old_addr, new_addr;
819  ip_csum_t sum;
820 
821  m_key.addr = ip->src_address;
822  m_key.port = 0;
823  m_key.protocol = 0;
824  m_key.fib_index = rx_fib_index;
825  kv.key = m_key.as_u64;
826  if (clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
827  return 1;
828 
829  m = pool_elt_at_index (sm->static_mappings, value.value);
830 
831  old_addr = ip->src_address.as_u32;
832  new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
833  sum = ip->checksum;
834  sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
835  ip->checksum = ip_csum_fold (sum);
836 
837 
838  /* Hairpinning */
839  if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
840  {
841  vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
843  }
844 
845  return 0;
846 }
847 
848 static inline uword
850  vlib_node_runtime_t * node,
851  vlib_frame_t * frame, int is_slow_path,
852  int is_output_feature)
853 {
854  u32 n_left_from, *from, *to_next;
855  snat_in2out_next_t next_index;
856  u32 pkts_processed = 0;
857  snat_main_t *sm = &snat_main;
858  f64 now = vlib_time_now (vm);
859  u32 stats_node_index;
860  u32 thread_index = vm->thread_index;
861  u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
862  0, fragments = 0;
863 
864  stats_node_index = is_slow_path ? snat_in2out_slowpath_node.index :
865  snat_in2out_node.index;
866 
867  from = vlib_frame_vector_args (frame);
868  n_left_from = frame->n_vectors;
869  next_index = node->cached_next_index;
870 
871  while (n_left_from > 0)
872  {
873  u32 n_left_to_next;
874 
875  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
876 
877  while (n_left_from >= 4 && n_left_to_next >= 2)
878  {
879  u32 bi0, bi1;
880  vlib_buffer_t *b0, *b1;
881  u32 next0, next1;
882  u32 sw_if_index0, sw_if_index1;
883  ip4_header_t *ip0, *ip1;
884  ip_csum_t sum0, sum1;
885  u32 new_addr0, old_addr0, new_addr1, old_addr1;
886  u16 old_port0, new_port0, old_port1, new_port1;
887  udp_header_t *udp0, *udp1;
888  tcp_header_t *tcp0, *tcp1;
889  icmp46_header_t *icmp0, *icmp1;
890  snat_session_key_t key0, key1;
891  u32 rx_fib_index0, rx_fib_index1;
892  u32 proto0, proto1;
893  snat_session_t *s0 = 0, *s1 = 0;
894  clib_bihash_kv_8_8_t kv0, value0, kv1, value1;
895  u32 iph_offset0 = 0, iph_offset1 = 0;
896 
897  /* Prefetch next iteration. */
898  {
899  vlib_buffer_t *p2, *p3;
900 
901  p2 = vlib_get_buffer (vm, from[2]);
902  p3 = vlib_get_buffer (vm, from[3]);
903 
904  vlib_prefetch_buffer_header (p2, LOAD);
905  vlib_prefetch_buffer_header (p3, LOAD);
906 
909  }
910 
911  /* speculatively enqueue b0 and b1 to the current next frame */
912  to_next[0] = bi0 = from[0];
913  to_next[1] = bi1 = from[1];
914  from += 2;
915  to_next += 2;
916  n_left_from -= 2;
917  n_left_to_next -= 2;
918 
919  b0 = vlib_get_buffer (vm, bi0);
920  b1 = vlib_get_buffer (vm, bi1);
921 
922  if (is_output_feature)
923  iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
924 
925  ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
926  iph_offset0);
927 
928  udp0 = ip4_next_header (ip0);
929  tcp0 = (tcp_header_t *) udp0;
930  icmp0 = (icmp46_header_t *) udp0;
931 
932  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
933  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
934  sw_if_index0);
935 
936  next0 = next1 = SNAT_IN2OUT_NEXT_LOOKUP;
937 
938  if (PREDICT_FALSE (ip0->ttl == 1))
939  {
940  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
941  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
942  ICMP4_time_exceeded_ttl_exceeded_in_transit,
943  0);
945  goto trace00;
946  }
947 
948  proto0 = ip_proto_to_snat_proto (ip0->protocol);
949 
950  /* Next configured feature, probably ip4-lookup */
951  if (is_slow_path)
952  {
953  if (PREDICT_FALSE (proto0 == ~0))
954  {
956  (sm, b0, ip0, rx_fib_index0))
957  {
958  next0 = SNAT_IN2OUT_NEXT_DROP;
959  b0->error =
960  node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
961  }
962  other_packets++;
963  goto trace00;
964  }
965 
966  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
967  {
968  next0 = icmp_in2out_slow_path
969  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
970  node, next0, now, thread_index, &s0);
971  icmp_packets++;
972  goto trace00;
973  }
974  }
975  else
976  {
977  if (PREDICT_FALSE (proto0 == ~0))
978  {
980  goto trace00;
981  }
982 
983  if (ip4_is_fragment (ip0))
984  {
985  next0 = SNAT_IN2OUT_NEXT_REASS;
986  fragments++;
987  goto trace00;
988  }
989 
990  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
991  {
993  goto trace00;
994  }
995  }
996 
997  key0.addr = ip0->src_address;
998  key0.port = udp0->src_port;
999  key0.protocol = proto0;
1000  key0.fib_index = rx_fib_index0;
1001 
1002  kv0.key = key0.as_u64;
1003 
1004  if (PREDICT_FALSE
1005  (clib_bihash_search_8_8
1006  (&sm->per_thread_data[thread_index].in2out, &kv0,
1007  &value0) != 0))
1008  {
1009  if (is_slow_path)
1010  {
1011  if (is_output_feature)
1012  {
1014  ip0,
1015  proto0,
1016  udp0->src_port,
1017  udp0->dst_port,
1018  thread_index,
1019  sw_if_index0)))
1020  goto trace00;
1021  }
1022  else
1023  {
1024  if (PREDICT_FALSE
1026  (sm, node, sw_if_index0, ip0, proto0,
1027  rx_fib_index0, thread_index)))
1028  goto trace00;
1029  }
1030 
1031  next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
1032  &s0, node, next0, thread_index, now);
1033  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
1034  goto trace00;
1035 
1036  if (PREDICT_FALSE (!s0))
1037  goto trace00;
1038  }
1039  else
1040  {
1042  goto trace00;
1043  }
1044  }
1045  else
1046  s0 =
1047  pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1048  value0.value);
1049 
1050  b0->flags |= VNET_BUFFER_F_IS_NATED;
1051 
1052  old_addr0 = ip0->src_address.as_u32;
1053  ip0->src_address = s0->out2in.addr;
1054  new_addr0 = ip0->src_address.as_u32;
1055  if (!is_output_feature)
1056  vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1057 
1058  sum0 = ip0->checksum;
1059  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1060  ip4_header_t,
1061  src_address /* changed member */ );
1062  ip0->checksum = ip_csum_fold (sum0);
1063 
1064  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1065  {
1066  old_port0 = tcp0->src_port;
1067  tcp0->src_port = s0->out2in.port;
1068  new_port0 = tcp0->src_port;
1069 
1070  sum0 = tcp0->checksum;
1071  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1072  ip4_header_t,
1073  dst_address /* changed member */ );
1074  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1075  ip4_header_t /* cheat */ ,
1076  length /* changed member */ );
1077  mss_clamping (sm, tcp0, &sum0);
1078  tcp0->checksum = ip_csum_fold (sum0);
1079  tcp_packets++;
1080  }
1081  else
1082  {
1083  old_port0 = udp0->src_port;
1084  udp0->src_port = s0->out2in.port;
1085  udp0->checksum = 0;
1086  udp_packets++;
1087  }
1088 
1089  /* Accounting */
1092  b0));
1093  /* Per-user LRU list maintenance */
1094  nat44_session_update_lru (sm, s0, thread_index);
1095  trace00:
1096 
1098  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1099  {
1100  snat_in2out_trace_t *t =
1101  vlib_add_trace (vm, node, b0, sizeof (*t));
1102  t->is_slow_path = is_slow_path;
1103  t->sw_if_index = sw_if_index0;
1104  t->next_index = next0;
1105  t->session_index = ~0;
1106  if (s0)
1107  t->session_index =
1108  s0 - sm->per_thread_data[thread_index].sessions;
1109  }
1110 
1111  pkts_processed += next0 == SNAT_IN2OUT_NEXT_LOOKUP;
1112 
1113  if (is_output_feature)
1114  iph_offset1 = vnet_buffer (b1)->ip.save_rewrite_length;
1115 
1116  ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) +
1117  iph_offset1);
1118 
1119  udp1 = ip4_next_header (ip1);
1120  tcp1 = (tcp_header_t *) udp1;
1121  icmp1 = (icmp46_header_t *) udp1;
1122 
1123  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1124  rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1125  sw_if_index1);
1126 
1127  if (PREDICT_FALSE (ip1->ttl == 1))
1128  {
1129  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1130  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1131  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1132  0);
1134  goto trace01;
1135  }
1136 
1137  proto1 = ip_proto_to_snat_proto (ip1->protocol);
1138 
1139  /* Next configured feature, probably ip4-lookup */
1140  if (is_slow_path)
1141  {
1142  if (PREDICT_FALSE (proto1 == ~0))
1143  {
1145  (sm, b1, ip1, rx_fib_index1))
1146  {
1147  next1 = SNAT_IN2OUT_NEXT_DROP;
1148  b1->error =
1149  node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
1150  }
1151  other_packets++;
1152  goto trace01;
1153  }
1154 
1155  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1156  {
1157  next1 = icmp_in2out_slow_path
1158  (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1159  next1, now, thread_index, &s1);
1160  icmp_packets++;
1161  goto trace01;
1162  }
1163  }
1164  else
1165  {
1166  if (PREDICT_FALSE (proto1 == ~0))
1167  {
1169  goto trace01;
1170  }
1171 
1172  if (ip4_is_fragment (ip1))
1173  {
1174  next1 = SNAT_IN2OUT_NEXT_REASS;
1175  fragments++;
1176  goto trace01;
1177  }
1178 
1179  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1180  {
1182  goto trace01;
1183  }
1184  }
1185 
1186  key1.addr = ip1->src_address;
1187  key1.port = udp1->src_port;
1188  key1.protocol = proto1;
1189  key1.fib_index = rx_fib_index1;
1190 
1191  kv1.key = key1.as_u64;
1192 
1193  if (PREDICT_FALSE
1194  (clib_bihash_search_8_8
1195  (&sm->per_thread_data[thread_index].in2out, &kv1,
1196  &value1) != 0))
1197  {
1198  if (is_slow_path)
1199  {
1200  if (is_output_feature)
1201  {
1203  ip1,
1204  proto1,
1205  udp1->src_port,
1206  udp1->dst_port,
1207  thread_index,
1208  sw_if_index1)))
1209  goto trace01;
1210  }
1211  else
1212  {
1213  if (PREDICT_FALSE
1215  (sm, node, sw_if_index1, ip1, proto1,
1216  rx_fib_index1, thread_index)))
1217  goto trace01;
1218  }
1219 
1220  next1 = slow_path (sm, b1, ip1, rx_fib_index1, &key1,
1221  &s1, node, next1, thread_index, now);
1222  if (PREDICT_FALSE (next1 == SNAT_IN2OUT_NEXT_DROP))
1223  goto trace01;
1224 
1225  if (PREDICT_FALSE (!s1))
1226  goto trace01;
1227  }
1228  else
1229  {
1231  goto trace01;
1232  }
1233  }
1234  else
1235  s1 =
1236  pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1237  value1.value);
1238 
1239  b1->flags |= VNET_BUFFER_F_IS_NATED;
1240 
1241  old_addr1 = ip1->src_address.as_u32;
1242  ip1->src_address = s1->out2in.addr;
1243  new_addr1 = ip1->src_address.as_u32;
1244  if (!is_output_feature)
1245  vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index;
1246 
1247  sum1 = ip1->checksum;
1248  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1249  ip4_header_t,
1250  src_address /* changed member */ );
1251  ip1->checksum = ip_csum_fold (sum1);
1252 
1253  if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
1254  {
1255  old_port1 = tcp1->src_port;
1256  tcp1->src_port = s1->out2in.port;
1257  new_port1 = tcp1->src_port;
1258 
1259  sum1 = tcp1->checksum;
1260  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1261  ip4_header_t,
1262  dst_address /* changed member */ );
1263  sum1 = ip_csum_update (sum1, old_port1, new_port1,
1264  ip4_header_t /* cheat */ ,
1265  length /* changed member */ );
1266  mss_clamping (sm, tcp1, &sum1);
1267  tcp1->checksum = ip_csum_fold (sum1);
1268  tcp_packets++;
1269  }
1270  else
1271  {
1272  old_port1 = udp1->src_port;
1273  udp1->src_port = s1->out2in.port;
1274  udp1->checksum = 0;
1275  udp_packets++;
1276  }
1277 
1278  /* Accounting */
1281  b1));
1282  /* Per-user LRU list maintenance */
1283  nat44_session_update_lru (sm, s1, thread_index);
1284  trace01:
1285 
1287  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1288  {
1289  snat_in2out_trace_t *t =
1290  vlib_add_trace (vm, node, b1, sizeof (*t));
1291  t->sw_if_index = sw_if_index1;
1292  t->next_index = next1;
1293  t->session_index = ~0;
1294  if (s1)
1295  t->session_index =
1296  s1 - sm->per_thread_data[thread_index].sessions;
1297  }
1298 
1299  pkts_processed += next1 == SNAT_IN2OUT_NEXT_LOOKUP;
1300 
1301  /* verify speculative enqueues, maybe switch current next frame */
1302  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1303  to_next, n_left_to_next,
1304  bi0, bi1, next0, next1);
1305  }
1306 
1307  while (n_left_from > 0 && n_left_to_next > 0)
1308  {
1309  u32 bi0;
1310  vlib_buffer_t *b0;
1311  u32 next0;
1312  u32 sw_if_index0;
1313  ip4_header_t *ip0;
1314  ip_csum_t sum0;
1315  u32 new_addr0, old_addr0;
1316  u16 old_port0, new_port0;
1317  udp_header_t *udp0;
1318  tcp_header_t *tcp0;
1319  icmp46_header_t *icmp0;
1320  snat_session_key_t key0;
1321  u32 rx_fib_index0;
1322  u32 proto0;
1323  snat_session_t *s0 = 0;
1324  clib_bihash_kv_8_8_t kv0, value0;
1325  u32 iph_offset0 = 0;
1326 
1327  /* speculatively enqueue b0 to the current next frame */
1328  bi0 = from[0];
1329  to_next[0] = bi0;
1330  from += 1;
1331  to_next += 1;
1332  n_left_from -= 1;
1333  n_left_to_next -= 1;
1334 
1335  b0 = vlib_get_buffer (vm, bi0);
1336  next0 = SNAT_IN2OUT_NEXT_LOOKUP;
1337 
1338  if (is_output_feature)
1339  iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1340 
1341  ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1342  iph_offset0);
1343 
1344  udp0 = ip4_next_header (ip0);
1345  tcp0 = (tcp_header_t *) udp0;
1346  icmp0 = (icmp46_header_t *) udp0;
1347 
1348  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1349  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1350  sw_if_index0);
1351 
1352  if (PREDICT_FALSE (ip0->ttl == 1))
1353  {
1354  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1355  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1356  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1357  0);
1359  goto trace0;
1360  }
1361 
1362  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1363 
1364  /* Next configured feature, probably ip4-lookup */
1365  if (is_slow_path)
1366  {
1367  if (PREDICT_FALSE (proto0 == ~0))
1368  {
1370  (sm, b0, ip0, rx_fib_index0))
1371  {
1372  next0 = SNAT_IN2OUT_NEXT_DROP;
1373  b0->error =
1374  node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
1375  }
1376  other_packets++;
1377  goto trace0;
1378  }
1379 
1380  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1381  {
1382  next0 = icmp_in2out_slow_path
1383  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1384  next0, now, thread_index, &s0);
1385  icmp_packets++;
1386  goto trace0;
1387  }
1388  }
1389  else
1390  {
1391  if (PREDICT_FALSE (proto0 == ~0))
1392  {
1394  goto trace0;
1395  }
1396 
1397  if (ip4_is_fragment (ip0))
1398  {
1399  next0 = SNAT_IN2OUT_NEXT_REASS;
1400  fragments++;
1401  goto trace0;
1402  }
1403 
1404  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1405  {
1407  goto trace0;
1408  }
1409  }
1410 
1411  key0.addr = ip0->src_address;
1412  key0.port = udp0->src_port;
1413  key0.protocol = proto0;
1414  key0.fib_index = rx_fib_index0;
1415 
1416  kv0.key = key0.as_u64;
1417 
1418  if (clib_bihash_search_8_8
1419  (&sm->per_thread_data[thread_index].in2out, &kv0, &value0))
1420  {
1421  if (is_slow_path)
1422  {
1423  if (is_output_feature)
1424  {
1426  ip0,
1427  proto0,
1428  udp0->src_port,
1429  udp0->dst_port,
1430  thread_index,
1431  sw_if_index0)))
1432  goto trace0;
1433  }
1434  else
1435  {
1436  if (PREDICT_FALSE
1438  (sm, node, sw_if_index0, ip0, proto0,
1439  rx_fib_index0, thread_index)))
1440  goto trace0;
1441  }
1442 
1443  next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
1444  &s0, node, next0, thread_index, now);
1445 
1446  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
1447  goto trace0;
1448 
1449  if (PREDICT_FALSE (!s0))
1450  goto trace0;
1451  }
1452  else
1453  {
1455  goto trace0;
1456  }
1457  }
1458  else
1459  s0 =
1460  pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1461  value0.value);
1462 
1463  b0->flags |= VNET_BUFFER_F_IS_NATED;
1464 
1465  old_addr0 = ip0->src_address.as_u32;
1466  ip0->src_address = s0->out2in.addr;
1467  new_addr0 = ip0->src_address.as_u32;
1468  if (!is_output_feature)
1469  vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1470 
1471  sum0 = ip0->checksum;
1472  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1473  ip4_header_t,
1474  src_address /* changed member */ );
1475  ip0->checksum = ip_csum_fold (sum0);
1476 
1477  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1478  {
1479  old_port0 = tcp0->src_port;
1480  tcp0->src_port = s0->out2in.port;
1481  new_port0 = tcp0->src_port;
1482 
1483  sum0 = tcp0->checksum;
1484  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1485  ip4_header_t,
1486  dst_address /* changed member */ );
1487  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1488  ip4_header_t /* cheat */ ,
1489  length /* changed member */ );
1490  mss_clamping (sm, tcp0, &sum0);
1491  tcp0->checksum = ip_csum_fold (sum0);
1492  tcp_packets++;
1493  }
1494  else
1495  {
1496  old_port0 = udp0->src_port;
1497  udp0->src_port = s0->out2in.port;
1498  udp0->checksum = 0;
1499  udp_packets++;
1500  }
1501 
1502  /* Accounting */
1505  b0));
1506  /* Per-user LRU list maintenance */
1507  nat44_session_update_lru (sm, s0, thread_index);
1508 
1509  trace0:
1511  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1512  {
1513  snat_in2out_trace_t *t =
1514  vlib_add_trace (vm, node, b0, sizeof (*t));
1515  t->is_slow_path = is_slow_path;
1516  t->sw_if_index = sw_if_index0;
1517  t->next_index = next0;
1518  t->session_index = ~0;
1519  if (s0)
1520  t->session_index =
1521  s0 - sm->per_thread_data[thread_index].sessions;
1522  }
1523 
1524  pkts_processed += next0 == SNAT_IN2OUT_NEXT_LOOKUP;
1525 
1526  /* verify speculative enqueue, maybe switch current next frame */
1527  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1528  to_next, n_left_to_next,
1529  bi0, next0);
1530  }
1531 
1532  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1533  }
1534 
1535  vlib_node_increment_counter (vm, stats_node_index,
1536  SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
1537  pkts_processed);
1538  vlib_node_increment_counter (vm, stats_node_index,
1539  SNAT_IN2OUT_ERROR_TCP_PACKETS, tcp_packets);
1540  vlib_node_increment_counter (vm, stats_node_index,
1541  SNAT_IN2OUT_ERROR_UDP_PACKETS, tcp_packets);
1542  vlib_node_increment_counter (vm, stats_node_index,
1543  SNAT_IN2OUT_ERROR_ICMP_PACKETS, icmp_packets);
1544  vlib_node_increment_counter (vm, stats_node_index,
1545  SNAT_IN2OUT_ERROR_OTHER_PACKETS,
1546  other_packets);
1547  vlib_node_increment_counter (vm, stats_node_index,
1548  SNAT_IN2OUT_ERROR_FRAGMENTS, fragments);
1549 
1550  return frame->n_vectors;
1551 }
1552 
1553 static uword
1555  vlib_node_runtime_t * node, vlib_frame_t * frame)
1556 {
1557  return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */ ,
1558  0);
1559 }
1560 
1561 /* *INDENT-OFF* */
1563  .function = snat_in2out_fast_path_fn,
1564  .name = "nat44-in2out",
1565  .vector_size = sizeof (u32),
1566  .format_trace = format_snat_in2out_trace,
1567  .type = VLIB_NODE_TYPE_INTERNAL,
1568 
1569  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1570  .error_strings = snat_in2out_error_strings,
1571 
1572  .runtime_data_bytes = sizeof (snat_runtime_t),
1573 
1574  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1575 
1576  /* edit / add dispositions here */
1577  .next_nodes = {
1578  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1579  [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1580  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
1581  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1582  [SNAT_IN2OUT_NEXT_REASS] = "nat44-in2out-reass",
1583  },
1584 };
1585 /* *INDENT-ON* */
1586 
1588 
1589 static uword
1591  vlib_node_runtime_t * node,
1592  vlib_frame_t * frame)
1593 {
1594  return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */ ,
1595  1);
1596 }
1597 
1598 /* *INDENT-OFF* */
1600  .function = snat_in2out_output_fast_path_fn,
1601  .name = "nat44-in2out-output",
1602  .vector_size = sizeof (u32),
1603  .format_trace = format_snat_in2out_trace,
1604  .type = VLIB_NODE_TYPE_INTERNAL,
1605 
1606  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1607  .error_strings = snat_in2out_error_strings,
1608 
1609  .runtime_data_bytes = sizeof (snat_runtime_t),
1610 
1611  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1612 
1613  /* edit / add dispositions here */
1614  .next_nodes = {
1615  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1616  [SNAT_IN2OUT_NEXT_LOOKUP] = "interface-output",
1617  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-output-slowpath",
1618  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1619  [SNAT_IN2OUT_NEXT_REASS] = "nat44-in2out-reass",
1620  },
1621 };
1622 /* *INDENT-ON* */
1623 
1626 
1627 static uword
1629  vlib_node_runtime_t * node, vlib_frame_t * frame)
1630 {
1631  return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */ ,
1632  0);
1633 }
1634 
1635 /* *INDENT-OFF* */
1637  .function = snat_in2out_slow_path_fn,
1638  .name = "nat44-in2out-slowpath",
1639  .vector_size = sizeof (u32),
1640  .format_trace = format_snat_in2out_trace,
1641  .type = VLIB_NODE_TYPE_INTERNAL,
1642 
1643  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1644  .error_strings = snat_in2out_error_strings,
1645 
1646  .runtime_data_bytes = sizeof (snat_runtime_t),
1647 
1648  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1649 
1650  /* edit / add dispositions here */
1651  .next_nodes = {
1652  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1653  [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1654  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
1655  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1656  [SNAT_IN2OUT_NEXT_REASS] = "nat44-in2out-reass",
1657  },
1658 };
1659 /* *INDENT-ON* */
1660 
1663 
1664 static uword
1666  vlib_node_runtime_t * node,
1667  vlib_frame_t * frame)
1668 {
1669  return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */ ,
1670  1);
1671 }
1672 
1673 /* *INDENT-OFF* */
1675  .function = snat_in2out_output_slow_path_fn,
1676  .name = "nat44-in2out-output-slowpath",
1677  .vector_size = sizeof (u32),
1678  .format_trace = format_snat_in2out_trace,
1679  .type = VLIB_NODE_TYPE_INTERNAL,
1680 
1681  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1682  .error_strings = snat_in2out_error_strings,
1683 
1684  .runtime_data_bytes = sizeof (snat_runtime_t),
1685 
1686  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1687 
1688  /* edit / add dispositions here */
1689  .next_nodes = {
1690  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1691  [SNAT_IN2OUT_NEXT_LOOKUP] = "interface-output",
1692  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-output-slowpath",
1693  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1694  [SNAT_IN2OUT_NEXT_REASS] = "nat44-in2out-reass",
1695  },
1696 };
1697 /* *INDENT-ON* */
1698 
1701 
1702 static uword
1704  vlib_node_runtime_t * node, vlib_frame_t * frame)
1705 {
1706  u32 n_left_from, *from, *to_next;
1707  snat_in2out_next_t next_index;
1708  u32 pkts_processed = 0, cached_fragments = 0;
1709  snat_main_t *sm = &snat_main;
1710  f64 now = vlib_time_now (vm);
1711  u32 thread_index = vm->thread_index;
1712  snat_main_per_thread_data_t *per_thread_data =
1713  &sm->per_thread_data[thread_index];
1714  u32 *fragments_to_drop = 0;
1715  u32 *fragments_to_loopback = 0;
1716 
1717  from = vlib_frame_vector_args (frame);
1718  n_left_from = frame->n_vectors;
1719  next_index = node->cached_next_index;
1720 
1721  while (n_left_from > 0)
1722  {
1723  u32 n_left_to_next;
1724 
1725  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1726 
1727  while (n_left_from > 0 && n_left_to_next > 0)
1728  {
1729  u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1730  vlib_buffer_t *b0;
1731  u32 next0;
1732  u8 cached0 = 0;
1733  ip4_header_t *ip0;
1734  nat_reass_ip4_t *reass0;
1735  udp_header_t *udp0;
1736  tcp_header_t *tcp0;
1737  icmp46_header_t *icmp0;
1738  snat_session_key_t key0;
1739  clib_bihash_kv_8_8_t kv0, value0;
1740  snat_session_t *s0 = 0;
1741  u16 old_port0, new_port0;
1742  ip_csum_t sum0;
1743 
1744  /* speculatively enqueue b0 to the current next frame */
1745  bi0 = from[0];
1746  to_next[0] = bi0;
1747  from += 1;
1748  to_next += 1;
1749  n_left_from -= 1;
1750  n_left_to_next -= 1;
1751 
1752  b0 = vlib_get_buffer (vm, bi0);
1753  next0 = SNAT_IN2OUT_NEXT_LOOKUP;
1754 
1755  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1756  rx_fib_index0 =
1758  sw_if_index0);
1759 
1761  {
1762  next0 = SNAT_IN2OUT_NEXT_DROP;
1763  b0->error = node->errors[SNAT_IN2OUT_ERROR_DROP_FRAGMENT];
1764  goto trace0;
1765  }
1766 
1767  ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1768  udp0 = ip4_next_header (ip0);
1769  tcp0 = (tcp_header_t *) udp0;
1770  icmp0 = (icmp46_header_t *) udp0;
1771  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1772 
1774  ip0->dst_address,
1775  ip0->fragment_id,
1776  ip0->protocol,
1777  1, &fragments_to_drop);
1778 
1779  if (PREDICT_FALSE (!reass0))
1780  {
1781  next0 = SNAT_IN2OUT_NEXT_DROP;
1782  b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_REASS];
1783  nat_log_notice ("maximum reassemblies exceeded");
1784  goto trace0;
1785  }
1786 
1788  {
1789  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1790  {
1791  next0 = icmp_in2out_slow_path
1792  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1793  next0, now, thread_index, &s0);
1794 
1795  if (PREDICT_TRUE (next0 != SNAT_IN2OUT_NEXT_DROP))
1796  {
1797  if (s0)
1798  reass0->sess_index = s0 - per_thread_data->sessions;
1799  else
1800  reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1801  nat_ip4_reass_get_frags (reass0,
1802  &fragments_to_loopback);
1803  }
1804 
1805  goto trace0;
1806  }
1807 
1808  key0.addr = ip0->src_address;
1809  key0.port = udp0->src_port;
1810  key0.protocol = proto0;
1811  key0.fib_index = rx_fib_index0;
1812  kv0.key = key0.as_u64;
1813 
1814  if (clib_bihash_search_8_8
1815  (&per_thread_data->in2out, &kv0, &value0))
1816  {
1817  if (PREDICT_FALSE
1819  (sm, node, sw_if_index0, ip0, proto0, rx_fib_index0,
1820  thread_index)))
1821  goto trace0;
1822 
1823  next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
1824  &s0, node, next0, thread_index, now);
1825 
1826  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
1827  goto trace0;
1828 
1829  if (PREDICT_FALSE (!s0))
1830  goto trace0;
1831 
1832  reass0->sess_index = s0 - per_thread_data->sessions;
1833  }
1834  else
1835  {
1836  s0 = pool_elt_at_index (per_thread_data->sessions,
1837  value0.value);
1838  reass0->sess_index = value0.value;
1839  }
1840  nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1841  }
1842  else
1843  {
1844  if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
1845  {
1847  (reass0, bi0, &fragments_to_drop))
1848  {
1849  b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_FRAG];
1851  ("maximum fragments per reassembly exceeded");
1852  next0 = SNAT_IN2OUT_NEXT_DROP;
1853  goto trace0;
1854  }
1855  cached0 = 1;
1856  goto trace0;
1857  }
1858  s0 = pool_elt_at_index (per_thread_data->sessions,
1859  reass0->sess_index);
1860  }
1861 
1862  old_addr0 = ip0->src_address.as_u32;
1863  ip0->src_address = s0->out2in.addr;
1864  new_addr0 = ip0->src_address.as_u32;
1865  vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1866 
1867  sum0 = ip0->checksum;
1868  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1869  ip4_header_t,
1870  src_address /* changed member */ );
1871  ip0->checksum = ip_csum_fold (sum0);
1872 
1874  {
1875  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1876  {
1877  old_port0 = tcp0->src_port;
1878  tcp0->src_port = s0->out2in.port;
1879  new_port0 = tcp0->src_port;
1880 
1881  sum0 = tcp0->checksum;
1882  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1883  ip4_header_t,
1884  dst_address /* changed member */ );
1885  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1886  ip4_header_t /* cheat */ ,
1887  length /* changed member */ );
1888  tcp0->checksum = ip_csum_fold (sum0);
1889  }
1890  else
1891  {
1892  old_port0 = udp0->src_port;
1893  udp0->src_port = s0->out2in.port;
1894  udp0->checksum = 0;
1895  }
1896  }
1897 
1898  /* Hairpinning */
1899  nat44_reass_hairpinning (sm, b0, ip0, s0->out2in.port,
1900  s0->ext_host_port, proto0, 0);
1901 
1902  /* Accounting */
1905  b0));
1906  /* Per-user LRU list maintenance */
1907  nat44_session_update_lru (sm, s0, thread_index);
1908 
1909  trace0:
1911  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1912  {
1913  nat44_reass_trace_t *t =
1914  vlib_add_trace (vm, node, b0, sizeof (*t));
1915  t->cached = cached0;
1916  t->sw_if_index = sw_if_index0;
1917  t->next_index = next0;
1918  }
1919 
1920  if (cached0)
1921  {
1922  n_left_to_next++;
1923  to_next--;
1924  cached_fragments++;
1925  }
1926  else
1927  {
1928  pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
1929 
1930  /* verify speculative enqueue, maybe switch current next frame */
1931  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1932  to_next, n_left_to_next,
1933  bi0, next0);
1934  }
1935 
1936  if (n_left_from == 0 && vec_len (fragments_to_loopback))
1937  {
1938  from = vlib_frame_vector_args (frame);
1939  u32 len = vec_len (fragments_to_loopback);
1940  if (len <= VLIB_FRAME_SIZE)
1941  {
1942  clib_memcpy_fast (from, fragments_to_loopback,
1943  sizeof (u32) * len);
1944  n_left_from = len;
1945  vec_reset_length (fragments_to_loopback);
1946  }
1947  else
1948  {
1949  clib_memcpy_fast (from, fragments_to_loopback +
1950  (len - VLIB_FRAME_SIZE),
1951  sizeof (u32) * VLIB_FRAME_SIZE);
1952  n_left_from = VLIB_FRAME_SIZE;
1953  _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1954  }
1955  }
1956  }
1957 
1958  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1959  }
1960 
1962  SNAT_IN2OUT_ERROR_PROCESSED_FRAGMENTS,
1963  pkts_processed);
1965  SNAT_IN2OUT_ERROR_CACHED_FRAGMENTS,
1966  cached_fragments);
1967 
1968  nat_send_all_to_node (vm, fragments_to_drop, node,
1969  &node->errors[SNAT_IN2OUT_ERROR_DROP_FRAGMENT],
1971 
1972  vec_free (fragments_to_drop);
1973  vec_free (fragments_to_loopback);
1974  return frame->n_vectors;
1975 }
1976 
1977 /* *INDENT-OFF* */
1979  .function = nat44_in2out_reass_node_fn,
1980  .name = "nat44-in2out-reass",
1981  .vector_size = sizeof (u32),
1982  .format_trace = format_nat44_reass_trace,
1983  .type = VLIB_NODE_TYPE_INTERNAL,
1984 
1985  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1986  .error_strings = snat_in2out_error_strings,
1987 
1988  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1989  .next_nodes = {
1990  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1991  [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1992  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
1993  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1994  [SNAT_IN2OUT_NEXT_REASS] = "nat44-in2out-reass",
1995  },
1996 };
1997 /* *INDENT-ON* */
1998 
2001 
2002 static uword
2004  vlib_node_runtime_t * node,
2005  vlib_frame_t * frame)
2006 {
2007  u32 n_left_from, *from, *to_next;
2008  snat_in2out_next_t next_index;
2009  u32 pkts_processed = 0;
2010  snat_main_t *sm = &snat_main;
2011  u32 stats_node_index;
2012 
2013  stats_node_index = snat_in2out_fast_node.index;
2014 
2015  from = vlib_frame_vector_args (frame);
2016  n_left_from = frame->n_vectors;
2017  next_index = node->cached_next_index;
2018 
2019  while (n_left_from > 0)
2020  {
2021  u32 n_left_to_next;
2022 
2023  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2024 
2025  while (n_left_from > 0 && n_left_to_next > 0)
2026  {
2027  u32 bi0;
2028  vlib_buffer_t *b0;
2029  u32 next0;
2030  u32 sw_if_index0;
2031  ip4_header_t *ip0;
2032  ip_csum_t sum0;
2033  u32 new_addr0, old_addr0;
2034  u16 old_port0, new_port0;
2035  udp_header_t *udp0;
2036  tcp_header_t *tcp0;
2037  icmp46_header_t *icmp0;
2038  snat_session_key_t key0, sm0;
2039  u32 proto0;
2040  u32 rx_fib_index0;
2041 
2042  /* speculatively enqueue b0 to the current next frame */
2043  bi0 = from[0];
2044  to_next[0] = bi0;
2045  from += 1;
2046  to_next += 1;
2047  n_left_from -= 1;
2048  n_left_to_next -= 1;
2049 
2050  b0 = vlib_get_buffer (vm, bi0);
2051  next0 = SNAT_IN2OUT_NEXT_LOOKUP;
2052 
2053  ip0 = vlib_buffer_get_current (b0);
2054  udp0 = ip4_next_header (ip0);
2055  tcp0 = (tcp_header_t *) udp0;
2056  icmp0 = (icmp46_header_t *) udp0;
2057 
2058  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
2059  rx_fib_index0 =
2061 
2062  if (PREDICT_FALSE (ip0->ttl == 1))
2063  {
2064  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2065  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2066  ICMP4_time_exceeded_ttl_exceeded_in_transit,
2067  0);
2069  goto trace0;
2070  }
2071 
2072  proto0 = ip_proto_to_snat_proto (ip0->protocol);
2073 
2074  if (PREDICT_FALSE (proto0 == ~0))
2075  goto trace0;
2076 
2077  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2078  {
2079  next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0,
2080  rx_fib_index0, node, next0, ~0, 0, 0);
2081  goto trace0;
2082  }
2083 
2084  key0.addr = ip0->src_address;
2085  key0.protocol = proto0;
2086  key0.port = udp0->src_port;
2087  key0.fib_index = rx_fib_index0;
2088 
2089  if (snat_static_mapping_match (sm, key0, &sm0, 0, 0, 0, 0, 0, 0))
2090  {
2091  b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
2092  next0 = SNAT_IN2OUT_NEXT_DROP;
2093  goto trace0;
2094  }
2095 
2096  new_addr0 = sm0.addr.as_u32;
2097  new_port0 = sm0.port;
2098  vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
2099  old_addr0 = ip0->src_address.as_u32;
2100  ip0->src_address.as_u32 = new_addr0;
2101 
2102  sum0 = ip0->checksum;
2103  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2104  ip4_header_t,
2105  src_address /* changed member */ );
2106  ip0->checksum = ip_csum_fold (sum0);
2107 
2108  if (PREDICT_FALSE (new_port0 != udp0->dst_port))
2109  {
2110  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
2111  {
2112  old_port0 = tcp0->src_port;
2113  tcp0->src_port = new_port0;
2114 
2115  sum0 = tcp0->checksum;
2116  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2117  ip4_header_t,
2118  dst_address /* changed member */ );
2119  sum0 = ip_csum_update (sum0, old_port0, new_port0,
2120  ip4_header_t /* cheat */ ,
2121  length /* changed member */ );
2122  mss_clamping (sm, tcp0, &sum0);
2123  tcp0->checksum = ip_csum_fold (sum0);
2124  }
2125  else
2126  {
2127  old_port0 = udp0->src_port;
2128  udp0->src_port = new_port0;
2129  udp0->checksum = 0;
2130  }
2131  }
2132  else
2133  {
2134  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
2135  {
2136  sum0 = tcp0->checksum;
2137  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2138  ip4_header_t,
2139  dst_address /* changed member */ );
2140  mss_clamping (sm, tcp0, &sum0);
2141  tcp0->checksum = ip_csum_fold (sum0);
2142  }
2143  }
2144 
2145  /* Hairpinning */
2146  snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0, 0);
2147 
2148  trace0:
2150  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2151  {
2152  snat_in2out_trace_t *t =
2153  vlib_add_trace (vm, node, b0, sizeof (*t));
2154  t->sw_if_index = sw_if_index0;
2155  t->next_index = next0;
2156  }
2157 
2158  pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
2159 
2160  /* verify speculative enqueue, maybe switch current next frame */
2161  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2162  to_next, n_left_to_next,
2163  bi0, next0);
2164  }
2165 
2166  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2167  }
2168 
2169  vlib_node_increment_counter (vm, stats_node_index,
2170  SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
2171  pkts_processed);
2172  return frame->n_vectors;
2173 }
2174 
2175 
2176 /* *INDENT-OFF* */
2178  .function = snat_in2out_fast_static_map_fn,
2179  .name = "nat44-in2out-fast",
2180  .vector_size = sizeof (u32),
2181  .format_trace = format_snat_in2out_fast_trace,
2182  .type = VLIB_NODE_TYPE_INTERNAL,
2183 
2184  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2185  .error_strings = snat_in2out_error_strings,
2186 
2187  .runtime_data_bytes = sizeof (snat_runtime_t),
2188 
2189  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
2190 
2191  /* edit / add dispositions here */
2192  .next_nodes = {
2193  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2194  [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2195  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2196  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2197  [SNAT_IN2OUT_NEXT_REASS] = "nat44-in2out-reass",
2198  },
2199 };
2200 /* *INDENT-ON* */
2201 
2204 
2205 /*
2206  * fd.io coding-style-patch-verification: ON
2207  *
2208  * Local Variables:
2209  * eval: (c-set-style "gnu")
2210  * End:
2211  */
ip4_address_t external_addr
Definition: nat.h:330
void nat_ipfix_logging_max_sessions(u32 limit)
Generate maximum session entries exceeded event.
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:212
static ip_csum_t ip_incremental_checksum_buffer(vlib_main_t *vm, vlib_buffer_t *first_buffer, u32 first_buffer_offset, u32 n_bytes_to_checksum, ip_csum_t sum)
Definition: ip.h:154
nat_outside_fib_t * outside_fibs
Definition: nat.h:476
static u32 slow_path(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, u32 rx_fib_index0, snat_session_key_t *key0, snat_session_t **sessionp, vlib_node_runtime_t *node, u32 next0, u32 thread_index, f64 now)
Definition: in2out.c:244
#define snat_is_session_static(s)
Check if SNAT session is created from static mapping.
Definition: nat.h:605
static u8 * format_snat_in2out_trace(u8 *s, va_list *args)
Definition: in2out.c:47
#define CLIB_UNUSED(x)
Definition: clib.h:82
snat_in2out_error_t
Definition: in2out.c:101
static uword snat_in2out_slow_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out.c:1628
ip4_address_t src_address
Definition: ip4_packet.h:170
static int nat_not_translate_output_feature(snat_main_t *sm, ip4_header_t *ip0, u32 proto0, u16 src_port, u16 dst_port, u32 thread_index, u32 sw_if_index)
Definition: in2out.c:160
static u32 nat44_session_get_timeout(snat_main_t *sm, snat_session_t *s)
Definition: nat_inlines.h:273
static u8 * format_snat_in2out_fast_trace(u8 *s, va_list *args)
Definition: in2out.c:63
static uword snat_in2out_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_slow_path, int is_output_feature)
Definition: in2out.c:849
#define PREDICT_TRUE(x)
Definition: clib.h:112
static_always_inline u8 icmp_is_error_message(icmp46_header_t *icmp)
Definition: nat_inlines.h:53
unsigned long u64
Definition: types.h:89
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:232
static char * snat_in2out_error_strings[]
Definition: in2out.c:109
u32 fib_table_get_index_for_sw_if_index(fib_protocol_t proto, u32 sw_if_index)
Get the index of the FIB bound to the interface.
Definition: fib_table.c:956
u16 port_per_thread
Definition: nat.h:442
u32 thread_index
Definition: main.h:179
#define nat_log_warn(...)
Definition: nat.h:694
int i
uword ip_csum_t
Definition: ip_packet.h:181
snat_in2out_next_t
Definition: in2out.c:115
u32 * fib_index_by_sw_if_index
Table index indexed by software interface.
Definition: ip4.h:112
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:494
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:267
struct _tcp_header tcp_header_t
int snat_hairpinning(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, udp_header_t *udp0, tcp_header_t *tcp0, u32 proto0, int is_ed)
VLIB_NODE_FUNCTION_MULTIARCH(snat_in2out_node, snat_in2out_fast_path_fn)
u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation.
Definition: in2out.c:566
unsigned char u8
Definition: types.h:56
u8 deterministic
Definition: nat.h:511
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
static int ip4_is_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:213
static int snat_not_translate_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0)
Check if packet should be translated.
Definition: nat_inlines.h:410
u16 src_port
Definition: udp.api:41
static uword snat_in2out_output_slow_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out.c:1665
clib_bihash_8_8_t in2out
Definition: nat.h:383
vlib_node_registration_t snat_in2out_output_slowpath_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_output_slowpath_node)
Definition: in2out.c:79
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:224
#define static_always_inline
Definition: clib.h:99
static uword ip4_header_checksum_is_valid(ip4_header_t *i)
Definition: ip4_packet.h:268
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:490
vlib_node_registration_t snat_in2out_fast_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_fast_node)
Definition: in2out.c:77
u32 sw_if_index
Definition: vxlan_gbp.api:37
static int snat_not_translate(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0, u32 thread_index)
Definition: in2out.c:126
ip4_address_t dst_address
Definition: ip4_packet.h:170
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:188
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Aggregrate type for a prefix.
Definition: fib_types.h:203
u32 icmp_in2out(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0, u32 thread_index, void *d, void *e)
Definition: in2out.c:635
ip4_main_t * ip4_main
Definition: nat.h:548
#define NAT_REASS_FLAG_ED_DONT_TRANSLATE
Definition: nat_reass.h:35
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:241
unsigned int u32
Definition: types.h:88
vlib_node_registration_t snat_in2out_slowpath_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_slowpath_node)
Definition: in2out.c:76
#define VLIB_FRAME_SIZE
Definition: node.h:401
fib_node_index_t fib_table_lookup(u32 fib_index, const fib_prefix_t *prefix)
Perfom a longest prefix match in the non-forwarding table.
Definition: fib_table.c:66
static u8 maximum_sessions_exceeded(snat_main_t *sm, u32 thread_index)
Definition: nat_inlines.h:94
int snat_static_mapping_match(snat_main_t *sm, snat_session_key_t match, snat_session_key_t *mapping, u8 by_external, u8 *is_addr_only, twice_nat_type_t *twice_nat, lb_nat_type_t *lb, ip4_address_t *ext_host_addr, u8 *is_identity_nat)
Match NAT44 static mapping.
Definition: nat.c:2287
void snat_free_outside_address_and_port(snat_address_t *addresses, u32 thread_index, snat_session_key_t *k)
Free outside address and port pair.
Definition: nat.c:2249
static void nat44_delete_session(snat_main_t *sm, snat_session_t *ses, u32 thread_index)
Definition: nat_inlines.h:168
#define foreach_snat_in2out_error
Definition: in2out.c:82
u32 max_translations
Definition: nat.h:516
static void mss_clamping(snat_main_t *sm, tcp_header_t *tcp, ip_csum_t *sum)
Definition: nat_inlines.h:347
int snat_alloc_outside_address_and_port(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u16 port_per_thread, u32 snat_thread_index)
Alloc outside address and port.
Definition: nat.c:2432
snat_user_t * nat_user_get_or_create(snat_main_t *sm, ip4_address_t *addr, u32 fib_index, u32 thread_index)
Find or create NAT user.
Definition: nat.c:291
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:511
u32 fib_index
Definition: nat.h:257
static uword nat44_in2out_reass_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out.c:1703
u64 key
the key
Definition: bihash_8_8.h:33
static u32 icmp_in2out_slow_path(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0, f64 now, u32 thread_index, snat_session_t **p_s0)
Definition: in2out.c:785
long ctx[MAX_CONNS]
Definition: main.c:144
vlib_main_t * vlib_main
Definition: nat.h:546
unsigned short u16
Definition: types.h:57
u16 protocol
Definition: nat.h:54
snat_static_mapping_t * static_mappings
Definition: nat.h:455
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:214
void snat_ipfix_logging_nat44_ses_delete(u32 src_ip, u32 nat_src_ip, snat_protocol_t snat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session delete event.
void nat_syslog_nat44_apmadd(u32 ssubix, u32 sfibix, ip4_address_t *isaddr, u16 isport, ip4_address_t *xsaddr, u16 xsport, snat_protocol_t proto)
Definition: nat_syslog.c:109
#define PREDICT_FALSE(x)
Definition: clib.h:111
void snat_ipfix_logging_nat44_ses_create(u32 src_ip, u32 nat_src_ip, snat_protocol_t snat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session create event.
vl_api_address_union_t src_address
Definition: ip_types.api:44
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:368
#define nat_log_notice(...)
Definition: nat.h:696
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:139
u32 snat_icmp_hairpinning(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, int is_ed)
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1180
u8 len
Definition: ip_types.api:49
int nat44_o2i_is_idle_session_cb(clib_bihash_kv_8_8_t *kv, void *arg)
Definition: out2in.c:118
u32 fib_entry_get_resolving_interface(fib_node_index_t entry_index)
Definition: fib_entry.c:1451
snat_interface_t * output_feature_interfaces
Definition: nat.h:459
snat_main_t snat_main
Definition: nat.c:38
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
u64 value
the value
Definition: bihash_8_8.h:34
static int nat_in2out_sm_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index)
Definition: in2out.c:811
vlib_node_registration_t nat44_in2out_reass_node
(constructor) VLIB_REGISTER_NODE (nat44_in2out_reass_node)
Definition: in2out.c:80
static void nat44_delete_user_with_no_session(snat_main_t *sm, snat_user_t *u, u32 thread_index)
Definition: nat_inlines.h:146
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:420
clib_bihash_8_8_t out2in
Definition: nat.h:382
u8 nat_reass_is_drop_frag(u8 is_ip6)
Get status of virtual fragmentation reassembly.
Definition: nat_reass.c:168
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:79
vlib_main_t * vm
Definition: buffer.c:301
static uword snat_in2out_output_fast_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out.c:1590
vlib_node_registration_t snat_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_node)
Definition: in2out.c:75
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.c:431
static void nat44_session_update_counters(snat_session_t *s, f64 now, uword bytes)
Definition: nat_inlines.h:296
u32 outside_fib_index
Definition: nat.h:521
static uword snat_in2out_fast_static_map_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out.c:2003
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:30
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:31
#define ARRAY_LEN(x)
Definition: clib.h:62
ip4_address_t addr
Definition: nat.h:52
static_always_inline snat_in2out_error_t icmp_get_key(ip4_header_t *ip0, snat_session_key_t *p_key0)
Definition: in2out.c:390
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:459
u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: in2out.c:449
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:538
#define ASSERT(truth)
static void nat44_session_update_lru(snat_main_t *sm, snat_session_t *s, u32 thread_index)
Per-user LRU list maintenance.
Definition: nat_inlines.h:305
void nat_syslog_nat44_apmdel(u32 ssubix, u32 sfibix, ip4_address_t *isaddr, u16 isport, ip4_address_t *xsaddr, u16 xsport, snat_protocol_t proto)
Definition: nat_syslog.c:118
snat_session_t * nat_session_alloc_or_recycle(snat_main_t *sm, snat_user_t *u, u32 thread_index)
Allocate new NAT session or recycle last used.
Definition: nat.c:338
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:57
#define vec_elt(v, i)
Get vector value at index i.
struct _vlib_node_registration vlib_node_registration_t
Definition: defs.h:47
format_function_t format_nat44_reass_trace
Definition: nat.h:597
static int ip4_is_first_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:220
void nat_hairpinning_sm_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip)
static u32 ip_proto_to_snat_proto(u8 ip_proto)
The NAT inline functions.
Definition: nat_inlines.h:26
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:31
static void user_session_increment(snat_main_t *sm, snat_user_t *u, u8 is_static)
Definition: nat_inlines.h:134
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
snat_main_per_thread_data_t * per_thread_data
Definition: nat.h:446
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:274
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:231
NAT syslog logging.
nat_reass_ip4_t * nat_ip4_reass_find_or_create(ip4_address_t src, ip4_address_t dst, u16 frag_id, u8 proto, u8 reset_timeout, u32 **bi_to_drop)
Find or create reassembly.
Definition: nat_reass.c:220
snat_address_t * addresses
Definition: nat.h:462
static uword snat_in2out_fast_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out.c:1554
#define vnet_buffer(b)
Definition: buffer.h:368
#define SNAT_SESSION_FLAG_STATIC_MAPPING
Definition: nat.h:171
int nat_ip4_reass_add_fragment(nat_reass_ip4_t *reass, u32 bi, u32 **bi_to_drop)
Cache fragment.
Definition: nat_reass.c:338
u8 data[0]
Packet data.
Definition: buffer.h:176
u8 forwarding_enabled
Definition: nat.h:506
#define vec_foreach(var, vec)
Vector iterator.
vlib_node_registration_t snat_in2out_output_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_output_node)
Definition: in2out.c:78
u16 flags
Copy of main node flags.
Definition: node.h:532
static void nat_send_all_to_node(vlib_main_t *vm, u32 *bi_vector, vlib_node_runtime_t *node, vlib_error_t *error, u32 next)
Definition: nat_inlines.h:104
u8 endpoint_dependent
Definition: nat.h:513
u16 dst_port
Definition: udp.api:42
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:235
void nat_ip4_reass_get_frags(nat_reass_ip4_t *reass, u32 **bi)
Get cached fragments.
Definition: nat_reass.c:370
NAT plugin virtual fragmentation reassembly.
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:326
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:117
int nat44_i2o_is_idle_session_cb(clib_bihash_kv_8_8_t *kv, void *arg)
Definition: in2out.c:202
snat_session_t * sessions
Definition: nat.h:396
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:62
snat_icmp_match_function_t * icmp_match_in2out_cb
Definition: nat.h:433
clib_bihash_8_8_t static_mapping_by_local
Definition: nat.h:449
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:237
void nat44_reass_hairpinning(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, u16 sport, u16 dport, u32 proto0, int is_ed)
Definition: defs.h:46
u16 fib_index
Definition: nat.h:54