FD.io VPP  v20.01-48-g3e0dafb74
Vector Packet Processing
out2in.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 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_inlines.h>
31 #include <nat/nat44_inlines.h>
32 #include <nat/nat_syslog.h>
33 #include <nat/nat_ha.h>
34 
35 #include <vppinfra/hash.h>
36 #include <vppinfra/error.h>
37 #include <vppinfra/elog.h>
38 
39 typedef struct
40 {
45 
46 /* packet trace format function */
47 static u8 *
48 format_snat_out2in_trace (u8 * s, va_list * args)
49 {
50  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
51  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
52  snat_out2in_trace_t *t = va_arg (*args, snat_out2in_trace_t *);
53 
54  s =
55  format (s,
56  "NAT44_OUT2IN: sw_if_index %d, next index %d, session index %d",
58  return s;
59 }
60 
61 static u8 *
62 format_snat_out2in_fast_trace (u8 * s, va_list * args)
63 {
64  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
65  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
66  snat_out2in_trace_t *t = va_arg (*args, snat_out2in_trace_t *);
67 
68  s = format (s, "NAT44_OUT2IN_FAST: sw_if_index %d, next index %d",
69  t->sw_if_index, t->next_index);
70  return s;
71 }
72 
73 #define foreach_snat_out2in_error \
74 _(UNSUPPORTED_PROTOCOL, "unsupported protocol") \
75 _(OUT2IN_PACKETS, "good out2in packets processed") \
76 _(OUT_OF_PORTS, "out of ports") \
77 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
78 _(NO_TRANSLATION, "no translation") \
79 _(MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded") \
80 _(DROP_FRAGMENT, "drop fragment") \
81 _(MAX_REASS, "maximum reassemblies exceeded") \
82 _(MAX_FRAG, "maximum fragments per reassembly exceeded")\
83 _(TCP_PACKETS, "TCP packets") \
84 _(UDP_PACKETS, "UDP packets") \
85 _(ICMP_PACKETS, "ICMP packets") \
86 _(OTHER_PACKETS, "other protocol packets") \
87 _(FRAGMENTS, "fragments") \
88 _(CACHED_FRAGMENTS, "cached fragments") \
89 _(PROCESSED_FRAGMENTS, "processed fragments")
90 
91 typedef enum
92 {
93 #define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
95 #undef _
98 
99 static char *snat_out2in_error_strings[] = {
100 #define _(sym,string) string,
102 #undef _
103 };
104 
105 typedef enum
106 {
112 
113 #ifndef CLIB_MARCH_VARIANT
114 int
116 {
117  snat_main_t *sm = &snat_main;
119  snat_session_t *s;
120  u64 sess_timeout_time;
122  ctx->thread_index);
124 
125  s = pool_elt_at_index (tsm->sessions, kv->value);
126  sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
127  if (ctx->now >= sess_timeout_time)
128  {
129  s_kv.key = s->in2out.as_u64;
130  if (clib_bihash_add_del_8_8 (&tsm->in2out, &s_kv, 0))
131  nat_elog_warn ("out2in key del failed");
132 
134  s->in2out.addr.as_u32,
135  s->out2in.addr.as_u32,
136  s->in2out.protocol,
137  s->in2out.port,
138  s->out2in.port,
139  s->in2out.fib_index);
140 
141  nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
142  &s->in2out.addr, s->in2out.port,
143  &s->out2in.addr, s->out2in.port,
144  s->in2out.protocol);
145 
146  nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
147  s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
148  ctx->thread_index);
149 
150  if (!snat_is_session_static (s))
152  &s->out2in);
153 
154  nat44_delete_session (sm, s, ctx->thread_index);
155  return 1;
156  }
157 
158  return 0;
159 }
160 #endif
161 
162 /**
163  * @brief Create session for static mapping.
164  *
165  * Create NAT session initiated by host from external network with static
166  * mapping.
167  *
168  * @param sm NAT main.
169  * @param b0 Vlib buffer.
170  * @param in2out In2out NAT44 session key.
171  * @param out2in Out2in NAT44 session key.
172  * @param node Vlib node.
173  *
174  * @returns SNAT session if successfully created otherwise 0.
175  */
176 static inline snat_session_t *
178  vlib_buffer_t * b0,
179  snat_session_key_t in2out,
180  snat_session_key_t out2in,
182  u32 thread_index, f64 now)
183 {
184  snat_user_t *u;
185  snat_session_t *s;
187  ip4_header_t *ip0;
188  udp_header_t *udp0;
190 
191  nat44_session_try_cleanup (&in2out.addr, in2out.fib_index, thread_index,
192  now);
193 
194  if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
195  {
196  b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
197  nat_elog_notice ("maximum sessions exceeded");
198  return 0;
199  }
200 
201  ip0 = vlib_buffer_get_current (b0);
202  udp0 = ip4_next_header (ip0);
203 
204  u =
205  nat_user_get_or_create (sm, &in2out.addr, in2out.fib_index, thread_index);
206  if (!u)
207  {
208  nat_elog_warn ("create NAT user failed");
209  return 0;
210  }
211 
212  s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
213  if (!s)
214  {
215  nat44_delete_user_with_no_session (sm, u, thread_index);
216  nat_elog_warn ("create NAT session failed");
217  return 0;
218  }
219 
221  s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
222  s->ext_host_port = udp0->src_port;
223  user_session_increment (sm, u, 1 /* static */ );
224  s->in2out = in2out;
225  s->out2in = out2in;
226  s->in2out.protocol = out2in.protocol;
227 
228  /* Add to translation hashes */
229  ctx0.now = now;
230  ctx0.thread_index = thread_index;
231  kv0.key = s->in2out.as_u64;
232  kv0.value = s - sm->per_thread_data[thread_index].sessions;
233  if (clib_bihash_add_or_overwrite_stale_8_8
234  (&sm->per_thread_data[thread_index].in2out, &kv0,
236  nat_elog_notice ("in2out key add failed");
237 
238  kv0.key = s->out2in.as_u64;
239 
240  if (clib_bihash_add_or_overwrite_stale_8_8
241  (&sm->per_thread_data[thread_index].out2in, &kv0,
243  nat_elog_notice ("out2in key add failed");
244 
245  /* log NAT event */
247  s->in2out.addr.as_u32,
248  s->out2in.addr.as_u32,
249  s->in2out.protocol,
250  s->in2out.port,
251  s->out2in.port, s->in2out.fib_index);
252 
253  nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index,
254  &s->in2out.addr, s->in2out.port, &s->out2in.addr,
255  s->out2in.port, s->in2out.protocol);
256 
257  nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
258  s->out2in.port, &s->ext_host_addr, s->ext_host_port,
259  &s->ext_host_nat_addr, s->ext_host_nat_port,
260  s->in2out.protocol, s->in2out.fib_index, s->flags,
261  thread_index, 0);
262 
263  return s;
264 }
265 
266 #ifndef CLIB_MARCH_VARIANT
269  snat_session_key_t * p_key0)
270 {
271  icmp46_header_t *icmp0;
272  snat_session_key_t key0;
273  icmp_echo_header_t *echo0, *inner_echo0 = 0;
274  ip4_header_t *inner_ip0;
275  void *l4_header = 0;
276  icmp46_header_t *inner_icmp0;
277 
278  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
279  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
280 
282  (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
283  {
284  key0.protocol = SNAT_PROTOCOL_ICMP;
285  key0.addr = ip0->dst_address;
286  key0.port = vnet_buffer (b)->ip.reass.l4_src_port; // TODO should this be dst port?
287  }
288  else
289  {
290  inner_ip0 = (ip4_header_t *) (echo0 + 1);
291  l4_header = ip4_next_header (inner_ip0);
292  key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
293  key0.addr = inner_ip0->src_address;
294  switch (key0.protocol)
295  {
296  case SNAT_PROTOCOL_ICMP:
297  inner_icmp0 = (icmp46_header_t *) l4_header;
298  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
299  key0.port = inner_echo0->identifier;
300  break;
301  case SNAT_PROTOCOL_UDP:
302  case SNAT_PROTOCOL_TCP:
303  key0.port = ((tcp_udp_header_t *) l4_header)->src_port;
304  break;
305  default:
306  return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
307  }
308  }
309  *p_key0 = key0;
310  return -1; /* success */
311 }
312 
313 /**
314  * Get address and port values to be used for ICMP packet translation
315  * and create session if needed
316  *
317  * @param[in,out] sm NAT main
318  * @param[in,out] node NAT node runtime
319  * @param[in] thread_index thread index
320  * @param[in,out] b0 buffer containing packet to be translated
321  * @param[out] p_proto protocol used for matching
322  * @param[out] p_value address and port after NAT translation
323  * @param[out] p_dont_translate if packet should not be translated
324  * @param d optional parameter
325  * @param e optional parameter
326  */
327 u32
329  u32 thread_index, vlib_buffer_t * b0,
330  ip4_header_t * ip0, u8 * p_proto,
331  snat_session_key_t * p_value,
332  u8 * p_dont_translate, void *d, void *e)
333 {
334  u32 sw_if_index0;
335  u32 rx_fib_index0;
336  snat_session_key_t key0;
337  snat_session_key_t sm0;
338  snat_session_t *s0 = 0;
339  u8 dont_translate = 0;
340  clib_bihash_kv_8_8_t kv0, value0;
341  u8 is_addr_only;
342  u32 next0 = ~0;
343  int err;
344  u8 identity_nat;
345 
346  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
347  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
348 
349  key0.protocol = 0;
350 
351  err = icmp_get_key (b0, ip0, &key0);
352  if (err != -1)
353  {
354  b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
355  next0 = SNAT_OUT2IN_NEXT_DROP;
356  goto out;
357  }
358  key0.fib_index = rx_fib_index0;
359 
360  kv0.key = key0.as_u64;
361 
362  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
363  &value0))
364  {
365  /* Try to match static mapping by external address and port,
366  destination address and port in packet */
368  (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0, &identity_nat))
369  {
370  if (!sm->forwarding_enabled)
371  {
372  /* Don't NAT packet aimed at the intfc address */
373  if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index0,
374  ip0->dst_address.as_u32)))
375  {
376  dont_translate = 1;
377  goto out;
378  }
379  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
380  next0 = SNAT_OUT2IN_NEXT_DROP;
381  goto out;
382  }
383  else
384  {
385  dont_translate = 1;
386  goto out;
387  }
388  }
389 
390  if (PREDICT_FALSE
391  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
392  ICMP4_echo_reply
393  && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
394  ICMP4_echo_request || !is_addr_only)))
395  {
396  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
397  next0 = SNAT_OUT2IN_NEXT_DROP;
398  goto out;
399  }
400 
401  if (PREDICT_FALSE (identity_nat))
402  {
403  dont_translate = 1;
404  goto out;
405  }
406  /* Create session initiated by host from external network */
407  s0 = create_session_for_static_mapping (sm, b0, sm0, key0,
408  node, thread_index,
409  vlib_time_now (sm->vlib_main));
410 
411  if (!s0)
412  {
413  next0 = SNAT_OUT2IN_NEXT_DROP;
414  goto out;
415  }
416  }
417  else
418  {
419  if (PREDICT_FALSE
420  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
421  ICMP4_echo_reply
422  && vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
423  ICMP4_echo_request
425  reass.icmp_type_or_tcp_flags)))
426  {
427  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
428  next0 = SNAT_OUT2IN_NEXT_DROP;
429  goto out;
430  }
431 
432  s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
433  value0.value);
434  }
435 
436 out:
437  *p_proto = key0.protocol;
438  if (s0)
439  *p_value = s0->in2out;
440  *p_dont_translate = dont_translate;
441  if (d)
442  *(snat_session_t **) d = s0;
443  return next0;
444 }
445 #endif
446 
447 #ifndef CLIB_MARCH_VARIANT
448 /**
449  * Get address and port values to be used for ICMP packet translation
450  *
451  * @param[in] sm NAT main
452  * @param[in,out] node NAT node runtime
453  * @param[in] thread_index thread index
454  * @param[in,out] b0 buffer containing packet to be translated
455  * @param[out] p_proto protocol used for matching
456  * @param[out] p_value address and port after NAT translation
457  * @param[out] p_dont_translate if packet should not be translated
458  * @param d optional parameter
459  * @param e optional parameter
460  */
461 u32
463  u32 thread_index, vlib_buffer_t * b0,
464  ip4_header_t * ip0, u8 * p_proto,
465  snat_session_key_t * p_value,
466  u8 * p_dont_translate, void *d, void *e)
467 {
468  u32 sw_if_index0;
469  u32 rx_fib_index0;
470  snat_session_key_t key0;
471  snat_session_key_t sm0;
472  u8 dont_translate = 0;
473  u8 is_addr_only;
474  u32 next0 = ~0;
475  int err;
476 
477  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
478  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
479 
480  err = icmp_get_key (b0, ip0, &key0);
481  if (err != -1)
482  {
483  b0->error = node->errors[err];
484  next0 = SNAT_OUT2IN_NEXT_DROP;
485  goto out2;
486  }
487  key0.fib_index = rx_fib_index0;
488 
490  (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0, 0))
491  {
492  /* Don't NAT packet aimed at the intfc address */
493  if (is_interface_addr (sm, node, sw_if_index0, ip0->dst_address.as_u32))
494  {
495  dont_translate = 1;
496  goto out;
497  }
498  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
499  next0 = SNAT_OUT2IN_NEXT_DROP;
500  goto out;
501  }
502 
503  if (PREDICT_FALSE
504  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_reply
505  && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
506  ICMP4_echo_request || !is_addr_only)
508  reass.icmp_type_or_tcp_flags)))
509  {
510  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
511  next0 = SNAT_OUT2IN_NEXT_DROP;
512  goto out;
513  }
514 
515 out:
516  *p_value = sm0;
517 out2:
518  *p_proto = key0.protocol;
519  *p_dont_translate = dont_translate;
520  return next0;
521 }
522 #endif
523 
524 #ifndef CLIB_MARCH_VARIANT
525 u32
527  vlib_buffer_t * b0,
528  ip4_header_t * ip0,
529  icmp46_header_t * icmp0,
530  u32 sw_if_index0,
531  u32 rx_fib_index0,
533  u32 next0, u32 thread_index, void *d, void *e)
534 {
535  snat_session_key_t sm0;
536  u8 protocol;
537  icmp_echo_header_t *echo0, *inner_echo0 = 0;
538  ip4_header_t *inner_ip0 = 0;
539  void *l4_header = 0;
540  icmp46_header_t *inner_icmp0;
541  u8 dont_translate;
542  u32 new_addr0, old_addr0;
543  u16 old_id0, new_id0;
544  ip_csum_t sum0;
545  u16 checksum0;
546  u32 next0_tmp;
547 
548  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
549 
550  next0_tmp = sm->icmp_match_out2in_cb (sm, node, thread_index, b0, ip0,
551  &protocol, &sm0, &dont_translate, d,
552  e);
553  if (next0_tmp != ~0)
554  next0 = next0_tmp;
555  if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
556  goto out;
557 
558  if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
559  {
560  sum0 = ip_incremental_checksum_buffer (sm->vlib_main, b0, (u8 *) icmp0 -
561  (u8 *)
563  ntohs (ip0->length) -
564  ip4_header_bytes (ip0), 0);
565  checksum0 = ~ip_csum_fold (sum0);
566  if (checksum0 != 0 && checksum0 != 0xffff)
567  {
568  next0 = SNAT_OUT2IN_NEXT_DROP;
569  goto out;
570  }
571  }
572 
573  old_addr0 = ip0->dst_address.as_u32;
574  new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32;
575  vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
576 
577  sum0 = ip0->checksum;
578  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
579  dst_address /* changed member */ );
580  ip0->checksum = ip_csum_fold (sum0);
581 
582 
583  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
584  {
585  if (icmp0->checksum == 0)
586  icmp0->checksum = 0xffff;
587 
588  if (!icmp_type_is_error_message (icmp0->type))
589  {
590  new_id0 = sm0.port;
591  if (PREDICT_FALSE (new_id0 != echo0->identifier))
592  {
593  old_id0 = echo0->identifier;
594  new_id0 = sm0.port;
595  echo0->identifier = new_id0;
596 
597  sum0 = icmp0->checksum;
598  sum0 =
599  ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
600  identifier /* changed member */ );
601  icmp0->checksum = ip_csum_fold (sum0);
602  }
603  }
604  else
605  {
606  inner_ip0 = (ip4_header_t *) (echo0 + 1);
607  l4_header = ip4_next_header (inner_ip0);
608 
609  if (!ip4_header_checksum_is_valid (inner_ip0))
610  {
611  next0 = SNAT_OUT2IN_NEXT_DROP;
612  goto out;
613  }
614 
615  old_addr0 = inner_ip0->src_address.as_u32;
616  inner_ip0->src_address = sm0.addr;
617  new_addr0 = inner_ip0->src_address.as_u32;
618 
619  sum0 = icmp0->checksum;
620  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
621  src_address /* changed member */ );
622  icmp0->checksum = ip_csum_fold (sum0);
623 
624  switch (protocol)
625  {
626  case SNAT_PROTOCOL_ICMP:
627  inner_icmp0 = (icmp46_header_t *) l4_header;
628  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
629 
630  old_id0 = inner_echo0->identifier;
631  new_id0 = sm0.port;
632  inner_echo0->identifier = new_id0;
633 
634  sum0 = icmp0->checksum;
635  sum0 =
636  ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
637  identifier);
638  icmp0->checksum = ip_csum_fold (sum0);
639  break;
640  case SNAT_PROTOCOL_UDP:
641  case SNAT_PROTOCOL_TCP:
642  old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
643  new_id0 = sm0.port;
644  ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
645 
646  sum0 = icmp0->checksum;
647  sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
648  src_port);
649  icmp0->checksum = ip_csum_fold (sum0);
650  break;
651  default:
652  ASSERT (0);
653  }
654  }
655  }
656 
657 out:
658  return next0;
659 }
660 #endif
661 
662 static inline u32
664  vlib_buffer_t * b0,
665  ip4_header_t * ip0,
666  icmp46_header_t * icmp0,
667  u32 sw_if_index0,
668  u32 rx_fib_index0,
670  u32 next0, f64 now,
671  u32 thread_index, snat_session_t ** p_s0)
672 {
673  next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
674  next0, thread_index, p_s0, 0);
675  snat_session_t *s0 = *p_s0;
676  if (PREDICT_TRUE (next0 != SNAT_OUT2IN_NEXT_DROP && s0))
677  {
678  /* Accounting */
681  (sm->vlib_main, b0), thread_index);
682  /* Per-user LRU list maintenance */
683  nat44_session_update_lru (sm, s0, thread_index);
684  }
685  return next0;
686 }
687 
688 static int
690  vlib_buffer_t * b,
691  ip4_header_t * ip, u32 rx_fib_index)
692 {
695  snat_session_key_t m_key;
696  u32 old_addr, new_addr;
697  ip_csum_t sum;
698 
699  m_key.addr = ip->dst_address;
700  m_key.port = 0;
701  m_key.protocol = 0;
702  m_key.fib_index = 0;
703  kv.key = m_key.as_u64;
704  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
705  return 1;
706 
707  m = pool_elt_at_index (sm->static_mappings, value.value);
708 
709  old_addr = ip->dst_address.as_u32;
710  new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
711  sum = ip->checksum;
712  sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
713  ip->checksum = ip_csum_fold (sum);
714 
715  vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
716  return 0;
717 }
718 
722 {
723  u32 n_left_from, *from, *to_next;
724  snat_out2in_next_t next_index;
725  u32 pkts_processed = 0;
726  snat_main_t *sm = &snat_main;
727  f64 now = vlib_time_now (vm);
728  u32 thread_index = vm->thread_index;
729  u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
730  0, fragments = 0;
731 
732  from = vlib_frame_vector_args (frame);
733  n_left_from = frame->n_vectors;
734  next_index = node->cached_next_index;
735 
736  while (n_left_from > 0)
737  {
738  u32 n_left_to_next;
739 
740  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
741 
742  while (n_left_from >= 4 && n_left_to_next >= 2)
743  {
744  u32 bi0, bi1;
745  vlib_buffer_t *b0, *b1;
748  u32 sw_if_index0, sw_if_index1;
749  ip4_header_t *ip0, *ip1;
750  ip_csum_t sum0, sum1;
751  u32 new_addr0, old_addr0;
752  u16 new_port0, old_port0;
753  u32 new_addr1, old_addr1;
754  u16 new_port1, old_port1;
755  udp_header_t *udp0, *udp1;
756  tcp_header_t *tcp0, *tcp1;
757  icmp46_header_t *icmp0, *icmp1;
758  snat_session_key_t key0, key1, sm0, sm1;
759  u32 rx_fib_index0, rx_fib_index1;
760  u32 proto0, proto1;
761  snat_session_t *s0 = 0, *s1 = 0;
762  clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
763  u8 identity_nat0, identity_nat1;
764 
765  /* Prefetch next iteration. */
766  {
767  vlib_buffer_t *p2, *p3;
768 
769  p2 = vlib_get_buffer (vm, from[2]);
770  p3 = vlib_get_buffer (vm, from[3]);
771 
772  vlib_prefetch_buffer_header (p2, LOAD);
773  vlib_prefetch_buffer_header (p3, LOAD);
774 
777  }
778 
779  /* speculatively enqueue b0 and b1 to the current next frame */
780  to_next[0] = bi0 = from[0];
781  to_next[1] = bi1 = from[1];
782  from += 2;
783  to_next += 2;
784  n_left_from -= 2;
785  n_left_to_next -= 2;
786 
787  b0 = vlib_get_buffer (vm, bi0);
788  b1 = vlib_get_buffer (vm, bi1);
789 
790  vnet_buffer (b0)->snat.flags = 0;
791  vnet_buffer (b1)->snat.flags = 0;
792 
793  ip0 = vlib_buffer_get_current (b0);
794  udp0 = ip4_next_header (ip0);
795  tcp0 = (tcp_header_t *) udp0;
796  icmp0 = (icmp46_header_t *) udp0;
797 
798  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
799  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
800  sw_if_index0);
801 
802  if (PREDICT_FALSE (ip0->ttl == 1))
803  {
804  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
805  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
806  ICMP4_time_exceeded_ttl_exceeded_in_transit,
807  0);
809  goto trace0;
810  }
811 
812  proto0 = ip_proto_to_snat_proto (ip0->protocol);
813 
814  if (PREDICT_FALSE (proto0 == ~0))
815  {
816  if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
817  {
818  if (!sm->forwarding_enabled)
819  {
820  b0->error =
821  node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
822  next0 = SNAT_OUT2IN_NEXT_DROP;
823  }
824  }
825  other_packets++;
826  goto trace0;
827  }
828 
829  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
830  {
831  next0 = icmp_out2in_slow_path
832  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
833  next0, now, thread_index, &s0);
834  icmp_packets++;
835  goto trace0;
836  }
837 
838  key0.addr = ip0->dst_address;
839  key0.port = vnet_buffer (b0)->ip.reass.l4_dst_port;
840  key0.protocol = proto0;
841  key0.fib_index = rx_fib_index0;
842 
843  kv0.key = key0.as_u64;
844 
845  if (clib_bihash_search_8_8
846  (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
847  {
848  /* Try to match static mapping by external address and port,
849  destination address and port in packet */
851  (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
852  {
853  /*
854  * Send DHCP packets to the ipv4 stack, or we won't
855  * be able to use dhcp client on the outside interface
856  */
857  if (PREDICT_FALSE
858  (proto0 == SNAT_PROTOCOL_UDP
859  && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
860  clib_host_to_net_u16
861  (UDP_DST_PORT_dhcp_to_client))))
862  {
863  vnet_feature_next (&next0, b0);
864  goto trace0;
865  }
866 
867  if (!sm->forwarding_enabled)
868  {
869  b0->error =
870  node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
871  next0 = SNAT_OUT2IN_NEXT_DROP;
872  }
873  goto trace0;
874  }
875 
876  if (PREDICT_FALSE (identity_nat0))
877  goto trace0;
878 
879  /* Create session initiated by host from external network */
880  s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
881  thread_index, now);
882  if (!s0)
883  {
884  next0 = SNAT_OUT2IN_NEXT_DROP;
885  goto trace0;
886  }
887  }
888  else
889  s0 =
890  pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
891  value0.value);
892 
893  old_addr0 = ip0->dst_address.as_u32;
894  ip0->dst_address = s0->in2out.addr;
895  new_addr0 = ip0->dst_address.as_u32;
896  vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
897 
898  sum0 = ip0->checksum;
899  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
900  ip4_header_t,
901  dst_address /* changed member */ );
902  ip0->checksum = ip_csum_fold (sum0);
903 
904  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
905  {
906  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
907  {
908  old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
909  new_port0 = udp0->dst_port = s0->in2out.port;
910  sum0 = tcp0->checksum;
911  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
912  ip4_header_t,
913  dst_address /* changed member */ );
914 
915  sum0 = ip_csum_update (sum0, old_port0, new_port0,
916  ip4_header_t /* cheat */ ,
917  length /* changed member */ );
918  tcp0->checksum = ip_csum_fold (sum0);
919  }
920  tcp_packets++;
921  }
922  else
923  {
924  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
925  {
926  old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
927  new_port0 = udp0->dst_port = s0->in2out.port;
928  if (PREDICT_FALSE (udp0->checksum))
929  {
930  sum0 = udp0->checksum;
931  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
932  );
933  sum0 =
934  ip_csum_update (sum0, old_port0, new_port0,
935  ip4_header_t /* cheat */ ,
936  length /* changed member */ );
937  udp0->checksum = ip_csum_fold (sum0);
938  }
939  }
940  udp_packets++;
941  }
942 
943  /* Accounting */
946  thread_index);
947  /* Per-user LRU list maintenance */
948  nat44_session_update_lru (sm, s0, thread_index);
949  trace0:
950 
951  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
952  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
953  {
955  vlib_add_trace (vm, node, b0, sizeof (*t));
956  t->sw_if_index = sw_if_index0;
957  t->next_index = next0;
958  t->session_index = ~0;
959  if (s0)
960  t->session_index =
961  s0 - sm->per_thread_data[thread_index].sessions;
962  }
963 
964  pkts_processed += next0 == SNAT_OUT2IN_NEXT_LOOKUP;
965 
966 
967  ip1 = vlib_buffer_get_current (b1);
968  udp1 = ip4_next_header (ip1);
969  tcp1 = (tcp_header_t *) udp1;
970  icmp1 = (icmp46_header_t *) udp1;
971 
972  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
973  rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
974  sw_if_index1);
975 
976  if (PREDICT_FALSE (ip1->ttl == 1))
977  {
978  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
979  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
980  ICMP4_time_exceeded_ttl_exceeded_in_transit,
981  0);
983  goto trace1;
984  }
985 
986  proto1 = ip_proto_to_snat_proto (ip1->protocol);
987 
988  if (PREDICT_FALSE (proto1 == ~0))
989  {
990  if (nat_out2in_sm_unknown_proto (sm, b1, ip1, rx_fib_index1))
991  {
992  if (!sm->forwarding_enabled)
993  {
994  b1->error =
995  node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
996  next1 = SNAT_OUT2IN_NEXT_DROP;
997  }
998  }
999  other_packets++;
1000  goto trace1;
1001  }
1002 
1003  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1004  {
1005  next1 = icmp_out2in_slow_path
1006  (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1007  next1, now, thread_index, &s1);
1008  icmp_packets++;
1009  goto trace1;
1010  }
1011 
1012  key1.addr = ip1->dst_address;
1013  key1.port = vnet_buffer (b1)->ip.reass.l4_dst_port;
1014  key1.protocol = proto1;
1015  key1.fib_index = rx_fib_index1;
1016 
1017  kv1.key = key1.as_u64;
1018 
1019  if (clib_bihash_search_8_8
1020  (&sm->per_thread_data[thread_index].out2in, &kv1, &value1))
1021  {
1022  /* Try to match static mapping by external address and port,
1023  destination address and port in packet */
1025  (sm, key1, &sm1, 1, 0, 0, 0, 0, &identity_nat1))
1026  {
1027  /*
1028  * Send DHCP packets to the ipv4 stack, or we won't
1029  * be able to use dhcp client on the outside interface
1030  */
1031  if (PREDICT_FALSE
1032  (proto1 == SNAT_PROTOCOL_UDP
1033  && (vnet_buffer (b1)->ip.reass.l4_dst_port ==
1034  clib_host_to_net_u16
1035  (UDP_DST_PORT_dhcp_to_client))))
1036  {
1037  vnet_feature_next (&next1, b1);
1038  goto trace1;
1039  }
1040 
1041  if (!sm->forwarding_enabled)
1042  {
1043  b1->error =
1044  node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1045  next1 = SNAT_OUT2IN_NEXT_DROP;
1046  }
1047  goto trace1;
1048  }
1049 
1050  if (PREDICT_FALSE (identity_nat1))
1051  goto trace1;
1052 
1053  /* Create session initiated by host from external network */
1054  s1 = create_session_for_static_mapping (sm, b1, sm1, key1, node,
1055  thread_index, now);
1056  if (!s1)
1057  {
1058  next1 = SNAT_OUT2IN_NEXT_DROP;
1059  goto trace1;
1060  }
1061  }
1062  else
1063  s1 =
1064  pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1065  value1.value);
1066 
1067  old_addr1 = ip1->dst_address.as_u32;
1068  ip1->dst_address = s1->in2out.addr;
1069  new_addr1 = ip1->dst_address.as_u32;
1070  vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1071 
1072  sum1 = ip1->checksum;
1073  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1074  ip4_header_t,
1075  dst_address /* changed member */ );
1076  ip1->checksum = ip_csum_fold (sum1);
1077 
1078  if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
1079  {
1080  if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1081  {
1082  old_port1 = vnet_buffer (b1)->ip.reass.l4_dst_port;
1083  new_port1 = udp1->dst_port = s1->in2out.port;
1084 
1085  sum1 = tcp1->checksum;
1086  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1087  ip4_header_t,
1088  dst_address /* changed member */ );
1089 
1090  sum1 = ip_csum_update (sum1, old_port1, new_port1,
1091  ip4_header_t /* cheat */ ,
1092  length /* changed member */ );
1093  tcp1->checksum = ip_csum_fold (sum1);
1094  }
1095  tcp_packets++;
1096  }
1097  else
1098  {
1099  if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1100  {
1101  old_port1 = vnet_buffer (b1)->ip.reass.l4_dst_port;
1102  new_port1 = udp1->dst_port = s1->in2out.port;
1103  if (PREDICT_FALSE (udp1->checksum))
1104  {
1105 
1106  sum1 = udp1->checksum;
1107  sum1 =
1108  ip_csum_update (sum1, old_addr1, new_addr1,
1109  ip4_header_t,
1110  dst_address /* changed member */ );
1111  sum1 =
1112  ip_csum_update (sum1, old_port1, new_port1,
1113  ip4_header_t /* cheat */ ,
1114  length /* changed member */ );
1115  udp1->checksum = ip_csum_fold (sum1);
1116  }
1117  }
1118  udp_packets++;
1119  }
1120 
1121  /* Accounting */
1123  vlib_buffer_length_in_chain (vm, b1),
1124  thread_index);
1125  /* Per-user LRU list maintenance */
1126  nat44_session_update_lru (sm, s1, thread_index);
1127  trace1:
1128 
1129  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1130  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1131  {
1132  snat_out2in_trace_t *t =
1133  vlib_add_trace (vm, node, b1, sizeof (*t));
1134  t->sw_if_index = sw_if_index1;
1135  t->next_index = next1;
1136  t->session_index = ~0;
1137  if (s1)
1138  t->session_index =
1139  s1 - sm->per_thread_data[thread_index].sessions;
1140  }
1141 
1142  pkts_processed += next1 == SNAT_OUT2IN_NEXT_LOOKUP;
1143 
1144  /* verify speculative enqueues, maybe switch current next frame */
1145  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1146  to_next, n_left_to_next,
1147  bi0, bi1, next0, next1);
1148  }
1149 
1150  while (n_left_from > 0 && n_left_to_next > 0)
1151  {
1152  u32 bi0;
1153  vlib_buffer_t *b0;
1154  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1155  u32 sw_if_index0;
1156  ip4_header_t *ip0;
1157  ip_csum_t sum0;
1158  u32 new_addr0, old_addr0;
1159  u16 new_port0, old_port0;
1160  udp_header_t *udp0;
1161  tcp_header_t *tcp0;
1162  icmp46_header_t *icmp0;
1163  snat_session_key_t key0, sm0;
1164  u32 rx_fib_index0;
1165  u32 proto0;
1166  snat_session_t *s0 = 0;
1167  clib_bihash_kv_8_8_t kv0, value0;
1168  u8 identity_nat0;
1169 
1170  /* speculatively enqueue b0 to the current next frame */
1171  bi0 = from[0];
1172  to_next[0] = bi0;
1173  from += 1;
1174  to_next += 1;
1175  n_left_from -= 1;
1176  n_left_to_next -= 1;
1177 
1178  b0 = vlib_get_buffer (vm, bi0);
1179 
1180  vnet_buffer (b0)->snat.flags = 0;
1181 
1182  ip0 = vlib_buffer_get_current (b0);
1183  udp0 = ip4_next_header (ip0);
1184  tcp0 = (tcp_header_t *) udp0;
1185  icmp0 = (icmp46_header_t *) udp0;
1186 
1187  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1188  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1189  sw_if_index0);
1190 
1191  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1192 
1193  if (PREDICT_FALSE (proto0 == ~0))
1194  {
1195  if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
1196  {
1197  if (!sm->forwarding_enabled)
1198  {
1199  b0->error =
1200  node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1201  next0 = SNAT_OUT2IN_NEXT_DROP;
1202  }
1203  }
1204  other_packets++;
1205  goto trace00;
1206  }
1207 
1208  if (PREDICT_FALSE (ip0->ttl == 1))
1209  {
1210  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1211  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1212  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1213  0);
1215  goto trace00;
1216  }
1217 
1218  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1219  {
1220  next0 = icmp_out2in_slow_path
1221  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1222  next0, now, thread_index, &s0);
1223  icmp_packets++;
1224  goto trace00;
1225  }
1226 
1227  key0.addr = ip0->dst_address;
1228  key0.port = vnet_buffer (b0)->ip.reass.l4_dst_port;
1229  key0.protocol = proto0;
1230  key0.fib_index = rx_fib_index0;
1231 
1232  kv0.key = key0.as_u64;
1233 
1234  if (clib_bihash_search_8_8
1235  (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
1236  {
1237  /* Try to match static mapping by external address and port,
1238  destination address and port in packet */
1240  (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
1241  {
1242  /*
1243  * Send DHCP packets to the ipv4 stack, or we won't
1244  * be able to use dhcp client on the outside interface
1245  */
1246  if (PREDICT_FALSE
1247  (proto0 == SNAT_PROTOCOL_UDP
1248  && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1249  clib_host_to_net_u16
1250  (UDP_DST_PORT_dhcp_to_client))))
1251  {
1252  vnet_feature_next (&next0, b0);
1253  goto trace00;
1254  }
1255 
1256  if (!sm->forwarding_enabled)
1257  {
1258  b0->error =
1259  node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1260  next0 = SNAT_OUT2IN_NEXT_DROP;
1261  }
1262  goto trace00;
1263  }
1264 
1265  if (PREDICT_FALSE (identity_nat0))
1266  goto trace00;
1267 
1268  /* Create session initiated by host from external network */
1269  s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
1270  thread_index, now);
1271  if (!s0)
1272  {
1273  next0 = SNAT_OUT2IN_NEXT_DROP;
1274  goto trace00;
1275  }
1276  }
1277  else
1278  s0 =
1279  pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1280  value0.value);
1281 
1282  old_addr0 = ip0->dst_address.as_u32;
1283  ip0->dst_address = s0->in2out.addr;
1284  new_addr0 = ip0->dst_address.as_u32;
1285  vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1286 
1287  sum0 = ip0->checksum;
1288  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1289  ip4_header_t,
1290  dst_address /* changed member */ );
1291  ip0->checksum = ip_csum_fold (sum0);
1292 
1293  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1294  {
1295  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1296  {
1297  old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
1298  new_port0 = udp0->dst_port = s0->in2out.port;
1299 
1300  sum0 = tcp0->checksum;
1301  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1302  ip4_header_t,
1303  dst_address /* changed member */ );
1304 
1305  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1306  ip4_header_t /* cheat */ ,
1307  length /* changed member */ );
1308  tcp0->checksum = ip_csum_fold (sum0);
1309  }
1310  tcp_packets++;
1311  }
1312  else
1313  {
1314  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1315  {
1316  old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
1317  new_port0 = udp0->dst_port = s0->in2out.port;
1318  if (PREDICT_FALSE (udp0->checksum))
1319  {
1320  sum0 = udp0->checksum;
1321  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
1322  );
1323  sum0 =
1324  ip_csum_update (sum0, old_port0, new_port0,
1325  ip4_header_t /* cheat */ ,
1326  length /* changed member */ );
1327  udp0->checksum = ip_csum_fold (sum0);
1328  }
1329  }
1330  udp_packets++;
1331  }
1332 
1333  /* Accounting */
1335  vlib_buffer_length_in_chain (vm, b0),
1336  thread_index);
1337  /* Per-user LRU list maintenance */
1338  nat44_session_update_lru (sm, s0, thread_index);
1339  trace00:
1340 
1341  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1342  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1343  {
1344  snat_out2in_trace_t *t =
1345  vlib_add_trace (vm, node, b0, sizeof (*t));
1346  t->sw_if_index = sw_if_index0;
1347  t->next_index = next0;
1348  t->session_index = ~0;
1349  if (s0)
1350  t->session_index =
1351  s0 - sm->per_thread_data[thread_index].sessions;
1352  }
1353 
1354  pkts_processed += next0 == SNAT_OUT2IN_NEXT_LOOKUP;
1355 
1356  /* verify speculative enqueue, maybe switch current next frame */
1357  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1358  to_next, n_left_to_next,
1359  bi0, next0);
1360  }
1361 
1362  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1363  }
1364 
1366  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1367  pkts_processed);
1369  SNAT_OUT2IN_ERROR_TCP_PACKETS, tcp_packets);
1371  SNAT_OUT2IN_ERROR_UDP_PACKETS, udp_packets);
1373  SNAT_OUT2IN_ERROR_ICMP_PACKETS, icmp_packets);
1375  SNAT_OUT2IN_ERROR_OTHER_PACKETS,
1376  other_packets);
1378  SNAT_OUT2IN_ERROR_FRAGMENTS, fragments);
1379 
1380  return frame->n_vectors;
1381 }
1382 
1383 /* *INDENT-OFF* */
1385  .name = "nat44-out2in",
1386  .vector_size = sizeof (u32),
1387  .format_trace = format_snat_out2in_trace,
1389 
1390  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1391  .error_strings = snat_out2in_error_strings,
1392 
1393  .runtime_data_bytes = sizeof (snat_runtime_t),
1394 
1395  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1396 
1397  /* edit / add dispositions here */
1398  .next_nodes = {
1399  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1400  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1401  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1402  },
1403 };
1404 /* *INDENT-ON* */
1405 
1408  vlib_frame_t * frame)
1409 {
1410  u32 n_left_from, *from, *to_next;
1411  snat_out2in_next_t next_index;
1412  u32 pkts_processed = 0;
1413  snat_main_t *sm = &snat_main;
1414 
1415  from = vlib_frame_vector_args (frame);
1416  n_left_from = frame->n_vectors;
1417  next_index = node->cached_next_index;
1418 
1419  while (n_left_from > 0)
1420  {
1421  u32 n_left_to_next;
1422 
1423  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1424 
1425  while (n_left_from > 0 && n_left_to_next > 0)
1426  {
1427  u32 bi0;
1428  vlib_buffer_t *b0;
1429  u32 next0 = SNAT_OUT2IN_NEXT_DROP;
1430  u32 sw_if_index0;
1431  ip4_header_t *ip0;
1432  ip_csum_t sum0;
1433  u32 new_addr0, old_addr0;
1434  u16 new_port0, old_port0;
1435  udp_header_t *udp0;
1436  tcp_header_t *tcp0;
1437  icmp46_header_t *icmp0;
1438  snat_session_key_t key0, sm0;
1439  u32 proto0;
1440  u32 rx_fib_index0;
1441 
1442  /* speculatively enqueue b0 to the current next frame */
1443  bi0 = from[0];
1444  to_next[0] = bi0;
1445  from += 1;
1446  to_next += 1;
1447  n_left_from -= 1;
1448  n_left_to_next -= 1;
1449 
1450  b0 = vlib_get_buffer (vm, bi0);
1451 
1452  ip0 = vlib_buffer_get_current (b0);
1453  udp0 = ip4_next_header (ip0);
1454  tcp0 = (tcp_header_t *) udp0;
1455  icmp0 = (icmp46_header_t *) udp0;
1456 
1457  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1458  rx_fib_index0 =
1460 
1461  vnet_feature_next (&next0, b0);
1462 
1463  if (PREDICT_FALSE (ip0->ttl == 1))
1464  {
1465  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1466  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1467  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1468  0);
1470  goto trace00;
1471  }
1472 
1473  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1474 
1475  if (PREDICT_FALSE (proto0 == ~0))
1476  goto trace00;
1477 
1478  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1479  {
1480  next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0,
1481  rx_fib_index0, node, next0, ~0, 0, 0);
1482  goto trace00;
1483  }
1484 
1485  key0.addr = ip0->dst_address;
1486  key0.port = udp0->dst_port;
1487  key0.fib_index = rx_fib_index0;
1488 
1489  if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0, 0))
1490  {
1491  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1492  goto trace00;
1493  }
1494 
1495  new_addr0 = sm0.addr.as_u32;
1496  new_port0 = sm0.port;
1497  vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
1498  old_addr0 = ip0->dst_address.as_u32;
1499  ip0->dst_address.as_u32 = new_addr0;
1500 
1501  sum0 = ip0->checksum;
1502  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1503  ip4_header_t,
1504  dst_address /* changed member */ );
1505  ip0->checksum = ip_csum_fold (sum0);
1506 
1507  if (PREDICT_FALSE (new_port0 != udp0->dst_port))
1508  {
1509  old_port0 = udp0->dst_port;
1510  udp0->dst_port = new_port0;
1511 
1512  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1513  {
1514  sum0 = tcp0->checksum;
1515  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1516  ip4_header_t,
1517  dst_address /* changed member */ );
1518  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1519  ip4_header_t /* cheat */ ,
1520  length /* changed member */ );
1521  tcp0->checksum = ip_csum_fold (sum0);
1522  }
1523  else if (udp0->checksum)
1524  {
1525  sum0 = udp0->checksum;
1526  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1527  ip4_header_t,
1528  dst_address /* changed member */ );
1529  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1530  ip4_header_t /* cheat */ ,
1531  length /* changed member */ );
1532  udp0->checksum = ip_csum_fold (sum0);
1533  }
1534  }
1535  else
1536  {
1537  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1538  {
1539  sum0 = tcp0->checksum;
1540  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1541  ip4_header_t,
1542  dst_address /* changed member */ );
1543  tcp0->checksum = ip_csum_fold (sum0);
1544  }
1545  else if (udp0->checksum)
1546  {
1547  sum0 = udp0->checksum;
1548  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1549  ip4_header_t,
1550  dst_address /* changed member */ );
1551  udp0->checksum = ip_csum_fold (sum0);
1552  }
1553  }
1554 
1555  trace00:
1556 
1557  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1558  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1559  {
1560  snat_out2in_trace_t *t =
1561  vlib_add_trace (vm, node, b0, sizeof (*t));
1562  t->sw_if_index = sw_if_index0;
1563  t->next_index = next0;
1564  }
1565 
1566  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1567 
1568  /* verify speculative enqueue, maybe switch current next frame */
1569  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1570  to_next, n_left_to_next,
1571  bi0, next0);
1572  }
1573 
1574  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1575  }
1576 
1578  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1579  pkts_processed);
1580  return frame->n_vectors;
1581 }
1582 
1583 /* *INDENT-OFF* */
1585  .name = "nat44-out2in-fast",
1586  .vector_size = sizeof (u32),
1587  .format_trace = format_snat_out2in_fast_trace,
1589 
1590  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1591  .error_strings = snat_out2in_error_strings,
1592 
1593  .runtime_data_bytes = sizeof (snat_runtime_t),
1594 
1595  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1596 
1597  /* edit / add dispositions here */
1598  .next_nodes = {
1599  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1600  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1601  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1602  },
1603 };
1604 /* *INDENT-ON* */
1605 
1606 /*
1607  * fd.io coding-style-patch-verification: ON
1608  *
1609  * Local Variables:
1610  * eval: (c-set-style "gnu")
1611  * End:
1612  */
vlib_node_registration_t snat_out2in_fast_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_fast_node)
Definition: out2in.c:1584
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:124
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:151
#define snat_is_session_static(s)
Check if SNAT session is created from static mapping.
Definition: nat.h:765
#define CLIB_UNUSED(x)
Definition: clib.h:82
u32 icmp_match_out2in_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: out2in.c:328
ip4_address_t src_address
Definition: ip4_packet.h:170
static u8 * format_snat_out2in_fast_trace(u8 *s, va_list *args)
Definition: out2in.c:62
static u32 nat44_session_get_timeout(snat_main_t *sm, snat_session_t *s)
Definition: nat_inlines.h:394
#define nat_elog_notice(nat_elog_str)
Definition: nat.h:1023
static u32 icmp_out2in_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: out2in.c:663
#define PREDICT_TRUE(x)
Definition: clib.h:112
unsigned long u64
Definition: types.h:89
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:279
u32 thread_index
Definition: main.h:218
u8 data[0]
Packet data.
Definition: buffer.h:181
uword ip_csum_t
Definition: ip_packet.h:244
#define nat_elog_warn(nat_elog_str)
Definition: nat.h:1025
void nat_ha_sadd(ip4_address_t *in_addr, u16 in_port, ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, ip4_address_t *ehn_addr, u16 ehn_port, u8 proto, u32 fib_index, u16 flags, u32 thread_index, u8 is_resync)
Create session add HA event.
Definition: nat_ha.c:689
u32 * fib_index_by_sw_if_index
Table index indexed by software interface.
Definition: ip4.h:121
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define VLIB_NODE_FN(node)
Definition: node.h:202
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
int nat44_o2i_is_idle_session_cb(clib_bihash_kv_8_8_t *kv, void *arg)
Definition: out2in.c:115
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:366
struct _tcp_header tcp_header_t
unsigned char u8
Definition: types.h:56
double f64
Definition: types.h:142
static int ip4_is_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:213
snat_session_t * nat_session_alloc_or_recycle(snat_main_t *sm, snat_user_t *u, u32 thread_index, f64 now)
Allocate new NAT session or recycle last used.
Definition: nat.c:375
u16 src_port
Definition: udp.api:41
clib_bihash_8_8_t in2out
Definition: nat.h:496
vl_api_ip_proto_t protocol
Definition: lb_types.api:71
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:230
#define static_always_inline
Definition: clib.h:99
static uword ip4_header_checksum_is_valid(ip4_header_t *i)
Definition: ip4_packet.h:332
ip4_address_t dst_address
Definition: ip4_packet.h:170
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:203
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
ip4_main_t * ip4_main
Definition: nat.h:700
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:241
unsigned int u32
Definition: types.h:88
#define foreach_snat_out2in_error
Definition: out2in.c:73
ip4_address_t local_addr
Definition: nat.h:441
static u8 maximum_sessions_exceeded(snat_main_t *sm, u32 thread_index)
Definition: nat_inlines.h:215
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:2604
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:2530
static void nat44_delete_session(snat_main_t *sm, snat_session_t *ses, u32 thread_index)
Definition: nat_inlines.h:289
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
snat_out2in_next_t
Definition: out2in.c:105
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:328
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:519
static_always_inline u8 icmp_type_is_error_message(u8 icmp_type)
Definition: nat_inlines.h:174
u64 key
the key
Definition: bihash_8_8.h:35
long ctx[MAX_CONNS]
Definition: main.c:144
vlib_main_t * vlib_main
Definition: nat.h:698
unsigned short u16
Definition: types.h:57
u16 protocol
Definition: nat.h:92
snat_static_mapping_t * static_mappings
Definition: nat.h:577
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
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
clib_bihash_8_8_t static_mapping_by_external
Definition: nat.h:574
vl_api_address_union_t src_address
Definition: ip_types.api:98
#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
vlib_node_registration_t snat_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_node)
Definition: out2in.c:1384
#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:338
vlib_main_t * vm
Definition: in2out_ed.c:1810
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
snat_main_t snat_main
Definition: nat.c:39
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
void snat_ipfix_logging_nat44_ses_delete(u32 thread_index, 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.
u64 value
the value
Definition: bihash_8_8.h:36
static void nat44_delete_user_with_no_session(snat_main_t *sm, snat_user_t *u, u32 thread_index)
Definition: nat_inlines.h:267
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
clib_bihash_8_8_t out2in
Definition: nat.h:495
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:302
static void nat44_session_update_counters(snat_session_t *s, f64 now, uword bytes, u32 thread_index)
Definition: nat_inlines.h:417
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:33
#define ARRAY_LEN(x)
Definition: clib.h:62
ip4_address_t addr
Definition: nat.h:90
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:456
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1810
u8 value
Definition: qos.api:54
#define ASSERT(truth)
snat_icmp_match_function_t * icmp_match_out2in_cb
Definition: nat.h:556
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:431
u32 out2in_node_index
Definition: nat.h:637
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
void nat_ha_sdel(ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index, u32 thread_index)
Create session delete HA event.
Definition: nat_ha.c:715
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:55
#define vec_elt(v, i)
Get vector value at index i.
Definition: defs.h:47
vl_api_address_t ip
Definition: l2.api:490
snat_out2in_error_t
Definition: out2in.c:91
static u32 ip_proto_to_snat_proto(u8 ip_proto)
Definition: nat_inlines.h:147
static void user_session_increment(snat_main_t *sm, snat_user_t *u, u8 is_static)
Definition: nat_inlines.h:255
static snat_session_t * create_session_for_static_mapping(snat_main_t *sm, vlib_buffer_t *b0, snat_session_key_t in2out, snat_session_key_t out2in, vlib_node_runtime_t *node, u32 thread_index, f64 now)
Create session for static mapping.
Definition: out2in.c:177
static char * snat_out2in_error_strings[]
Definition: out2in.c:99
static int nat_out2in_sm_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index)
Definition: out2in.c:689
VLIB buffer representation.
Definition: buffer.h:102
snat_main_per_thread_data_t * per_thread_data
Definition: nat.h:568
static_always_inline void nat44_session_try_cleanup(ip4_address_t *addr, u32 fib_index, u32 thread_index, f64 now)
Definition: nat44_inlines.h:65
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:294
NAT syslog logging.
static u8 is_interface_addr(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, u32 ip4_addr)
Definition: nat_inlines.h:190
static u8 * format_snat_out2in_trace(u8 *s, va_list *args)
Definition: out2in.c:48
snat_address_t * addresses
Definition: nat.h:584
u32 out2in_fast_node_index
Definition: nat.h:638
#define vnet_buffer(b)
Definition: buffer.h:408
#define SNAT_SESSION_FLAG_STATIC_MAPPING
Definition: nat.h:281
u8 forwarding_enabled
Definition: nat.h:656
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1811
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:235
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
static_always_inline snat_out2in_error_t icmp_get_key(vlib_buffer_t *b, ip4_header_t *ip0, snat_session_key_t *p_key0)
Definition: out2in.c:268
u32 icmp_out2in(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: out2in.c:526
int nat44_i2o_is_idle_session_cb(clib_bihash_kv_8_8_t *kv, void *arg)
Definition: in2out.c:195
snat_session_t * sessions
Definition: nat.h:509
static_always_inline void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.h:51
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:300
u32 icmp_match_out2in_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: out2in.c:462
Definition: defs.h:46
NAT active-passive HA.
u16 fib_index
Definition: nat.h:92
void snat_ipfix_logging_nat44_ses_create(u32 thread_index, 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.