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