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