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