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