FD.io VPP  v20.05-21-gb1500e9ff
Vector Packet Processing
in2out.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief NAT44 inside to outside network translation
18  */
19 
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22 #include <vnet/pg/pg.h>
23 
24 #include <vnet/ip/ip.h>
25 #include <vnet/ethernet/ethernet.h>
26 #include <vnet/fib/ip4_fib.h>
27 #include <vnet/udp/udp.h>
28 #include <nat/nat.h>
29 #include <nat/nat_ipfix_logging.h>
30 #include <nat/nat_inlines.h>
31 #include <nat/nat44/inlines.h>
32 #include <nat/nat_syslog.h>
33 #include <nat/nat_ha.h>
34 
35 #include <vppinfra/hash.h>
36 #include <vppinfra/error.h>
37 #include <vppinfra/elog.h>
38 
39 typedef struct
40 {
46 
47 /* packet trace format function */
48 static u8 *
49 format_snat_in2out_trace (u8 * s, va_list * args)
50 {
51  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
52  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
53  snat_in2out_trace_t *t = va_arg (*args, snat_in2out_trace_t *);
54  char *tag;
55 
56  tag = t->is_slow_path ? "NAT44_IN2OUT_SLOW_PATH" : "NAT44_IN2OUT_FAST_PATH";
57 
58  s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
60 
61  return s;
62 }
63 
64 static u8 *
65 format_snat_in2out_fast_trace (u8 * s, va_list * args)
66 {
67  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
68  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
69  snat_in2out_trace_t *t = va_arg (*args, snat_in2out_trace_t *);
70 
71  s = format (s, "NAT44_IN2OUT_FAST: sw_if_index %d, next index %d",
72  t->sw_if_index, t->next_index);
73 
74  return s;
75 }
76 
77 #define foreach_snat_in2out_error \
78 _(UNSUPPORTED_PROTOCOL, "unsupported protocol") \
79 _(IN2OUT_PACKETS, "good in2out packets processed") \
80 _(OUT_OF_PORTS, "out of ports") \
81 _(BAD_OUTSIDE_FIB, "outside VRF ID not found") \
82 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
83 _(NO_TRANSLATION, "no translation") \
84 _(MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded") \
85 _(DROP_FRAGMENT, "drop fragment") \
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_IN2OUT_ERROR_##sym,
98 #undef _
101 
102 static char *snat_in2out_error_strings[] = {
103 #define _(sym,string) string,
105 #undef _
106 };
107 
108 typedef enum
109 {
116 
117 static inline int
119  u32 sw_if_index0, ip4_header_t * ip0, u32 proto0,
120  u32 rx_fib_index0, u32 thread_index)
121 {
122  udp_header_t *udp0 = ip4_next_header (ip0);
123  snat_session_key_t key0, sm0;
124  clib_bihash_kv_8_8_t kv0, value0;
125 
126  key0.addr = ip0->dst_address;
127  key0.port = udp0->dst_port;
128  key0.protocol = proto0;
129  key0.fib_index = sm->outside_fib_index;
130  kv0.key = key0.as_u64;
131 
132  /* NAT packet aimed at external address if */
133  /* has active sessions */
134  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
135  &value0))
136  {
137  /* or is static mappings */
138  if (!snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0, 0))
139  return 0;
140  }
141  else
142  return 0;
143 
144  if (sm->forwarding_enabled)
145  return 1;
146 
147  return snat_not_translate_fast (sm, node, sw_if_index0, ip0, proto0,
148  rx_fib_index0);
149 }
150 
151 static inline int
153  u32 proto0, u16 src_port, u16 dst_port,
154  u32 thread_index, u32 sw_if_index)
155 {
156  snat_session_key_t key0;
157  clib_bihash_kv_8_8_t kv0, value0;
159 
160  /* src NAT check */
161  key0.addr = ip0->src_address;
162  key0.port = src_port;
163  key0.protocol = proto0;
165  kv0.key = key0.as_u64;
166 
167  if (!clib_bihash_search_8_8
168  (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
169  return 1;
170 
171  /* dst NAT check */
172  key0.addr = ip0->dst_address;
173  key0.port = dst_port;
174  key0.protocol = proto0;
175  kv0.key = key0.as_u64;
176  if (!clib_bihash_search_8_8
177  (&sm->per_thread_data[thread_index].in2out, &kv0, &value0))
178  {
179  /* hairpinning */
180  /* *INDENT-OFF* */
182  ({
183  if ((nat_interface_is_inside(i)) && (sw_if_index == i->sw_if_index))
184  return 0;
185  }));
186  /* *INDENT-ON* */
187  return 1;
188  }
189 
190  return 0;
191 }
192 
193 #ifndef CLIB_MARCH_VARIANT
194 int
196 {
197  snat_main_t *sm = &snat_main;
199  snat_session_t *s;
200  u64 sess_timeout_time;
202  ctx->thread_index);
204 
205  s = pool_elt_at_index (tsm->sessions, kv->value);
206  sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
207  if (ctx->now >= sess_timeout_time)
208  {
209  s_kv.key = s->out2in.as_u64;
210  if (clib_bihash_add_del_8_8 (&tsm->out2in, &s_kv, 0))
211  nat_elog_warn ("out2in key del failed");
212 
214  s->in2out.addr.as_u32,
215  s->out2in.addr.as_u32,
216  s->in2out.protocol,
217  s->in2out.port,
218  s->out2in.port,
219  s->in2out.fib_index);
220 
221  nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
222  &s->in2out.addr, s->in2out.port,
223  &s->out2in.addr, s->out2in.port,
224  s->in2out.protocol);
225 
226  nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
227  s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
228  ctx->thread_index);
229 
230  if (!snat_is_session_static (s))
232  &s->out2in);
233 
234  nat44_delete_session (sm, s, ctx->thread_index);
235  return 1;
236  }
237 
238  return 0;
239 }
240 #endif
241 
242 static u32
244  ip4_header_t * ip0,
245  u32 rx_fib_index0,
246  snat_session_key_t * key0,
247  snat_session_t ** sessionp,
248  vlib_node_runtime_t * node, u32 next0, u32 thread_index, f64 now)
249 {
250  snat_user_t *u;
251  snat_session_t *s = 0;
253  snat_session_key_t key1;
254  u8 is_sm = 0;
255  nat_outside_fib_t *outside_fib;
257  u8 identity_nat;
258  fib_prefix_t pfx = {
260  .fp_len = 32,
261  .fp_addr = {
262  .ip4.as_u32 = ip0->dst_address.as_u32,
263  },
264  };
266 
267  if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
268  {
269  b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
271  nat_elog_notice ("maximum sessions exceeded");
272  return SNAT_IN2OUT_NEXT_DROP;
273  }
274 
275  key1.protocol = key0->protocol;
276 
277  /* First try to match static mapping by local address and port */
279  (sm, *key0, &key1, 0, 0, 0, 0, 0, &identity_nat))
280  {
281  /* Try to create dynamic translation */
282  if (snat_alloc_outside_address_and_port (sm->addresses, rx_fib_index0,
283  thread_index, &key1,
284  sm->port_per_thread,
285  sm->per_thread_data
286  [thread_index].snat_thread_index))
287  {
288  b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
289  return SNAT_IN2OUT_NEXT_DROP;
290  }
291  }
292  else
293  {
294  if (PREDICT_FALSE (identity_nat))
295  {
296  *sessionp = s;
297  return next0;
298  }
299 
300  is_sm = 1;
301  }
302 
303  u = nat_user_get_or_create (sm, &ip0->src_address, rx_fib_index0,
304  thread_index);
305  if (!u)
306  {
307  nat_elog_warn ("create NAT user failed");
308  return SNAT_IN2OUT_NEXT_DROP;
309  }
310 
311  s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
312  if (!s)
313  {
314  nat44_delete_user_with_no_session (sm, u, thread_index);
315  nat_elog_warn ("create NAT session failed");
316  return SNAT_IN2OUT_NEXT_DROP;
317  }
318 
319  if (is_sm)
321  user_session_increment (sm, u, is_sm);
322  s->in2out = *key0;
323  s->out2in = key1;
324  s->out2in.protocol = key0->protocol;
325  s->out2in.fib_index = sm->outside_fib_index;
326  switch (vec_len (sm->outside_fibs))
327  {
328  case 0:
329  s->out2in.fib_index = sm->outside_fib_index;
330  break;
331  case 1:
332  s->out2in.fib_index = sm->outside_fibs[0].fib_index;
333  break;
334  default:
335  /* *INDENT-OFF* */
336  vec_foreach (outside_fib, sm->outside_fibs)
337  {
338  fei = fib_table_lookup (outside_fib->fib_index, &pfx);
339  if (FIB_NODE_INDEX_INVALID != fei)
340  {
341  if (fib_entry_get_resolving_interface (fei) != ~0)
342  {
343  s->out2in.fib_index = outside_fib->fib_index;
344  break;
345  }
346  }
347  }
348  /* *INDENT-ON* */
349  break;
350  }
351  s->ext_host_addr.as_u32 = ip0->dst_address.as_u32;
352  s->ext_host_port = vnet_buffer (b0)->ip.reass.l4_dst_port;
353  *sessionp = s;
354 
355  /* Add to translation hashes */
356  ctx0.now = now;
357  ctx0.thread_index = thread_index;
358  kv0.key = s->in2out.as_u64;
359  kv0.value = s - sm->per_thread_data[thread_index].sessions;
360  if (clib_bihash_add_or_overwrite_stale_8_8
361  (&sm->per_thread_data[thread_index].in2out, &kv0,
363  nat_elog_notice ("in2out key add failed");
364 
365  kv0.key = s->out2in.as_u64;
366  kv0.value = s - sm->per_thread_data[thread_index].sessions;
367 
368  if (clib_bihash_add_or_overwrite_stale_8_8
369  (&sm->per_thread_data[thread_index].out2in, &kv0,
371  nat_elog_notice ("out2in key add failed");
372 
373  /* log NAT event */
375  s->in2out.addr.as_u32,
376  s->out2in.addr.as_u32,
377  s->in2out.protocol,
378  s->in2out.port,
379  s->out2in.port, s->in2out.fib_index);
380 
381  nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index,
382  &s->in2out.addr, s->in2out.port, &s->out2in.addr,
383  s->out2in.port, s->in2out.protocol);
384 
385  nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
386  s->out2in.port, &s->ext_host_addr, s->ext_host_port,
387  &s->ext_host_nat_addr, s->ext_host_nat_port,
388  s->in2out.protocol, s->in2out.fib_index, s->flags,
389  thread_index, 0);
390 
391  return next0;
392 }
393 
394 #ifndef CLIB_MARCH_VARIANT
397  snat_session_key_t * p_key0)
398 {
399  icmp46_header_t *icmp0;
400  snat_session_key_t key0;
401  icmp_echo_header_t *echo0, *inner_echo0 = 0;
402  ip4_header_t *inner_ip0 = 0;
403  void *l4_header = 0;
404  icmp46_header_t *inner_icmp0;
405 
406  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
407  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
408 
410  (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
411  {
412  key0.protocol = NAT_PROTOCOL_ICMP;
413  key0.addr = ip0->src_address;
414  key0.port = vnet_buffer (b)->ip.reass.l4_src_port; // TODO fixme should this be dst port?
415  }
416  else
417  {
418  inner_ip0 = (ip4_header_t *) (echo0 + 1);
419  l4_header = ip4_next_header (inner_ip0);
420  key0.protocol = ip_proto_to_nat_proto (inner_ip0->protocol);
421  key0.addr = inner_ip0->dst_address;
422  switch (key0.protocol)
423  {
424  case NAT_PROTOCOL_ICMP:
425  inner_icmp0 = (icmp46_header_t *) l4_header;
426  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
427  key0.port = inner_echo0->identifier;
428  break;
429  case NAT_PROTOCOL_UDP:
430  case NAT_PROTOCOL_TCP:
431  key0.port = ((tcp_udp_header_t *) l4_header)->dst_port;
432  break;
433  default:
434  return SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL;
435  }
436  }
437  *p_key0 = key0;
438  return -1; /* success */
439 }
440 
441 /**
442  * Get address and port values to be used for ICMP packet translation
443  * and create session if needed
444  *
445  * @param[in,out] sm NAT main
446  * @param[in,out] node NAT node runtime
447  * @param[in] thread_index thread index
448  * @param[in,out] b0 buffer containing packet to be translated
449  * @param[in,out] ip0 ip header
450  * @param[out] p_proto protocol used for matching
451  * @param[out] p_value address and port after NAT translation
452  * @param[out] p_dont_translate if packet should not be translated
453  * @param d optional parameter
454  * @param e optional parameter
455  */
456 u32
458  u32 thread_index, vlib_buffer_t * b0,
459  ip4_header_t * ip0, u8 * p_proto,
460  snat_session_key_t * p_value,
461  u8 * p_dont_translate, void *d, void *e)
462 {
463  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
464  u32 sw_if_index0;
465  u32 rx_fib_index0;
466  snat_session_key_t key0;
467  snat_session_t *s0 = 0;
468  u8 dont_translate = 0;
469  clib_bihash_kv_8_8_t kv0, value0;
470  u32 next0 = ~0;
471  int err;
472  vlib_main_t *vm = vlib_get_main ();
473 
474  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
475  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
476 
477  err = icmp_get_key (b0, ip0, &key0);
478  if (err != -1)
479  {
480  b0->error = node->errors[err];
481  next0 = SNAT_IN2OUT_NEXT_DROP;
482  goto out;
483  }
484  key0.fib_index = rx_fib_index0;
485 
486  kv0.key = key0.as_u64;
487 
488  if (clib_bihash_search_8_8 (&tsm->in2out, &kv0, &value0))
489  {
490  if (vnet_buffer (b0)->sw_if_index[VLIB_TX] != ~0)
491  {
493  key0.protocol,
494  key0.port,
495  key0.port,
496  thread_index,
497  sw_if_index0)))
498  {
499  dont_translate = 1;
500  goto out;
501  }
502  }
503  else
504  {
505  if (PREDICT_FALSE (snat_not_translate (sm, node, sw_if_index0,
506  ip0, NAT_PROTOCOL_ICMP,
507  rx_fib_index0,
508  thread_index)))
509  {
510  dont_translate = 1;
511  goto out;
512  }
513  }
514 
515  if (PREDICT_FALSE
517  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags)))
518  {
519  b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
520  next0 = SNAT_IN2OUT_NEXT_DROP;
521  goto out;
522  }
523 
524  next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, &s0, node, next0,
525  thread_index, vlib_time_now (vm));
526 
527  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
528  goto out;
529 
530  if (!s0)
531  {
532  dont_translate = 1;
533  goto out;
534  }
535  }
536  else
537  {
538  if (PREDICT_FALSE
539  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
540  ICMP4_echo_request
541  && vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
542  ICMP4_echo_reply
544  reass.icmp_type_or_tcp_flags)))
545  {
546  b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
547  next0 = SNAT_IN2OUT_NEXT_DROP;
548  goto out;
549  }
550 
551  s0 = pool_elt_at_index (tsm->sessions, value0.value);
552  }
553 
554 out:
555  *p_proto = key0.protocol;
556  if (s0)
557  *p_value = s0->out2in;
558  *p_dont_translate = dont_translate;
559  if (d)
560  *(snat_session_t **) d = s0;
561  return next0;
562 }
563 #endif
564 
565 #ifndef CLIB_MARCH_VARIANT
566 /**
567  * Get address and port values to be used for ICMP packet translation
568  *
569  * @param[in] sm NAT main
570  * @param[in,out] node NAT node runtime
571  * @param[in] thread_index thread index
572  * @param[in,out] b0 buffer containing packet to be translated
573  * @param[in,out] ip0 ip header
574  * @param[out] p_proto protocol used for matching
575  * @param[out] p_value address and port after NAT translation
576  * @param[out] p_dont_translate if packet should not be translated
577  * @param d optional parameter
578  * @param e optional parameter
579  */
580 u32
582  u32 thread_index, vlib_buffer_t * b0,
583  ip4_header_t * ip0, u8 * p_proto,
584  snat_session_key_t * p_value,
585  u8 * p_dont_translate, void *d, void *e)
586 {
587  u32 sw_if_index0;
588  u32 rx_fib_index0;
589  snat_session_key_t key0;
590  snat_session_key_t sm0;
591  u8 dont_translate = 0;
592  u8 is_addr_only;
593  u32 next0 = ~0;
594  int err;
595 
596  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
597  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
598 
599  err = icmp_get_key (b0, ip0, &key0);
600  if (err != -1)
601  {
602  b0->error = node->errors[err];
603  next0 = SNAT_IN2OUT_NEXT_DROP;
604  goto out2;
605  }
606  key0.fib_index = rx_fib_index0;
607 
609  (sm, key0, &sm0, 0, &is_addr_only, 0, 0, 0, 0))
610  {
611  if (PREDICT_FALSE (snat_not_translate_fast (sm, node, sw_if_index0, ip0,
612  IP_PROTOCOL_ICMP,
613  rx_fib_index0)))
614  {
615  dont_translate = 1;
616  goto out;
617  }
618 
620  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
621  {
622  next0 = SNAT_IN2OUT_NEXT_DROP;
623  goto out;
624  }
625 
626  b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
627  next0 = SNAT_IN2OUT_NEXT_DROP;
628  goto out;
629  }
630 
631  if (PREDICT_FALSE
632  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_request
633  && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
634  ICMP4_echo_reply || !is_addr_only)
636  reass.icmp_type_or_tcp_flags)))
637  {
638  b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
639  next0 = SNAT_IN2OUT_NEXT_DROP;
640  goto out;
641  }
642 
643 out:
644  *p_value = sm0;
645 out2:
646  *p_proto = key0.protocol;
647  *p_dont_translate = dont_translate;
648  return next0;
649 }
650 #endif
651 
652 #ifndef CLIB_MARCH_VARIANT
653 u32
655  vlib_buffer_t * b0,
656  ip4_header_t * ip0,
657  icmp46_header_t * icmp0,
658  u32 sw_if_index0,
659  u32 rx_fib_index0,
661  u32 next0, u32 thread_index, void *d, void *e)
662 {
663  vlib_main_t *vm = vlib_get_main ();
664  snat_session_key_t sm0;
665  u8 protocol;
666  icmp_echo_header_t *echo0, *inner_echo0 = 0;
667  ip4_header_t *inner_ip0;
668  void *l4_header = 0;
669  icmp46_header_t *inner_icmp0;
670  u8 dont_translate;
671  u32 new_addr0, old_addr0;
672  u16 old_id0, new_id0;
673  u16 old_checksum0, new_checksum0;
674  ip_csum_t sum0;
675  u16 checksum0;
676  u32 next0_tmp;
677 
678  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
679 
680  next0_tmp = sm->icmp_match_in2out_cb (sm, node, thread_index, b0, ip0,
681  &protocol, &sm0, &dont_translate, d,
682  e);
683  if (next0_tmp != ~0)
684  next0 = next0_tmp;
685  if (next0 == SNAT_IN2OUT_NEXT_DROP || dont_translate)
686  goto out;
687 
688  if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
689  {
690  sum0 =
692  (u8 *) icmp0 -
693  (u8 *) vlib_buffer_get_current (b0),
694  ntohs (ip0->length) -
695  ip4_header_bytes (ip0), 0);
696  checksum0 = ~ip_csum_fold (sum0);
697  if (PREDICT_FALSE (checksum0 != 0 && checksum0 != 0xffff))
698  {
699  next0 = SNAT_IN2OUT_NEXT_DROP;
700  goto out;
701  }
702  }
703 
704  old_addr0 = ip0->src_address.as_u32;
705  new_addr0 = ip0->src_address.as_u32 = sm0.addr.as_u32;
706 
707  sum0 = ip0->checksum;
708  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
709  src_address /* changed member */ );
710  ip0->checksum = ip_csum_fold (sum0);
711 
712  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
713  {
714  if (icmp0->checksum == 0)
715  icmp0->checksum = 0xffff;
716 
717  if (!icmp_type_is_error_message (icmp0->type))
718  {
719  new_id0 = sm0.port;
720  if (PREDICT_FALSE (new_id0 != echo0->identifier))
721  {
722  old_id0 = echo0->identifier;
723  new_id0 = sm0.port;
724  echo0->identifier = new_id0;
725 
726  sum0 = icmp0->checksum;
727  sum0 =
728  ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
729  identifier);
730  icmp0->checksum = ip_csum_fold (sum0);
731  }
732  }
733  else
734  {
735  inner_ip0 = (ip4_header_t *) (echo0 + 1);
736  l4_header = ip4_next_header (inner_ip0);
737 
738  if (!ip4_header_checksum_is_valid (inner_ip0))
739  {
740  next0 = SNAT_IN2OUT_NEXT_DROP;
741  goto out;
742  }
743 
744  /* update inner destination IP address */
745  old_addr0 = inner_ip0->dst_address.as_u32;
746  inner_ip0->dst_address = sm0.addr;
747  new_addr0 = inner_ip0->dst_address.as_u32;
748  sum0 = icmp0->checksum;
749  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
750  dst_address /* changed member */ );
751  icmp0->checksum = ip_csum_fold (sum0);
752 
753  /* update inner IP header checksum */
754  old_checksum0 = inner_ip0->checksum;
755  sum0 = inner_ip0->checksum;
756  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
757  dst_address /* changed member */ );
758  inner_ip0->checksum = ip_csum_fold (sum0);
759  new_checksum0 = inner_ip0->checksum;
760  sum0 = icmp0->checksum;
761  sum0 =
762  ip_csum_update (sum0, old_checksum0, new_checksum0, ip4_header_t,
763  checksum);
764  icmp0->checksum = ip_csum_fold (sum0);
765 
766  switch (protocol)
767  {
768  case NAT_PROTOCOL_ICMP:
769  inner_icmp0 = (icmp46_header_t *) l4_header;
770  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
771 
772  old_id0 = inner_echo0->identifier;
773  new_id0 = sm0.port;
774  inner_echo0->identifier = new_id0;
775 
776  sum0 = icmp0->checksum;
777  sum0 =
778  ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
779  identifier);
780  icmp0->checksum = ip_csum_fold (sum0);
781  break;
782  case NAT_PROTOCOL_UDP:
783  case NAT_PROTOCOL_TCP:
784  old_id0 = ((tcp_udp_header_t *) l4_header)->dst_port;
785  new_id0 = sm0.port;
786  ((tcp_udp_header_t *) l4_header)->dst_port = new_id0;
787 
788  sum0 = icmp0->checksum;
789  sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
790  dst_port);
791  icmp0->checksum = ip_csum_fold (sum0);
792  break;
793  default:
794  ASSERT (0);
795  }
796  }
797  }
798 
799  if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0)
800  {
801  if (sm->deterministic ||
802  0 != snat_icmp_hairpinning (sm, b0, ip0, icmp0,
803  sm->endpoint_dependent))
804  vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
805  }
806 
807 out:
808  return next0;
809 }
810 #endif
811 
812 static inline u32
814  vlib_buffer_t * b0,
815  ip4_header_t * ip0,
816  icmp46_header_t * icmp0,
817  u32 sw_if_index0,
818  u32 rx_fib_index0,
820  u32 next0,
821  f64 now, u32 thread_index, snat_session_t ** p_s0)
822 {
823  vlib_main_t *vm = vlib_get_main ();
824 
825  next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
826  next0, thread_index, p_s0, 0);
827  snat_session_t *s0 = *p_s0;
828  if (PREDICT_TRUE (next0 != SNAT_IN2OUT_NEXT_DROP && s0))
829  {
830  /* Accounting */
833  (vm, b0), thread_index);
834  /* Per-user LRU list maintenance */
835  nat44_session_update_lru (sm, s0, thread_index);
836  }
837  return next0;
838 }
839 
840 static int
842  vlib_buffer_t * b,
843  ip4_header_t * ip, u32 rx_fib_index)
844 {
847  snat_session_key_t m_key;
848  u32 old_addr, new_addr;
849  ip_csum_t sum;
850 
851  m_key.addr = ip->src_address;
852  m_key.port = 0;
853  m_key.protocol = 0;
854  m_key.fib_index = rx_fib_index;
855  kv.key = m_key.as_u64;
856  if (clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
857  return 1;
858 
859  m = pool_elt_at_index (sm->static_mappings, value.value);
860 
861  old_addr = ip->src_address.as_u32;
862  new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
863  sum = ip->checksum;
864  sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
865  ip->checksum = ip_csum_fold (sum);
866 
867 
868  /* Hairpinning */
869  if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
870  {
871  vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
873  }
874 
875  return 0;
876 }
877 
878 static inline uword
881  vlib_frame_t * frame, int is_slow_path,
882  int is_output_feature)
883 {
884  u32 n_left_from, *from, *to_next;
885  snat_in2out_next_t next_index;
886  u32 pkts_processed = 0;
887  snat_main_t *sm = &snat_main;
888  f64 now = vlib_time_now (vm);
889  u32 stats_node_index;
890  u32 thread_index = vm->thread_index;
891  u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
892  0, fragments = 0;
893 
894  stats_node_index = is_slow_path ? sm->in2out_slowpath_node_index :
895  sm->in2out_node_index;
896 
897  from = vlib_frame_vector_args (frame);
898  n_left_from = frame->n_vectors;
899  next_index = node->cached_next_index;
900 
901  while (n_left_from > 0)
902  {
903  u32 n_left_to_next;
904 
905  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
906 
907  while (n_left_from >= 4 && n_left_to_next >= 2)
908  {
909  u32 bi0, bi1;
910  vlib_buffer_t *b0, *b1;
911  u32 next0, next1;
912  u32 sw_if_index0, sw_if_index1;
913  ip4_header_t *ip0, *ip1;
914  ip_csum_t sum0, sum1;
915  u32 new_addr0, old_addr0, new_addr1, old_addr1;
916  u16 old_port0, new_port0, old_port1, new_port1;
917  udp_header_t *udp0, *udp1;
918  tcp_header_t *tcp0, *tcp1;
919  icmp46_header_t *icmp0, *icmp1;
920  snat_session_key_t key0, key1;
921  u32 rx_fib_index0, rx_fib_index1;
922  u32 proto0, proto1;
923  snat_session_t *s0 = 0, *s1 = 0;
924  clib_bihash_kv_8_8_t kv0, value0, kv1, value1;
925  u32 iph_offset0 = 0, iph_offset1 = 0;
926 
927  /* Prefetch next iteration. */
928  {
929  vlib_buffer_t *p2, *p3;
930 
931  p2 = vlib_get_buffer (vm, from[2]);
932  p3 = vlib_get_buffer (vm, from[3]);
933 
934  vlib_prefetch_buffer_header (p2, LOAD);
935  vlib_prefetch_buffer_header (p3, LOAD);
936 
939  }
940 
941  /* speculatively enqueue b0 and b1 to the current next frame */
942  to_next[0] = bi0 = from[0];
943  to_next[1] = bi1 = from[1];
944  from += 2;
945  to_next += 2;
946  n_left_from -= 2;
947  n_left_to_next -= 2;
948 
949  b0 = vlib_get_buffer (vm, bi0);
950  b1 = vlib_get_buffer (vm, bi1);
951 
952  if (is_output_feature)
953  iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
954 
955  ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
956  iph_offset0);
957 
958  udp0 = ip4_next_header (ip0);
959  tcp0 = (tcp_header_t *) udp0;
960  icmp0 = (icmp46_header_t *) udp0;
961 
962  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
963  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
964  sw_if_index0);
965 
966  next0 = next1 = SNAT_IN2OUT_NEXT_LOOKUP;
967 
968  if (PREDICT_FALSE (ip0->ttl == 1))
969  {
970  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
971  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
972  ICMP4_time_exceeded_ttl_exceeded_in_transit,
973  0);
975  goto trace00;
976  }
977 
978  proto0 = ip_proto_to_nat_proto (ip0->protocol);
979 
980  /* Next configured feature, probably ip4-lookup */
981  if (is_slow_path)
982  {
983  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
984  {
986  (sm, b0, ip0, rx_fib_index0))
987  {
988  next0 = SNAT_IN2OUT_NEXT_DROP;
989  b0->error =
990  node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
991  }
992  other_packets++;
993  goto trace00;
994  }
995 
996  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
997  {
998  next0 = icmp_in2out_slow_path
999  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
1000  node, next0, now, thread_index, &s0);
1001  icmp_packets++;
1002  goto trace00;
1003  }
1004  }
1005  else
1006  {
1007  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1008  {
1010  goto trace00;
1011  }
1012 
1013  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1014  {
1016  goto trace00;
1017  }
1018  }
1019 
1020  key0.addr = ip0->src_address;
1021  key0.port = vnet_buffer (b0)->ip.reass.l4_src_port;
1022  key0.protocol = proto0;
1023  key0.fib_index = rx_fib_index0;
1024 
1025  kv0.key = key0.as_u64;
1026 
1027  if (PREDICT_FALSE
1028  (clib_bihash_search_8_8
1029  (&sm->per_thread_data[thread_index].in2out, &kv0,
1030  &value0) != 0))
1031  {
1032  if (is_slow_path)
1033  {
1034  if (is_output_feature)
1035  {
1036  if (PREDICT_FALSE
1038  (sm, ip0, proto0,
1039  vnet_buffer (b0)->ip.reass.l4_src_port,
1040  vnet_buffer (b0)->ip.reass.l4_dst_port,
1041  thread_index, sw_if_index0)))
1042  goto trace00;
1043 
1044  /*
1045  * Send DHCP packets to the ipv4 stack, or we won't
1046  * be able to use dhcp client on the outside interface
1047  */
1048  if (PREDICT_FALSE
1049  (proto0 == NAT_PROTOCOL_UDP
1050  && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1051  clib_host_to_net_u16
1052  (UDP_DST_PORT_dhcp_to_server))
1053  && ip0->dst_address.as_u32 == 0xffffffff))
1054  goto trace00;
1055  }
1056  else
1057  {
1058  if (PREDICT_FALSE
1060  (sm, node, sw_if_index0, ip0, proto0,
1061  rx_fib_index0, thread_index)))
1062  goto trace00;
1063  }
1064 
1065  next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
1066  &s0, node, next0, thread_index, now);
1067  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
1068  goto trace00;
1069 
1070  if (PREDICT_FALSE (!s0))
1071  goto trace00;
1072  }
1073  else
1074  {
1076  goto trace00;
1077  }
1078  }
1079  else
1080  s0 =
1081  pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1082  value0.value);
1083 
1084  b0->flags |= VNET_BUFFER_F_IS_NATED;
1085 
1086  old_addr0 = ip0->src_address.as_u32;
1087  ip0->src_address = s0->out2in.addr;
1088  new_addr0 = ip0->src_address.as_u32;
1089  if (!is_output_feature)
1090  vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1091 
1092  sum0 = ip0->checksum;
1093  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1094  ip4_header_t,
1095  src_address /* changed member */ );
1096  ip0->checksum = ip_csum_fold (sum0);
1097 
1098 
1099  if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1100  {
1101  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1102  {
1103  old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1104  new_port0 = udp0->src_port = s0->out2in.port;
1105  sum0 = tcp0->checksum;
1106  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1107  ip4_header_t,
1108  dst_address /* changed member */ );
1109  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1110  ip4_header_t /* cheat */ ,
1111  length /* changed member */ );
1112  mss_clamping (sm, tcp0, &sum0);
1113  tcp0->checksum = ip_csum_fold (sum0);
1114  }
1115  tcp_packets++;
1116  }
1117  else
1118  {
1119  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1120  {
1121  udp0->src_port = s0->out2in.port;
1122  if (PREDICT_FALSE (udp0->checksum))
1123  {
1124  old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1125  new_port0 = udp0->src_port;
1126  sum0 = udp0->checksum;
1127  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
1128  );
1129  sum0 =
1130  ip_csum_update (sum0, old_port0, new_port0,
1131  ip4_header_t /* cheat */ ,
1132  length /* changed member */ );
1133  udp0->checksum = ip_csum_fold (sum0);
1134  }
1135  }
1136  udp_packets++;
1137  }
1138 
1139  /* Accounting */
1141  vlib_buffer_length_in_chain (vm, b0),
1142  thread_index);
1143  /* Per-user LRU list maintenance */
1144  nat44_session_update_lru (sm, s0, thread_index);
1145  trace00:
1146 
1148  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1149  {
1150  snat_in2out_trace_t *t =
1151  vlib_add_trace (vm, node, b0, sizeof (*t));
1152  t->is_slow_path = is_slow_path;
1153  t->sw_if_index = sw_if_index0;
1154  t->next_index = next0;
1155  t->session_index = ~0;
1156  if (s0)
1157  t->session_index =
1158  s0 - sm->per_thread_data[thread_index].sessions;
1159  }
1160 
1161  pkts_processed += next0 == SNAT_IN2OUT_NEXT_LOOKUP;
1162 
1163  if (is_output_feature)
1164  iph_offset1 = vnet_buffer (b1)->ip.reass.save_rewrite_length;
1165 
1166  ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) +
1167  iph_offset1);
1168 
1169  udp1 = ip4_next_header (ip1);
1170  tcp1 = (tcp_header_t *) udp1;
1171  icmp1 = (icmp46_header_t *) udp1;
1172 
1173  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1174  rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1175  sw_if_index1);
1176 
1177  if (PREDICT_FALSE (ip1->ttl == 1))
1178  {
1179  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1180  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1181  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1182  0);
1184  goto trace01;
1185  }
1186 
1187  proto1 = ip_proto_to_nat_proto (ip1->protocol);
1188 
1189  /* Next configured feature, probably ip4-lookup */
1190  if (is_slow_path)
1191  {
1192  if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
1193  {
1195  (sm, b1, ip1, rx_fib_index1))
1196  {
1197  next1 = SNAT_IN2OUT_NEXT_DROP;
1198  b1->error =
1199  node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
1200  }
1201  other_packets++;
1202  goto trace01;
1203  }
1204 
1205  if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
1206  {
1207  next1 = icmp_in2out_slow_path
1208  (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1209  next1, now, thread_index, &s1);
1210  icmp_packets++;
1211  goto trace01;
1212  }
1213  }
1214  else
1215  {
1216  if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
1217  {
1219  goto trace01;
1220  }
1221 
1222  if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
1223  {
1225  goto trace01;
1226  }
1227  }
1228 
1229  key1.addr = ip1->src_address;
1230  key1.port = vnet_buffer (b1)->ip.reass.l4_src_port;
1231  key1.protocol = proto1;
1232  key1.fib_index = rx_fib_index1;
1233 
1234  kv1.key = key1.as_u64;
1235 
1236  if (PREDICT_FALSE
1237  (clib_bihash_search_8_8
1238  (&sm->per_thread_data[thread_index].in2out, &kv1,
1239  &value1) != 0))
1240  {
1241  if (is_slow_path)
1242  {
1243  if (is_output_feature)
1244  {
1245  if (PREDICT_FALSE
1247  (sm, ip1, proto1,
1248  vnet_buffer (b1)->ip.reass.l4_src_port,
1249  vnet_buffer (b1)->ip.reass.l4_dst_port,
1250  thread_index, sw_if_index1)))
1251  goto trace01;
1252 
1253  /*
1254  * Send DHCP packets to the ipv4 stack, or we won't
1255  * be able to use dhcp client on the outside interface
1256  */
1257  if (PREDICT_FALSE
1258  (proto1 == NAT_PROTOCOL_UDP
1259  && (vnet_buffer (b1)->ip.reass.l4_dst_port ==
1260  clib_host_to_net_u16
1261  (UDP_DST_PORT_dhcp_to_server))
1262  && ip1->dst_address.as_u32 == 0xffffffff))
1263  goto trace01;
1264  }
1265  else
1266  {
1267  if (PREDICT_FALSE
1269  (sm, node, sw_if_index1, ip1, proto1,
1270  rx_fib_index1, thread_index)))
1271  goto trace01;
1272  }
1273 
1274  next1 = slow_path (sm, b1, ip1, rx_fib_index1, &key1,
1275  &s1, node, next1, thread_index, now);
1276  if (PREDICT_FALSE (next1 == SNAT_IN2OUT_NEXT_DROP))
1277  goto trace01;
1278 
1279  if (PREDICT_FALSE (!s1))
1280  goto trace01;
1281  }
1282  else
1283  {
1285  goto trace01;
1286  }
1287  }
1288  else
1289  s1 =
1290  pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1291  value1.value);
1292 
1293  b1->flags |= VNET_BUFFER_F_IS_NATED;
1294 
1295  old_addr1 = ip1->src_address.as_u32;
1296  ip1->src_address = s1->out2in.addr;
1297  new_addr1 = ip1->src_address.as_u32;
1298  if (!is_output_feature)
1299  vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index;
1300 
1301  sum1 = ip1->checksum;
1302  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1303  ip4_header_t,
1304  src_address /* changed member */ );
1305  ip1->checksum = ip_csum_fold (sum1);
1306 
1307  if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
1308  {
1309  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1310  {
1311  old_port1 = vnet_buffer (b1)->ip.reass.l4_src_port;
1312  new_port1 = udp1->src_port = s1->out2in.port;
1313  sum1 = tcp1->checksum;
1314  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1315  ip4_header_t,
1316  dst_address /* changed member */ );
1317  sum1 = ip_csum_update (sum1, old_port1, new_port1,
1318  ip4_header_t /* cheat */ ,
1319  length /* changed member */ );
1320  mss_clamping (sm, tcp1, &sum1);
1321  tcp1->checksum = ip_csum_fold (sum1);
1322  }
1323  tcp_packets++;
1324  }
1325  else
1326  {
1327  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1328  {
1329  udp1->src_port = s1->out2in.port;
1330  if (PREDICT_FALSE (udp1->checksum))
1331  {
1332  old_port1 = vnet_buffer (b1)->ip.reass.l4_src_port;
1333  new_port1 = udp1->src_port;
1334  sum1 = udp1->checksum;
1335  sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t, dst_address /* changed member */
1336  );
1337  sum1 =
1338  ip_csum_update (sum1, old_port1, new_port1,
1339  ip4_header_t /* cheat */ ,
1340  length /* changed member */ );
1341  udp1->checksum = ip_csum_fold (sum1);
1342  }
1343  }
1344  udp_packets++;
1345  }
1346 
1347  /* Accounting */
1349  vlib_buffer_length_in_chain (vm, b1),
1350  thread_index);
1351  /* Per-user LRU list maintenance */
1352  nat44_session_update_lru (sm, s1, thread_index);
1353  trace01:
1354 
1356  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1357  {
1358  snat_in2out_trace_t *t =
1359  vlib_add_trace (vm, node, b1, sizeof (*t));
1360  t->sw_if_index = sw_if_index1;
1361  t->next_index = next1;
1362  t->session_index = ~0;
1363  if (s1)
1364  t->session_index =
1365  s1 - sm->per_thread_data[thread_index].sessions;
1366  }
1367 
1368  pkts_processed += next1 == SNAT_IN2OUT_NEXT_LOOKUP;
1369 
1370  /* verify speculative enqueues, maybe switch current next frame */
1371  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1372  to_next, n_left_to_next,
1373  bi0, bi1, next0, next1);
1374  }
1375 
1376  while (n_left_from > 0 && n_left_to_next > 0)
1377  {
1378  u32 bi0;
1379  vlib_buffer_t *b0;
1380  u32 next0;
1381  u32 sw_if_index0;
1382  ip4_header_t *ip0;
1383  ip_csum_t sum0;
1384  u32 new_addr0, old_addr0;
1385  u16 old_port0, new_port0;
1386  udp_header_t *udp0;
1387  tcp_header_t *tcp0;
1388  icmp46_header_t *icmp0;
1389  snat_session_key_t key0;
1390  u32 rx_fib_index0;
1391  u32 proto0;
1392  snat_session_t *s0 = 0;
1393  clib_bihash_kv_8_8_t kv0, value0;
1394  u32 iph_offset0 = 0;
1395 
1396  /* speculatively enqueue b0 to the current next frame */
1397  bi0 = from[0];
1398  to_next[0] = bi0;
1399  from += 1;
1400  to_next += 1;
1401  n_left_from -= 1;
1402  n_left_to_next -= 1;
1403 
1404  b0 = vlib_get_buffer (vm, bi0);
1405  next0 = SNAT_IN2OUT_NEXT_LOOKUP;
1406 
1407  if (is_output_feature)
1408  iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
1409 
1410  ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1411  iph_offset0);
1412 
1413  udp0 = ip4_next_header (ip0);
1414  tcp0 = (tcp_header_t *) udp0;
1415  icmp0 = (icmp46_header_t *) udp0;
1416 
1417  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1418  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1419  sw_if_index0);
1420 
1421  if (PREDICT_FALSE (ip0->ttl == 1))
1422  {
1423  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1424  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1425  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1426  0);
1428  goto trace0;
1429  }
1430 
1431  proto0 = ip_proto_to_nat_proto (ip0->protocol);
1432 
1433  /* Next configured feature, probably ip4-lookup */
1434  if (is_slow_path)
1435  {
1436  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1437  {
1439  (sm, b0, ip0, rx_fib_index0))
1440  {
1441  next0 = SNAT_IN2OUT_NEXT_DROP;
1442  b0->error =
1443  node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
1444  }
1445  other_packets++;
1446  goto trace0;
1447  }
1448 
1449  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1450  {
1451  next0 = icmp_in2out_slow_path
1452  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1453  next0, now, thread_index, &s0);
1454  icmp_packets++;
1455  goto trace0;
1456  }
1457  }
1458  else
1459  {
1460  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1461  {
1463  goto trace0;
1464  }
1465 
1466  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1467  {
1469  goto trace0;
1470  }
1471  }
1472 
1473  key0.addr = ip0->src_address;
1474  key0.port = vnet_buffer (b0)->ip.reass.l4_src_port;
1475  key0.protocol = proto0;
1476  key0.fib_index = rx_fib_index0;
1477 
1478  kv0.key = key0.as_u64;
1479 
1480  if (clib_bihash_search_8_8
1481  (&sm->per_thread_data[thread_index].in2out, &kv0, &value0))
1482  {
1483  if (is_slow_path)
1484  {
1485  if (is_output_feature)
1486  {
1487  if (PREDICT_FALSE
1489  (sm, ip0, proto0,
1490  vnet_buffer (b0)->ip.reass.l4_src_port,
1491  vnet_buffer (b0)->ip.reass.l4_dst_port,
1492  thread_index, sw_if_index0)))
1493  goto trace0;
1494 
1495  /*
1496  * Send DHCP packets to the ipv4 stack, or we won't
1497  * be able to use dhcp client on the outside interface
1498  */
1499  if (PREDICT_FALSE
1500  (proto0 == NAT_PROTOCOL_UDP
1501  && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1502  clib_host_to_net_u16
1503  (UDP_DST_PORT_dhcp_to_server))
1504  && ip0->dst_address.as_u32 == 0xffffffff))
1505  goto trace0;
1506  }
1507  else
1508  {
1509  if (PREDICT_FALSE
1511  (sm, node, sw_if_index0, ip0, proto0,
1512  rx_fib_index0, thread_index)))
1513  goto trace0;
1514  }
1515 
1516  next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
1517  &s0, node, next0, thread_index, now);
1518 
1519  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
1520  goto trace0;
1521 
1522  if (PREDICT_FALSE (!s0))
1523  goto trace0;
1524  }
1525  else
1526  {
1528  goto trace0;
1529  }
1530  }
1531  else
1532  s0 =
1533  pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1534  value0.value);
1535 
1536  b0->flags |= VNET_BUFFER_F_IS_NATED;
1537 
1538  old_addr0 = ip0->src_address.as_u32;
1539  ip0->src_address = s0->out2in.addr;
1540  new_addr0 = ip0->src_address.as_u32;
1541  if (!is_output_feature)
1542  vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1543 
1544  sum0 = ip0->checksum;
1545  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1546  ip4_header_t,
1547  src_address /* changed member */ );
1548  ip0->checksum = ip_csum_fold (sum0);
1549 
1550  if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1551  {
1552  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1553  {
1554  old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1555  new_port0 = udp0->src_port = s0->out2in.port;
1556  sum0 = tcp0->checksum;
1557  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1558  ip4_header_t,
1559  dst_address /* changed member */ );
1560  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1561  ip4_header_t /* cheat */ ,
1562  length /* changed member */ );
1563  mss_clamping (sm, tcp0, &sum0);
1564  tcp0->checksum = ip_csum_fold (sum0);
1565  }
1566  tcp_packets++;
1567  }
1568  else
1569  {
1570  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1571  {
1572  udp0->src_port = s0->out2in.port;
1573  if (PREDICT_FALSE (udp0->checksum))
1574  {
1575  old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1576  new_port0 = udp0->src_port;
1577  sum0 = udp0->checksum;
1578  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
1579  );
1580  sum0 =
1581  ip_csum_update (sum0, old_port0, new_port0,
1582  ip4_header_t /* cheat */ ,
1583  length /* changed member */ );
1584  udp0->checksum = ip_csum_fold (sum0);
1585  }
1586  }
1587  udp_packets++;
1588  }
1589 
1590  /* Accounting */
1592  vlib_buffer_length_in_chain (vm, b0),
1593  thread_index);
1594  /* Per-user LRU list maintenance */
1595  nat44_session_update_lru (sm, s0, thread_index);
1596 
1597  trace0:
1599  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1600  {
1601  snat_in2out_trace_t *t =
1602  vlib_add_trace (vm, node, b0, sizeof (*t));
1603  t->is_slow_path = is_slow_path;
1604  t->sw_if_index = sw_if_index0;
1605  t->next_index = next0;
1606  t->session_index = ~0;
1607  if (s0)
1608  t->session_index =
1609  s0 - sm->per_thread_data[thread_index].sessions;
1610  }
1611 
1612  pkts_processed += next0 == SNAT_IN2OUT_NEXT_LOOKUP;
1613 
1614  /* verify speculative enqueue, maybe switch current next frame */
1615  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1616  to_next, n_left_to_next,
1617  bi0, next0);
1618  }
1619 
1620  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1621  }
1622 
1623  vlib_node_increment_counter (vm, stats_node_index,
1624  SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
1625  pkts_processed);
1626  vlib_node_increment_counter (vm, stats_node_index,
1627  SNAT_IN2OUT_ERROR_TCP_PACKETS, tcp_packets);
1628  vlib_node_increment_counter (vm, stats_node_index,
1629  SNAT_IN2OUT_ERROR_UDP_PACKETS, udp_packets);
1630  vlib_node_increment_counter (vm, stats_node_index,
1631  SNAT_IN2OUT_ERROR_ICMP_PACKETS, icmp_packets);
1632  vlib_node_increment_counter (vm, stats_node_index,
1633  SNAT_IN2OUT_ERROR_OTHER_PACKETS,
1634  other_packets);
1635  vlib_node_increment_counter (vm, stats_node_index,
1636  SNAT_IN2OUT_ERROR_FRAGMENTS, fragments);
1637 
1638  return frame->n_vectors;
1639 }
1640 
1643  vlib_frame_t * frame)
1644 {
1645  return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */ ,
1646  0);
1647 }
1648 
1649 /* *INDENT-OFF* */
1651  .name = "nat44-in2out",
1652  .vector_size = sizeof (u32),
1653  .format_trace = format_snat_in2out_trace,
1655 
1656  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1657  .error_strings = snat_in2out_error_strings,
1658 
1659  .runtime_data_bytes = sizeof (snat_runtime_t),
1660 
1661  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1662 
1663  /* edit / add dispositions here */
1664  .next_nodes = {
1665  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1666  [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1667  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
1668  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1669  },
1670 };
1671 /* *INDENT-ON* */
1672 
1675  vlib_frame_t * frame)
1676 {
1677  return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */ ,
1678  1);
1679 }
1680 
1681 /* *INDENT-OFF* */
1683  .name = "nat44-in2out-output",
1684  .vector_size = sizeof (u32),
1685  .format_trace = format_snat_in2out_trace,
1687 
1688  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1689  .error_strings = snat_in2out_error_strings,
1690 
1691  .runtime_data_bytes = sizeof (snat_runtime_t),
1692 
1693  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1694 
1695  /* edit / add dispositions here */
1696  .next_nodes = {
1697  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1698  [SNAT_IN2OUT_NEXT_LOOKUP] = "interface-output",
1699  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-output-slowpath",
1700  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1701  },
1702 };
1703 /* *INDENT-ON* */
1704 
1707  vlib_frame_t * frame)
1708 {
1709  return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */ ,
1710  0);
1711 }
1712 
1713 /* *INDENT-OFF* */
1715  .name = "nat44-in2out-slowpath",
1716  .vector_size = sizeof (u32),
1717  .format_trace = format_snat_in2out_trace,
1719 
1720  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1721  .error_strings = snat_in2out_error_strings,
1722 
1723  .runtime_data_bytes = sizeof (snat_runtime_t),
1724 
1725  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1726 
1727  /* edit / add dispositions here */
1728  .next_nodes = {
1729  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1730  [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1731  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
1732  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1733  },
1734 };
1735 /* *INDENT-ON* */
1736 
1739  vlib_frame_t * frame)
1740 {
1741  return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */ ,
1742  1);
1743 }
1744 
1745 /* *INDENT-OFF* */
1747  .name = "nat44-in2out-output-slowpath",
1748  .vector_size = sizeof (u32),
1749  .format_trace = format_snat_in2out_trace,
1751 
1752  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1753  .error_strings = snat_in2out_error_strings,
1754 
1755  .runtime_data_bytes = sizeof (snat_runtime_t),
1756 
1757  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1758 
1759  /* edit / add dispositions here */
1760  .next_nodes = {
1761  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1762  [SNAT_IN2OUT_NEXT_LOOKUP] = "interface-output",
1763  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-output-slowpath",
1764  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1765  },
1766 };
1767 /* *INDENT-ON* */
1768 
1771  vlib_frame_t * frame)
1772 {
1773  u32 n_left_from, *from, *to_next;
1774  snat_in2out_next_t next_index;
1775  u32 pkts_processed = 0;
1776  snat_main_t *sm = &snat_main;
1777  u32 stats_node_index;
1778 
1779  stats_node_index = sm->in2out_fast_node_index;
1780 
1781  from = vlib_frame_vector_args (frame);
1782  n_left_from = frame->n_vectors;
1783  next_index = node->cached_next_index;
1784 
1785  while (n_left_from > 0)
1786  {
1787  u32 n_left_to_next;
1788 
1789  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1790 
1791  while (n_left_from > 0 && n_left_to_next > 0)
1792  {
1793  u32 bi0;
1794  vlib_buffer_t *b0;
1795  u32 next0;
1796  u32 sw_if_index0;
1797  ip4_header_t *ip0;
1798  ip_csum_t sum0;
1799  u32 new_addr0, old_addr0;
1800  u16 old_port0, new_port0;
1801  udp_header_t *udp0;
1802  tcp_header_t *tcp0;
1803  icmp46_header_t *icmp0;
1804  snat_session_key_t key0, sm0;
1805  u32 proto0;
1806  u32 rx_fib_index0;
1807 
1808  /* speculatively enqueue b0 to the current next frame */
1809  bi0 = from[0];
1810  to_next[0] = bi0;
1811  from += 1;
1812  to_next += 1;
1813  n_left_from -= 1;
1814  n_left_to_next -= 1;
1815 
1816  b0 = vlib_get_buffer (vm, bi0);
1817  next0 = SNAT_IN2OUT_NEXT_LOOKUP;
1818 
1819  ip0 = vlib_buffer_get_current (b0);
1820  udp0 = ip4_next_header (ip0);
1821  tcp0 = (tcp_header_t *) udp0;
1822  icmp0 = (icmp46_header_t *) udp0;
1823 
1824  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1825  rx_fib_index0 =
1827 
1828  if (PREDICT_FALSE (ip0->ttl == 1))
1829  {
1830  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1831  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1832  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1833  0);
1835  goto trace0;
1836  }
1837 
1838  proto0 = ip_proto_to_nat_proto (ip0->protocol);
1839 
1840  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1841  goto trace0;
1842 
1843  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1844  {
1845  next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0,
1846  rx_fib_index0, node, next0, ~0, 0, 0);
1847  goto trace0;
1848  }
1849 
1850  key0.addr = ip0->src_address;
1851  key0.protocol = proto0;
1852  key0.port = udp0->src_port;
1853  key0.fib_index = rx_fib_index0;
1854 
1855  if (snat_static_mapping_match (sm, key0, &sm0, 0, 0, 0, 0, 0, 0))
1856  {
1857  b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
1858  next0 = SNAT_IN2OUT_NEXT_DROP;
1859  goto trace0;
1860  }
1861 
1862  new_addr0 = sm0.addr.as_u32;
1863  new_port0 = sm0.port;
1864  vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
1865  old_addr0 = ip0->src_address.as_u32;
1866  ip0->src_address.as_u32 = new_addr0;
1867 
1868  sum0 = ip0->checksum;
1869  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1870  ip4_header_t,
1871  src_address /* changed member */ );
1872  ip0->checksum = ip_csum_fold (sum0);
1873 
1874  if (PREDICT_FALSE (new_port0 != udp0->dst_port))
1875  {
1876  old_port0 = udp0->src_port;
1877  udp0->src_port = new_port0;
1878 
1879  if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1880  {
1881  sum0 = tcp0->checksum;
1882  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1883  ip4_header_t,
1884  dst_address /* changed member */ );
1885  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1886  ip4_header_t /* cheat */ ,
1887  length /* changed member */ );
1888  mss_clamping (sm, tcp0, &sum0);
1889  tcp0->checksum = ip_csum_fold (sum0);
1890  }
1891  else if (udp0->checksum)
1892  {
1893  sum0 = udp0->checksum;
1894  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1895  ip4_header_t,
1896  dst_address /* changed member */ );
1897  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1898  ip4_header_t /* cheat */ ,
1899  length /* changed member */ );
1900  udp0->checksum = ip_csum_fold (sum0);
1901  }
1902  }
1903  else
1904  {
1905  if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1906  {
1907  sum0 = tcp0->checksum;
1908  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1909  ip4_header_t,
1910  dst_address /* changed member */ );
1911  mss_clamping (sm, tcp0, &sum0);
1912  tcp0->checksum = ip_csum_fold (sum0);
1913  }
1914  else if (udp0->checksum)
1915  {
1916  sum0 = udp0->checksum;
1917  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1918  ip4_header_t,
1919  dst_address /* changed member */ );
1920  udp0->checksum = ip_csum_fold (sum0);
1921  }
1922  }
1923 
1924  /* Hairpinning */
1925  snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0, 0);
1926 
1927  trace0:
1928  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1929  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1930  {
1931  snat_in2out_trace_t *t =
1932  vlib_add_trace (vm, node, b0, sizeof (*t));
1933  t->sw_if_index = sw_if_index0;
1934  t->next_index = next0;
1935  }
1936 
1937  pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
1938 
1939  /* verify speculative enqueue, maybe switch current next frame */
1940  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1941  to_next, n_left_to_next,
1942  bi0, next0);
1943  }
1944 
1945  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1946  }
1947 
1948  vlib_node_increment_counter (vm, stats_node_index,
1949  SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
1950  pkts_processed);
1951  return frame->n_vectors;
1952 }
1953 
1954 
1955 /* *INDENT-OFF* */
1957  .name = "nat44-in2out-fast",
1958  .vector_size = sizeof (u32),
1959  .format_trace = format_snat_in2out_fast_trace,
1961 
1962  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1963  .error_strings = snat_in2out_error_strings,
1964 
1965  .runtime_data_bytes = sizeof (snat_runtime_t),
1966 
1967  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1968 
1969  /* edit / add dispositions here */
1970  .next_nodes = {
1971  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1972  [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1973  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
1974  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1975  },
1976 };
1977 /* *INDENT-ON* */
1978 
1979 /*
1980  * fd.io coding-style-patch-verification: ON
1981  *
1982  * Local Variables:
1983  * eval: (c-set-style "gnu")
1984  * End:
1985  */
ip4_address_t external_addr
Definition: nat.h:401
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
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:212
static ip_csum_t ip_incremental_checksum_buffer(vlib_main_t *vm, vlib_buffer_t *first_buffer, u32 first_buffer_offset, u32 n_bytes_to_checksum, ip_csum_t sum)
Definition: ip.h:152
nat_outside_fib_t * outside_fibs
Definition: nat.h:566
static u32 slow_path(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, u32 rx_fib_index0, snat_session_key_t *key0, snat_session_t **sessionp, vlib_node_runtime_t *node, u32 next0, u32 thread_index, f64 now)
Definition: in2out.c:243
#define snat_is_session_static(s)
Check if SNAT session is created from static mapping.
Definition: nat.h:728
static u8 * format_snat_in2out_trace(u8 *s, va_list *args)
Definition: in2out.c:49
#define CLIB_UNUSED(x)
Definition: clib.h:86
snat_in2out_error_t
Definition: in2out.c:94
ip4_address_t src_address
Definition: ip4_packet.h:170
static int nat_not_translate_output_feature(snat_main_t *sm, ip4_header_t *ip0, u32 proto0, u16 src_port, u16 dst_port, u32 thread_index, u32 sw_if_index)
Definition: in2out.c:152
static u32 nat44_session_get_timeout(snat_main_t *sm, snat_session_t *s)
Definition: nat_inlines.h:385
static u8 * format_snat_in2out_fast_trace(u8 *s, va_list *args)
Definition: in2out.c:65
#define nat_elog_notice(nat_elog_str)
Definition: nat.h:986
static uword snat_in2out_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_slow_path, int is_output_feature)
Definition: in2out.c:879
#define PREDICT_TRUE(x)
Definition: clib.h:119
unsigned long u64
Definition: types.h:89
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:291
static char * snat_in2out_error_strings[]
Definition: in2out.c:102
u16 port_per_thread
Definition: nat.h:532
u32 thread_index
Definition: main.h:218
uword ip_csum_t
Definition: ip_packet.h:244
#define nat_elog_warn(nat_elog_str)
Definition: nat.h:988
snat_in2out_next_t
Definition: in2out.c:108
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:122
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:472
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:402
void snat_ipfix_logging_nat44_ses_create(u32 thread_index, u32 src_ip, u32 nat_src_ip, nat_protocol_t nat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session create event.
struct _tcp_header tcp_header_t
int snat_hairpinning(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, udp_header_t *udp0, tcp_header_t *tcp0, u32 proto0, int is_ed)
u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation.
Definition: in2out.c:581
unsigned char u8
Definition: types.h:56
u8 deterministic
Definition: nat.h:629
static_always_inline snat_in2out_error_t icmp_get_key(vlib_buffer_t *b, ip4_header_t *ip0, snat_session_key_t *p_key0)
Definition: in2out.c:396
double f64
Definition: types.h:142
static int ip4_is_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:213
static int snat_not_translate_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0)
Check if packet should be translated.
Definition: nat_inlines.h:698
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:533
u16 src_port
Definition: udp.api:41
clib_bihash_8_8_t in2out
Definition: nat.h:454
vlib_node_registration_t snat_in2out_output_slowpath_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_output_slowpath_node)
Definition: in2out.c:1746
vl_api_ip_proto_t protocol
Definition: lb_types.api:71
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:230
#define static_always_inline
Definition: clib.h:106
static uword ip4_header_checksum_is_valid(ip4_header_t *i)
Definition: ip4_packet.h:332
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:513
static nat_protocol_t ip_proto_to_nat_proto(u8 ip_proto)
Common NAT inline functions.
Definition: inlines.h:22
vl_api_interface_index_t sw_if_index
Definition: gre.api:53
vlib_node_registration_t snat_in2out_fast_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_fast_node)
Definition: in2out.c:1956
void nat_syslog_nat44_apmdel(u32 ssubix, u32 sfibix, ip4_address_t *isaddr, u16 isport, ip4_address_t *xsaddr, u16 xsport, nat_protocol_t proto)
Definition: nat_syslog.c:116
static int snat_not_translate(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0, u32 thread_index)
Definition: in2out.c:118
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.
Aggregate type for a prefix.
Definition: fib_types.h:203
static_always_inline u8 icmp_type_is_error_message(u8 icmp_type)
Definition: inlines.h:53
u32 icmp_in2out(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0, u32 thread_index, void *d, void *e)
Definition: in2out.c:654
ip4_main_t * ip4_main
Definition: nat.h:672
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:241
unsigned int u32
Definition: types.h:88
vlib_node_registration_t snat_in2out_slowpath_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_slowpath_node)
Definition: in2out.c:1714
void nat_ipfix_logging_max_sessions(u32 thread_index, u32 limit)
Generate maximum session entries exceeded event.
fib_node_index_t fib_table_lookup(u32 fib_index, const fib_prefix_t *prefix)
Perfom a longest prefix match in the non-forwarding table.
Definition: fib_table.c:68
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:2741
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:2669
static void nat44_delete_session(snat_main_t *sm, snat_session_t *ses, u32 thread_index)
Definition: nat_inlines.h:249
#define foreach_snat_in2out_error
Definition: in2out.c:77
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
u32 max_translations
Definition: nat.h:635
static void mss_clamping(snat_main_t *sm, tcp_header_t *tcp, ip_csum_t *sum)
Definition: nat_inlines.h:635
int snat_alloc_outside_address_and_port(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u16 port_per_thread, u32 snat_thread_index)
Alloc outside address and port.
Definition: nat.c:2900
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:481
void nat_syslog_nat44_apmadd(u32 ssubix, u32 sfibix, ip4_address_t *isaddr, u16 isport, ip4_address_t *xsaddr, u16 xsport, nat_protocol_t proto)
Definition: nat_syslog.c:107
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:534
u32 fib_index
Definition: nat.h:328
u64 key
the key
Definition: bihash_8_8.h:41
static u32 icmp_in2out_slow_path(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0, f64 now, u32 thread_index, snat_session_t **p_s0)
Definition: in2out.c:813
long ctx[MAX_CONNS]
Definition: main.c:144
unsigned short u16
Definition: types.h:57
u16 protocol
Definition: nat.h:80
snat_static_mapping_t * static_mappings
Definition: nat.h:545
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
#define PREDICT_FALSE(x)
Definition: clib.h:118
vl_api_address_union_t src_address
Definition: ip_types.api:99
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:224
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:338
vlib_main_t * vm
Definition: in2out_ed.c:1599
u32 snat_icmp_hairpinning(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, int is_ed)
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
int nat44_o2i_is_idle_session_cb(clib_bihash_kv_8_8_t *kv, void *arg)
Definition: out2in.c:115
u32 fib_entry_get_resolving_interface(fib_node_index_t entry_index)
Definition: fib_entry.c:1458
snat_interface_t * output_feature_interfaces
Definition: nat.h:549
snat_main_t snat_main
Definition: nat.c:41
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
u64 value
the value
Definition: bihash_8_8.h:42
static int nat_in2out_sm_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index)
Definition: in2out.c:841
static void nat44_delete_user_with_no_session(snat_main_t *sm, snat_user_t *u, u32 thread_index)
Definition: nat_inlines.h:227
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:399
clib_bihash_8_8_t out2in
Definition: nat.h:453
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
vlib_node_registration_t snat_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_node)
Definition: in2out.c:1650
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
static void nat44_session_update_counters(snat_session_t *s, f64 now, uword bytes, u32 thread_index)
Definition: nat_inlines.h:408
u8 data[]
Packet data.
Definition: buffer.h:181
u32 outside_fib_index
Definition: nat.h:643
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:30
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:39
#define ARRAY_LEN(x)
Definition: clib.h:66
ip4_address_t addr
Definition: nat.h:78
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:483
u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: in2out.c:457
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1599
u32 in2out_fast_node_index
Definition: nat.h:600
static_always_inline u8 nat44_maximum_sessions_exceeded(snat_main_t *sm, u32 thread_index)
The NAT44 inline functions.
Definition: inlines.h:26
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:517
u8 value
Definition: qos.api:54
#define ASSERT(truth)
u32 in2out_slowpath_node_index
Definition: nat.h:601
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:422
void snat_ipfix_logging_nat44_ses_delete(u32 thread_index, u32 src_ip, u32 nat_src_ip, nat_protocol_t nat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session delete event.
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
void nat_ha_sdel(ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index, u32 thread_index)
Create session delete HA event.
Definition: nat_ha.c:715
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
#define vec_elt(v, i)
Get vector value at index i.
Definition: defs.h:47
void nat_hairpinning_sm_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip)
vl_api_address_t ip
Definition: l2.api:501
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:31
static void user_session_increment(snat_main_t *sm, snat_user_t *u, u8 is_static)
Definition: nat_inlines.h:215
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
snat_main_per_thread_data_t * per_thread_data
Definition: nat.h:536
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:294
NAT syslog logging.
snat_address_t * addresses
Definition: nat.h:552
u32 in2out_node_index
Definition: nat.h:598
#define vnet_buffer(b)
Definition: buffer.h:417
#define SNAT_SESSION_FLAG_STATIC_MAPPING
Definition: nat.h:232
u8 forwarding_enabled
Definition: nat.h:624
#define vec_foreach(var, vec)
Vector iterator.
vlib_node_registration_t snat_in2out_output_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_output_node)
Definition: in2out.c:1682
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1600
u16 flags
Copy of main node flags.
Definition: node.h:511
u8 endpoint_dependent
Definition: nat.h:631
u16 dst_port
Definition: udp.api:42
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:235
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:304
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
int nat44_i2o_is_idle_session_cb(clib_bihash_kv_8_8_t *kv, void *arg)
Definition: in2out.c:195
snat_session_t * sessions
Definition: nat.h:467
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
snat_icmp_match_function_t * icmp_match_in2out_cb
Definition: nat.h:523
clib_bihash_8_8_t static_mapping_by_local
Definition: nat.h:539
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:300
Definition: defs.h:46
NAT active-passive HA.
u16 fib_index
Definition: nat.h:80