FD.io VPP  v17.04.2-2-ga8f93f8
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 #include <vlib/vlib.h>
17 #include <vnet/vnet.h>
18 #include <vnet/pg/pg.h>
19 #include <vnet/handoff.h>
20 
21 #include <vnet/ip/ip.h>
22 #include <vnet/ethernet/ethernet.h>
23 #include <vnet/fib/ip4_fib.h>
24 #include <snat/snat.h>
26 #include <snat/snat_det.h>
27 
28 #include <vppinfra/hash.h>
29 #include <vppinfra/error.h>
30 #include <vppinfra/elog.h>
31 
32 typedef struct {
38 
39 typedef struct {
43 
44 /* packet trace format function */
45 static u8 * format_snat_in2out_trace (u8 * s, va_list * args)
46 {
47  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
48  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
49  snat_in2out_trace_t * t = va_arg (*args, snat_in2out_trace_t *);
50  char * tag;
51 
52  tag = t->is_slow_path ? "SNAT_IN2OUT_SLOW_PATH" : "SNAT_IN2OUT_FAST_PATH";
53 
54  s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
56 
57  return s;
58 }
59 
60 static u8 * format_snat_in2out_fast_trace (u8 * s, va_list * args)
61 {
62  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
63  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
64  snat_in2out_trace_t * t = va_arg (*args, snat_in2out_trace_t *);
65 
66  s = format (s, "SANT_IN2OUT_FAST: sw_if_index %d, next index %d",
67  t->sw_if_index, t->next_index);
68 
69  return s;
70 }
71 
72 static u8 * format_snat_in2out_worker_handoff_trace (u8 * s, va_list * args)
73 {
74  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
75  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
77  va_arg (*args, snat_in2out_worker_handoff_trace_t *);
78  char * m;
79 
80  m = t->do_handoff ? "next worker" : "same worker";
81  s = format (s, "SNAT_IN2OUT_WORKER_HANDOFF: %s %d", m, t->next_worker_index);
82 
83  return s;
84 }
85 
91 
92 #define foreach_snat_in2out_error \
93 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
94 _(IN2OUT_PACKETS, "Good in2out packets processed") \
95 _(OUT_OF_PORTS, "Out of ports") \
96 _(BAD_OUTSIDE_FIB, "Outside VRF ID not found") \
97 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
98 _(NO_TRANSLATION, "No translation")
99 
100 typedef enum {
101 #define _(sym,str) SNAT_IN2OUT_ERROR_##sym,
103 #undef _
106 
107 static char * snat_in2out_error_strings[] = {
108 #define _(sym,string) string,
110 #undef _
111 };
112 
113 typedef enum {
120 
121 /**
122  * @brief Check if packet should be translated
123  *
124  * Packets aimed at outside interface and external addresss with active session
125  * should be translated.
126  *
127  * @param sm SNAT main
128  * @param rt SNAT runtime data
129  * @param sw_if_index0 index of the inside interface
130  * @param ip0 IPv4 header
131  * @param proto0 SNAT protocol
132  * @param rx_fib_index0 RX FIB index
133  *
134  * @returns 0 if packet should be translated otherwise 1
135  */
136 static inline int
138  ip4_header_t * ip0, u32 proto0, u32 rx_fib_index0)
139 {
140  ip4_address_t * first_int_addr;
141  udp_header_t * udp0 = ip4_next_header (ip0);
142  snat_session_key_t key0, sm0;
143  clib_bihash_kv_8_8_t kv0, value0;
145  fib_prefix_t pfx = {
147  .fp_len = 32,
148  .fp_addr = {
149  .ip4.as_u32 = ip0->dst_address.as_u32,
150  },
151  };
152 
153  if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0))
154  {
155  first_int_addr =
156  ip4_interface_first_address (sm->ip4_main, sw_if_index0,
157  0 /* just want the address */);
158  rt->cached_sw_if_index = sw_if_index0;
159  if (first_int_addr)
160  rt->cached_ip4_address = first_int_addr->as_u32;
161  else
162  rt->cached_ip4_address = 0;
163  }
164 
165  /* Don't NAT packet aimed at the intfc address */
167  return 1;
168 
169  key0.addr = ip0->dst_address;
170  key0.port = udp0->dst_port;
171  key0.protocol = proto0;
172  key0.fib_index = sm->outside_fib_index;
173  kv0.key = key0.as_u64;
174 
175  /* NAT packet aimed at external address if */
176  /* has active sessions */
177  if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
178  {
179  /* or is static mappings */
180  if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0))
181  return 0;
182  }
183  else
184  return 0;
185 
186  fei = fib_table_lookup (rx_fib_index0, &pfx);
187  if (FIB_NODE_INDEX_INVALID != fei)
188  {
189  u32 sw_if_index = fib_entry_get_resolving_interface (fei);
190  if (sw_if_index == ~0)
191  {
192  fei = fib_table_lookup (sm->outside_fib_index, &pfx);
193  if (FIB_NODE_INDEX_INVALID != fei)
194  sw_if_index = fib_entry_get_resolving_interface (fei);
195  }
197  pool_foreach (i, sm->interfaces,
198  ({
199  /* NAT packet aimed at outside interface */
200  if ((i->is_inside == 0) && (sw_if_index == i->sw_if_index))
201  return 0;
202  }));
203  }
204 
205  return 1;
206 }
207 
209  ip4_header_t * ip0,
210  u32 rx_fib_index0,
211  snat_session_key_t * key0,
212  snat_session_t ** sessionp,
213  vlib_node_runtime_t * node,
214  u32 next0,
215  u32 cpu_index)
216 {
217  snat_user_t *u;
218  snat_user_key_t user_key;
219  snat_session_t *s;
220  clib_bihash_kv_8_8_t kv0, value0;
221  u32 oldest_per_user_translation_list_index;
222  dlist_elt_t * oldest_per_user_translation_list_elt;
223  dlist_elt_t * per_user_translation_list_elt;
224  dlist_elt_t * per_user_list_head_elt;
225  u32 session_index;
226  snat_session_key_t key1;
227  u32 address_index = ~0;
228  u32 outside_fib_index;
229  uword * p;
230  snat_worker_key_t worker_by_out_key;
231 
232  p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->outside_vrf_id);
233  if (! p)
234  {
235  b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_OUTSIDE_FIB];
236  return SNAT_IN2OUT_NEXT_DROP;
237  }
238  outside_fib_index = p[0];
239 
240  key1.protocol = key0->protocol;
241  user_key.addr = ip0->src_address;
242  user_key.fib_index = rx_fib_index0;
243  kv0.key = user_key.as_u64;
244 
245  /* Ever heard of the "user" = src ip4 address before? */
246  if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0))
247  {
248  /* no, make a new one */
249  pool_get (sm->per_thread_data[cpu_index].users, u);
250  memset (u, 0, sizeof (*u));
251  u->addr = ip0->src_address;
252  u->fib_index = rx_fib_index0;
253 
254  pool_get (sm->per_thread_data[cpu_index].list_pool, per_user_list_head_elt);
255 
256  u->sessions_per_user_list_head_index = per_user_list_head_elt -
257  sm->per_thread_data[cpu_index].list_pool;
258 
259  clib_dlist_init (sm->per_thread_data[cpu_index].list_pool,
261 
262  kv0.value = u - sm->per_thread_data[cpu_index].users;
263 
264  /* add user */
265  clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */);
266  }
267  else
268  {
269  u = pool_elt_at_index (sm->per_thread_data[cpu_index].users,
270  value0.value);
271  }
272 
273  /* Over quota? Recycle the least recently used dynamic translation */
274  if (u->nsessions >= sm->max_translations_per_user)
275  {
276  /* Remove the oldest dynamic translation */
277  do {
278  oldest_per_user_translation_list_index =
279  clib_dlist_remove_head (sm->per_thread_data[cpu_index].list_pool,
281 
282  ASSERT (oldest_per_user_translation_list_index != ~0);
283 
284  /* add it back to the end of the LRU list */
285  clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
287  oldest_per_user_translation_list_index);
288  /* Get the list element */
289  oldest_per_user_translation_list_elt =
290  pool_elt_at_index (sm->per_thread_data[cpu_index].list_pool,
291  oldest_per_user_translation_list_index);
292 
293  /* Get the session index from the list element */
294  session_index = oldest_per_user_translation_list_elt->value;
295 
296  /* Get the session */
297  s = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
298  session_index);
299  } while (snat_is_session_static (s));
300 
301  /* Remove in2out, out2in keys */
302  kv0.key = s->in2out.as_u64;
303  if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 0 /* is_add */))
304  clib_warning ("in2out key delete failed");
305  kv0.key = s->out2in.as_u64;
306  if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 0 /* is_add */))
307  clib_warning ("out2in key delete failed");
308 
309  /* log NAT event */
310  snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
311  s->out2in.addr.as_u32,
312  s->in2out.protocol,
313  s->in2out.port,
314  s->out2in.port,
315  s->in2out.fib_index);
316 
318  (sm, &s->out2in, s->outside_address_index);
319  s->outside_address_index = ~0;
320 
321  if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, &key1,
322  &address_index))
323  {
324  ASSERT(0);
325 
326  b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
327  return SNAT_IN2OUT_NEXT_DROP;
328  }
329  s->outside_address_index = address_index;
330  }
331  else
332  {
333  u8 static_mapping = 1;
334 
335  /* First try to match static mapping by local address and port */
336  if (snat_static_mapping_match (sm, *key0, &key1, 0, 0))
337  {
338  static_mapping = 0;
339  /* Try to create dynamic translation */
340  if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, &key1,
341  &address_index))
342  {
343  b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
344  return SNAT_IN2OUT_NEXT_DROP;
345  }
346  }
347 
348  /* Create a new session */
349  pool_get (sm->per_thread_data[cpu_index].sessions, s);
350  memset (s, 0, sizeof (*s));
351 
352  s->outside_address_index = address_index;
353 
354  if (static_mapping)
355  {
356  u->nstaticsessions++;
358  }
359  else
360  {
361  u->nsessions++;
362  }
363 
364  /* Create list elts */
365  pool_get (sm->per_thread_data[cpu_index].list_pool,
366  per_user_translation_list_elt);
367  clib_dlist_init (sm->per_thread_data[cpu_index].list_pool,
368  per_user_translation_list_elt -
369  sm->per_thread_data[cpu_index].list_pool);
370 
371  per_user_translation_list_elt->value =
372  s - sm->per_thread_data[cpu_index].sessions;
373  s->per_user_index = per_user_translation_list_elt -
374  sm->per_thread_data[cpu_index].list_pool;
375  s->per_user_list_head_index = u->sessions_per_user_list_head_index;
376 
377  clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
378  s->per_user_list_head_index,
379  per_user_translation_list_elt -
380  sm->per_thread_data[cpu_index].list_pool);
381  }
382 
383  s->in2out = *key0;
384  s->out2in = key1;
385  s->out2in.protocol = key0->protocol;
386  s->out2in.fib_index = outside_fib_index;
387  *sessionp = s;
388 
389  /* Add to translation hashes */
390  kv0.key = s->in2out.as_u64;
391  kv0.value = s - sm->per_thread_data[cpu_index].sessions;
392  if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */))
393  clib_warning ("in2out key add failed");
394 
395  kv0.key = s->out2in.as_u64;
396  kv0.value = s - sm->per_thread_data[cpu_index].sessions;
397 
398  if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */))
399  clib_warning ("out2in key add failed");
400 
401  /* Add to translated packets worker lookup */
402  worker_by_out_key.addr = s->out2in.addr;
403  worker_by_out_key.port = s->out2in.port;
404  worker_by_out_key.fib_index = s->out2in.fib_index;
405  kv0.key = worker_by_out_key.as_u64;
406  kv0.value = cpu_index;
407  clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1);
408 
409  /* log NAT event */
410  snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32,
411  s->out2in.addr.as_u32,
412  s->in2out.protocol,
413  s->in2out.port,
414  s->out2in.port,
415  s->in2out.fib_index);
416  return next0;
417 }
418 
421  snat_session_key_t *p_key0)
422 {
423  icmp46_header_t *icmp0;
424  snat_session_key_t key0;
425  icmp_echo_header_t *echo0, *inner_echo0 = 0;
426  ip4_header_t *inner_ip0 = 0;
427  void *l4_header = 0;
428  icmp46_header_t *inner_icmp0;
429 
430  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
431  echo0 = (icmp_echo_header_t *)(icmp0+1);
432 
433  if (!icmp_is_error_message (icmp0))
434  {
435  key0.protocol = SNAT_PROTOCOL_ICMP;
436  key0.addr = ip0->src_address;
437  key0.port = echo0->identifier;
438  }
439  else
440  {
441  inner_ip0 = (ip4_header_t *)(echo0+1);
442  l4_header = ip4_next_header (inner_ip0);
443  key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
444  key0.addr = inner_ip0->dst_address;
445  switch (key0.protocol)
446  {
447  case SNAT_PROTOCOL_ICMP:
448  inner_icmp0 = (icmp46_header_t*)l4_header;
449  inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
450  key0.port = inner_echo0->identifier;
451  break;
452  case SNAT_PROTOCOL_UDP:
453  case SNAT_PROTOCOL_TCP:
454  key0.port = ((tcp_udp_header_t*)l4_header)->dst_port;
455  break;
456  default:
457  return SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL;
458  }
459  }
460  *p_key0 = key0;
461  return -1; /* success */
462 }
463 
464 /**
465  * Get address and port values to be used for packet SNAT translation
466  * and create session if needed
467  *
468  * @param[in,out] sm SNAT main
469  * @param[in,out] node SNAT node runtime
470  * @param[in] cpu_index CPU index
471  * @param[in,out] b0 buffer containing packet to be translated
472  * @param[out] p_key address and port before NAT translation
473  * @param[out] p_value address and port after NAT translation
474  * @param[out] p_dont_translate if packet should not be translated
475  * @param d optional parameter
476  */
478  u32 cpu_index, vlib_buffer_t *b0,
479  snat_session_key_t *p_key,
480  snat_session_key_t *p_value,
481  u8 *p_dont_translate, void *d)
482 {
483  snat_runtime_t *rt;
484  ip4_header_t *ip0;
485  icmp46_header_t *icmp0;
486  u32 sw_if_index0;
487  u32 rx_fib_index0;
488  snat_session_key_t key0;
489  snat_session_t *s0 = 0;
490  u8 dont_translate = 0;
491  clib_bihash_kv_8_8_t kv0, value0;
492  u32 next0 = ~0;
493  int err;
494 
495  rt = (snat_runtime_t *) node->runtime_data;
496  ip0 = vlib_buffer_get_current (b0);
497  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
498  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
499  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
500 
501  err = icmp_get_key (ip0, &key0);
502  if (err != -1)
503  {
504  b0->error = node->errors[err];
505  next0 = SNAT_IN2OUT_NEXT_DROP;
506  goto out;
507  }
508  key0.fib_index = rx_fib_index0;
509 
510  kv0.key = key0.as_u64;
511 
512  if (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0))
513  {
514  if (PREDICT_FALSE(snat_not_translate(sm, rt, sw_if_index0, ip0,
515  IP_PROTOCOL_ICMP, rx_fib_index0)))
516  {
517  dont_translate = 1;
518  goto out;
519  }
520 
521  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request))
522  {
523  b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
524  next0 = SNAT_IN2OUT_NEXT_DROP;
525  goto out;
526  }
527 
528  next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
529  &s0, node, next0, cpu_index);
530 
531  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
532  goto out;
533  }
534  else
535  {
536  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request &&
537  icmp0->type != ICMP4_echo_reply &&
538  !icmp_is_error_message (icmp0)))
539  {
540  b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
541  next0 = SNAT_IN2OUT_NEXT_DROP;
542  goto out;
543  }
544 
545  s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
546  value0.value);
547  }
548 
549 out:
550  *p_key = key0;
551  if (s0)
552  *p_value = s0->out2in;
553  *p_dont_translate = dont_translate;
554  if (d)
555  *(snat_session_t**)d = s0;
556  return next0;
557 }
558 
559 /**
560  * Get address and port values to be used for packet SNAT translation
561  *
562  * @param[in] sm SNAT main
563  * @param[in,out] node SNAT node runtime
564  * @param[in] cpu_index CPU index
565  * @param[in,out] b0 buffer containing packet to be translated
566  * @param[out] p_key address and port before NAT translation
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  */
572  u32 cpu_index, vlib_buffer_t *b0,
573  snat_session_key_t *p_key,
574  snat_session_key_t *p_value,
575  u8 *p_dont_translate, void *d)
576 {
577  snat_runtime_t *rt;
578  ip4_header_t *ip0;
579  icmp46_header_t *icmp0;
580  u32 sw_if_index0;
581  u32 rx_fib_index0;
582  snat_session_key_t key0;
583  snat_session_key_t sm0;
584  u8 dont_translate = 0;
585  u8 is_addr_only;
586  u32 next0 = ~0;
587  int err;
588 
589  rt = (snat_runtime_t *) node->runtime_data;
590  ip0 = vlib_buffer_get_current (b0);
591  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
592  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
593  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
594 
595  err = icmp_get_key (ip0, &key0);
596  if (err != -1)
597  {
598  b0->error = node->errors[err];
599  next0 = SNAT_IN2OUT_NEXT_DROP;
600  goto out2;
601  }
602  key0.fib_index = rx_fib_index0;
603 
604  if (snat_static_mapping_match(sm, key0, &sm0, 0, &is_addr_only))
605  {
606  if (PREDICT_FALSE(snat_not_translate(sm, rt, sw_if_index0, ip0,
607  IP_PROTOCOL_ICMP, rx_fib_index0)))
608  {
609  dont_translate = 1;
610  goto out;
611  }
612 
613  if (icmp_is_error_message (icmp0))
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(icmp0->type != ICMP4_echo_request &&
625  (icmp0->type != ICMP4_echo_reply || !is_addr_only) &&
626  !icmp_is_error_message (icmp0)))
627  {
628  b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
629  next0 = SNAT_IN2OUT_NEXT_DROP;
630  goto out;
631  }
632 
633 out:
634  *p_value = sm0;
635 out2:
636  *p_key = key0;
637  *p_dont_translate = dont_translate;
638  return next0;
639 }
640 
641 static inline u32 icmp_in2out (snat_main_t *sm,
642  vlib_buffer_t * b0,
643  ip4_header_t * ip0,
644  icmp46_header_t * icmp0,
645  u32 sw_if_index0,
646  u32 rx_fib_index0,
647  vlib_node_runtime_t * node,
648  u32 next0,
649  u32 cpu_index,
650  void *d)
651 {
652  snat_session_key_t key0, sm0;
653  icmp_echo_header_t *echo0, *inner_echo0 = 0;
654  ip4_header_t *inner_ip0;
655  void *l4_header = 0;
656  icmp46_header_t *inner_icmp0;
657  u8 dont_translate;
658  u32 new_addr0, old_addr0;
659  u16 old_id0, new_id0;
660  ip_csum_t sum0;
661  u16 checksum0;
662  u32 next0_tmp;
663 
664  echo0 = (icmp_echo_header_t *)(icmp0+1);
665 
666  next0_tmp = sm->icmp_match_in2out_cb(sm, node, cpu_index, b0,
667  &key0, &sm0, &dont_translate, d);
668  if (next0_tmp != ~0)
669  next0 = next0_tmp;
670  if (next0 == SNAT_IN2OUT_NEXT_DROP || dont_translate)
671  goto out;
672 
673  sum0 = ip_incremental_checksum (0, icmp0,
674  ntohs(ip0->length) - ip4_header_bytes (ip0));
675  checksum0 = ~ip_csum_fold (sum0);
676  if (PREDICT_FALSE(checksum0 != 0 && checksum0 != 0xffff))
677  {
678  next0 = SNAT_IN2OUT_NEXT_DROP;
679  goto out;
680  }
681 
682  old_addr0 = ip0->src_address.as_u32;
683  new_addr0 = ip0->src_address.as_u32 = sm0.addr.as_u32;
684  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
685 
686  sum0 = ip0->checksum;
687  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
688  src_address /* changed member */);
689  ip0->checksum = ip_csum_fold (sum0);
690 
691  if (!icmp_is_error_message (icmp0))
692  {
693  new_id0 = sm0.port;
694  if (PREDICT_FALSE(new_id0 != echo0->identifier))
695  {
696  old_id0 = echo0->identifier;
697  new_id0 = sm0.port;
698  echo0->identifier = new_id0;
699 
700  sum0 = icmp0->checksum;
701  sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
702  identifier);
703  icmp0->checksum = ip_csum_fold (sum0);
704  }
705  }
706  else
707  {
708  inner_ip0 = (ip4_header_t *)(echo0+1);
709  l4_header = ip4_next_header (inner_ip0);
710 
711  if (!ip4_header_checksum_is_valid (inner_ip0))
712  {
713  next0 = SNAT_IN2OUT_NEXT_DROP;
714  goto out;
715  }
716 
717  old_addr0 = inner_ip0->dst_address.as_u32;
718  inner_ip0->dst_address = sm0.addr;
719  new_addr0 = inner_ip0->dst_address.as_u32;
720 
721  sum0 = icmp0->checksum;
722  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
723  dst_address /* changed member */);
724  icmp0->checksum = ip_csum_fold (sum0);
725 
726  switch (key0.protocol)
727  {
728  case SNAT_PROTOCOL_ICMP:
729  inner_icmp0 = (icmp46_header_t*)l4_header;
730  inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
731 
732  old_id0 = inner_echo0->identifier;
733  new_id0 = sm0.port;
734  inner_echo0->identifier = new_id0;
735 
736  sum0 = icmp0->checksum;
737  sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
738  identifier);
739  icmp0->checksum = ip_csum_fold (sum0);
740  break;
741  case SNAT_PROTOCOL_UDP:
742  case SNAT_PROTOCOL_TCP:
743  old_id0 = ((tcp_udp_header_t*)l4_header)->dst_port;
744  new_id0 = sm0.port;
745  ((tcp_udp_header_t*)l4_header)->dst_port = new_id0;
746 
747  sum0 = icmp0->checksum;
748  sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
749  dst_port);
750  icmp0->checksum = ip_csum_fold (sum0);
751  break;
752  default:
753  ASSERT(0);
754  }
755  }
756 
757 out:
758  return next0;
759 }
760 
761 /**
762  * @brief Hairpinning
763  *
764  * Hairpinning allows two endpoints on the internal side of the NAT to
765  * communicate even if they only use each other's external IP addresses
766  * and ports.
767  *
768  * @param sm SNAT main.
769  * @param b0 Vlib buffer.
770  * @param ip0 IP header.
771  * @param udp0 UDP header.
772  * @param tcp0 TCP header.
773  * @param proto0 SNAT protocol.
774  */
775 static inline void
777  vlib_buffer_t * b0,
778  ip4_header_t * ip0,
779  udp_header_t * udp0,
780  tcp_header_t * tcp0,
781  u32 proto0)
782 {
783  snat_session_key_t key0, sm0;
785  snat_session_t * s0;
786  clib_bihash_kv_8_8_t kv0, value0;
787  ip_csum_t sum0;
788  u32 new_dst_addr0 = 0, old_dst_addr0, ti = 0, si;
789  u16 new_dst_port0, old_dst_port0;
790 
791  key0.addr = ip0->dst_address;
792  key0.port = udp0->dst_port;
793  key0.protocol = proto0;
794  key0.fib_index = sm->outside_fib_index;
795  kv0.key = key0.as_u64;
796 
797  /* Check if destination is in active sessions */
798  if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
799  {
800  /* or static mappings */
801  if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0))
802  {
803  new_dst_addr0 = sm0.addr.as_u32;
804  new_dst_port0 = sm0.port;
805  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
806  }
807  }
808  else
809  {
810  si = value0.value;
811  if (sm->num_workers > 1)
812  {
813  k0.addr = ip0->dst_address;
814  k0.port = udp0->dst_port;
815  k0.fib_index = sm->outside_fib_index;
816  kv0.key = k0.as_u64;
817  if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0))
818  ASSERT(0);
819  else
820  ti = value0.value;
821  }
822  else
823  ti = sm->num_workers;
824 
825  s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si);
826  new_dst_addr0 = s0->in2out.addr.as_u32;
827  new_dst_port0 = s0->in2out.port;
828  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
829  }
830 
831  /* Destination is behind the same NAT, use internal address and port */
832  if (new_dst_addr0)
833  {
834  old_dst_addr0 = ip0->dst_address.as_u32;
835  ip0->dst_address.as_u32 = new_dst_addr0;
836  sum0 = ip0->checksum;
837  sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
838  ip4_header_t, dst_address);
839  ip0->checksum = ip_csum_fold (sum0);
840 
841  old_dst_port0 = tcp0->dst;
842  if (PREDICT_TRUE(new_dst_port0 != old_dst_port0))
843  {
844  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
845  {
846  tcp0->dst = new_dst_port0;
847  sum0 = tcp0->checksum;
848  sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
849  ip4_header_t, dst_address);
850  sum0 = ip_csum_update (sum0, old_dst_port0, new_dst_port0,
851  ip4_header_t /* cheat */, length);
852  tcp0->checksum = ip_csum_fold(sum0);
853  }
854  else
855  {
856  udp0->dst_port = new_dst_port0;
857  udp0->checksum = 0;
858  }
859  }
860  }
861 }
862 
864  vlib_buffer_t * b0,
865  ip4_header_t * ip0,
866  icmp46_header_t * icmp0,
867  u32 sw_if_index0,
868  u32 rx_fib_index0,
869  vlib_node_runtime_t * node,
870  u32 next0,
871  f64 now,
872  u32 cpu_index,
873  snat_session_t ** p_s0)
874 {
875  next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
876  next0, cpu_index, p_s0);
877  snat_session_t * s0 = *p_s0;
878  if (PREDICT_TRUE(next0 != SNAT_IN2OUT_NEXT_DROP && s0))
879  {
880  /* Accounting */
881  s0->last_heard = now;
882  s0->total_pkts++;
883  s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0);
884  /* Per-user LRU list maintenance for dynamic translations */
885  if (!snat_is_session_static (s0))
886  {
887  clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool,
888  s0->per_user_index);
889  clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
890  s0->per_user_list_head_index,
891  s0->per_user_index);
892  }
893  }
894  return next0;
895 }
896 
897 static inline uword
899  vlib_node_runtime_t * node,
900  vlib_frame_t * frame, int is_slow_path)
901 {
902  u32 n_left_from, * from, * to_next;
903  snat_in2out_next_t next_index;
904  u32 pkts_processed = 0;
905  snat_main_t * sm = &snat_main;
907  f64 now = vlib_time_now (vm);
908  u32 stats_node_index;
909  u32 cpu_index = os_get_cpu_number ();
910 
911  stats_node_index = is_slow_path ? snat_in2out_slowpath_node.index :
912  snat_in2out_node.index;
913 
914  from = vlib_frame_vector_args (frame);
915  n_left_from = frame->n_vectors;
916  next_index = node->cached_next_index;
917 
918  while (n_left_from > 0)
919  {
920  u32 n_left_to_next;
921 
922  vlib_get_next_frame (vm, node, next_index,
923  to_next, n_left_to_next);
924 
925  while (n_left_from >= 4 && n_left_to_next >= 2)
926  {
927  u32 bi0, bi1;
928  vlib_buffer_t * b0, * b1;
929  u32 next0, next1;
930  u32 sw_if_index0, sw_if_index1;
931  ip4_header_t * ip0, * ip1;
932  ip_csum_t sum0, sum1;
933  u32 new_addr0, old_addr0, new_addr1, old_addr1;
934  u16 old_port0, new_port0, old_port1, new_port1;
935  udp_header_t * udp0, * udp1;
936  tcp_header_t * tcp0, * tcp1;
937  icmp46_header_t * icmp0, * icmp1;
938  snat_session_key_t key0, key1;
939  u32 rx_fib_index0, rx_fib_index1;
940  u32 proto0, proto1;
941  snat_session_t * s0 = 0, * s1 = 0;
942  clib_bihash_kv_8_8_t kv0, value0, kv1, value1;
943 
944  /* Prefetch next iteration. */
945  {
946  vlib_buffer_t * p2, * p3;
947 
948  p2 = vlib_get_buffer (vm, from[2]);
949  p3 = vlib_get_buffer (vm, from[3]);
950 
951  vlib_prefetch_buffer_header (p2, LOAD);
952  vlib_prefetch_buffer_header (p3, LOAD);
953 
956  }
957 
958  /* speculatively enqueue b0 and b1 to the current next frame */
959  to_next[0] = bi0 = from[0];
960  to_next[1] = bi1 = from[1];
961  from += 2;
962  to_next += 2;
963  n_left_from -= 2;
964  n_left_to_next -= 2;
965 
966  b0 = vlib_get_buffer (vm, bi0);
967  b1 = vlib_get_buffer (vm, bi1);
968 
969  ip0 = vlib_buffer_get_current (b0);
970  udp0 = ip4_next_header (ip0);
971  tcp0 = (tcp_header_t *) udp0;
972  icmp0 = (icmp46_header_t *) udp0;
973 
974  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
975  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
976  sw_if_index0);
977 
978  next0 = next1 = SNAT_IN2OUT_NEXT_LOOKUP;
979 
980  if (PREDICT_FALSE(ip0->ttl == 1))
981  {
982  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
983  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
984  ICMP4_time_exceeded_ttl_exceeded_in_transit,
985  0);
987  goto trace00;
988  }
989 
990  proto0 = ip_proto_to_snat_proto (ip0->protocol);
991 
992  /* Next configured feature, probably ip4-lookup */
993  if (is_slow_path)
994  {
995  if (PREDICT_FALSE (proto0 == ~0))
996  goto trace00;
997 
998  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
999  {
1000  next0 = icmp_in2out_slow_path
1001  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
1002  node, next0, now, cpu_index, &s0);
1003  goto trace00;
1004  }
1005  }
1006  else
1007  {
1008  if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP))
1009  {
1011  goto trace00;
1012  }
1013  }
1014 
1015  key0.addr = ip0->src_address;
1016  key0.port = udp0->src_port;
1017  key0.protocol = proto0;
1018  key0.fib_index = rx_fib_index0;
1019 
1020  kv0.key = key0.as_u64;
1021 
1022  if (PREDICT_FALSE (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0) != 0))
1023  {
1024  if (is_slow_path)
1025  {
1026  if (PREDICT_FALSE(snat_not_translate(sm, rt, sw_if_index0, ip0,
1027  proto0, rx_fib_index0)))
1028  goto trace00;
1029 
1030  next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
1031  &s0, node, next0, cpu_index);
1032  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
1033  goto trace00;
1034  }
1035  else
1036  {
1038  goto trace00;
1039  }
1040  }
1041  else
1042  s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
1043  value0.value);
1044 
1045  old_addr0 = ip0->src_address.as_u32;
1046  ip0->src_address = s0->out2in.addr;
1047  new_addr0 = ip0->src_address.as_u32;
1048  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1049 
1050  sum0 = ip0->checksum;
1051  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1052  ip4_header_t,
1053  src_address /* changed member */);
1054  ip0->checksum = ip_csum_fold (sum0);
1055 
1056  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1057  {
1058  old_port0 = tcp0->src_port;
1059  tcp0->src_port = s0->out2in.port;
1060  new_port0 = tcp0->src_port;
1061 
1062  sum0 = tcp0->checksum;
1063  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1064  ip4_header_t,
1065  dst_address /* changed member */);
1066  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1067  ip4_header_t /* cheat */,
1068  length /* changed member */);
1069  tcp0->checksum = ip_csum_fold(sum0);
1070  }
1071  else
1072  {
1073  old_port0 = udp0->src_port;
1074  udp0->src_port = s0->out2in.port;
1075  udp0->checksum = 0;
1076  }
1077 
1078  /* Hairpinning */
1079  snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0);
1080 
1081  /* Accounting */
1082  s0->last_heard = now;
1083  s0->total_pkts++;
1084  s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1085  /* Per-user LRU list maintenance for dynamic translation */
1086  if (!snat_is_session_static (s0))
1087  {
1088  clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool,
1089  s0->per_user_index);
1090  clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
1091  s0->per_user_list_head_index,
1092  s0->per_user_index);
1093  }
1094  trace00:
1095 
1097  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1098  {
1099  snat_in2out_trace_t *t =
1100  vlib_add_trace (vm, node, b0, sizeof (*t));
1101  t->is_slow_path = is_slow_path;
1102  t->sw_if_index = sw_if_index0;
1103  t->next_index = next0;
1104  t->session_index = ~0;
1105  if (s0)
1106  t->session_index = s0 - sm->per_thread_data[cpu_index].sessions;
1107  }
1108 
1109  pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
1110 
1111  ip1 = vlib_buffer_get_current (b1);
1112  udp1 = ip4_next_header (ip1);
1113  tcp1 = (tcp_header_t *) udp1;
1114  icmp1 = (icmp46_header_t *) udp1;
1115 
1116  sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1117  rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1118  sw_if_index1);
1119 
1120  if (PREDICT_FALSE(ip1->ttl == 1))
1121  {
1122  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1123  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1124  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1125  0);
1127  goto trace01;
1128  }
1129 
1130  proto1 = ip_proto_to_snat_proto (ip1->protocol);
1131 
1132  /* Next configured feature, probably ip4-lookup */
1133  if (is_slow_path)
1134  {
1135  if (PREDICT_FALSE (proto1 == ~0))
1136  goto trace01;
1137 
1138  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1139  {
1140  next1 = icmp_in2out_slow_path
1141  (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1142  next1, now, cpu_index, &s1);
1143  goto trace01;
1144  }
1145  }
1146  else
1147  {
1148  if (PREDICT_FALSE (proto1 == ~0 || proto1 == SNAT_PROTOCOL_ICMP))
1149  {
1151  goto trace01;
1152  }
1153  }
1154 
1155  key1.addr = ip1->src_address;
1156  key1.port = udp1->src_port;
1157  key1.protocol = proto1;
1158  key1.fib_index = rx_fib_index1;
1159 
1160  kv1.key = key1.as_u64;
1161 
1162  if (PREDICT_FALSE(clib_bihash_search_8_8 (&sm->in2out, &kv1, &value1) != 0))
1163  {
1164  if (is_slow_path)
1165  {
1166  if (PREDICT_FALSE(snat_not_translate(sm, rt, sw_if_index1, ip1,
1167  proto1, rx_fib_index1)))
1168  goto trace01;
1169 
1170  next1 = slow_path (sm, b1, ip1, rx_fib_index1, &key1,
1171  &s1, node, next1, cpu_index);
1172  if (PREDICT_FALSE (next1 == SNAT_IN2OUT_NEXT_DROP))
1173  goto trace01;
1174  }
1175  else
1176  {
1178  goto trace01;
1179  }
1180  }
1181  else
1182  s1 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
1183  value1.value);
1184 
1185  old_addr1 = ip1->src_address.as_u32;
1186  ip1->src_address = s1->out2in.addr;
1187  new_addr1 = ip1->src_address.as_u32;
1188  vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index;
1189 
1190  sum1 = ip1->checksum;
1191  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1192  ip4_header_t,
1193  src_address /* changed member */);
1194  ip1->checksum = ip_csum_fold (sum1);
1195 
1196  if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1197  {
1198  old_port1 = tcp1->src_port;
1199  tcp1->src_port = s1->out2in.port;
1200  new_port1 = tcp1->src_port;
1201 
1202  sum1 = tcp1->checksum;
1203  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1204  ip4_header_t,
1205  dst_address /* changed member */);
1206  sum1 = ip_csum_update (sum1, old_port1, new_port1,
1207  ip4_header_t /* cheat */,
1208  length /* changed member */);
1209  tcp1->checksum = ip_csum_fold(sum1);
1210  }
1211  else
1212  {
1213  old_port1 = udp1->src_port;
1214  udp1->src_port = s1->out2in.port;
1215  udp1->checksum = 0;
1216  }
1217 
1218  /* Hairpinning */
1219  snat_hairpinning (sm, b1, ip1, udp1, tcp1, proto1);
1220 
1221  /* Accounting */
1222  s1->last_heard = now;
1223  s1->total_pkts++;
1224  s1->total_bytes += vlib_buffer_length_in_chain (vm, b1);
1225  /* Per-user LRU list maintenance for dynamic translation */
1226  if (!snat_is_session_static (s1))
1227  {
1228  clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool,
1229  s1->per_user_index);
1230  clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
1231  s1->per_user_list_head_index,
1232  s1->per_user_index);
1233  }
1234  trace01:
1235 
1237  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1238  {
1239  snat_in2out_trace_t *t =
1240  vlib_add_trace (vm, node, b1, sizeof (*t));
1241  t->sw_if_index = sw_if_index1;
1242  t->next_index = next1;
1243  t->session_index = ~0;
1244  if (s1)
1245  t->session_index = s1 - sm->per_thread_data[cpu_index].sessions;
1246  }
1247 
1248  pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP;
1249 
1250  /* verify speculative enqueues, maybe switch current next frame */
1251  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1252  to_next, n_left_to_next,
1253  bi0, bi1, next0, next1);
1254  }
1255 
1256  while (n_left_from > 0 && n_left_to_next > 0)
1257  {
1258  u32 bi0;
1259  vlib_buffer_t * b0;
1260  u32 next0;
1261  u32 sw_if_index0;
1262  ip4_header_t * ip0;
1263  ip_csum_t sum0;
1264  u32 new_addr0, old_addr0;
1265  u16 old_port0, new_port0;
1266  udp_header_t * udp0;
1267  tcp_header_t * tcp0;
1268  icmp46_header_t * icmp0;
1269  snat_session_key_t key0;
1270  u32 rx_fib_index0;
1271  u32 proto0;
1272  snat_session_t * s0 = 0;
1273  clib_bihash_kv_8_8_t kv0, value0;
1274 
1275  /* speculatively enqueue b0 to the current next frame */
1276  bi0 = from[0];
1277  to_next[0] = bi0;
1278  from += 1;
1279  to_next += 1;
1280  n_left_from -= 1;
1281  n_left_to_next -= 1;
1282 
1283  b0 = vlib_get_buffer (vm, bi0);
1284  next0 = SNAT_IN2OUT_NEXT_LOOKUP;
1285 
1286  ip0 = vlib_buffer_get_current (b0);
1287  udp0 = ip4_next_header (ip0);
1288  tcp0 = (tcp_header_t *) udp0;
1289  icmp0 = (icmp46_header_t *) udp0;
1290 
1291  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1292  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1293  sw_if_index0);
1294 
1295  if (PREDICT_FALSE(ip0->ttl == 1))
1296  {
1297  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1298  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1299  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1300  0);
1302  goto trace0;
1303  }
1304 
1305  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1306 
1307  /* Next configured feature, probably ip4-lookup */
1308  if (is_slow_path)
1309  {
1310  if (PREDICT_FALSE (proto0 == ~0))
1311  goto trace0;
1312 
1313  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1314  {
1315  next0 = icmp_in2out_slow_path
1316  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1317  next0, now, cpu_index, &s0);
1318  goto trace0;
1319  }
1320  }
1321  else
1322  {
1323  if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP))
1324  {
1326  goto trace0;
1327  }
1328  }
1329 
1330  key0.addr = ip0->src_address;
1331  key0.port = udp0->src_port;
1332  key0.protocol = proto0;
1333  key0.fib_index = rx_fib_index0;
1334 
1335  kv0.key = key0.as_u64;
1336 
1337  if (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0))
1338  {
1339  if (is_slow_path)
1340  {
1341  if (PREDICT_FALSE(snat_not_translate(sm, rt, sw_if_index0, ip0,
1342  proto0, rx_fib_index0)))
1343  goto trace0;
1344 
1345  next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
1346  &s0, node, next0, cpu_index);
1347 
1348  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
1349  goto trace0;
1350  }
1351  else
1352  {
1354  goto trace0;
1355  }
1356  }
1357  else
1358  s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
1359  value0.value);
1360 
1361  old_addr0 = ip0->src_address.as_u32;
1362  ip0->src_address = s0->out2in.addr;
1363  new_addr0 = ip0->src_address.as_u32;
1364  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1365 
1366  sum0 = ip0->checksum;
1367  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1368  ip4_header_t,
1369  src_address /* changed member */);
1370  ip0->checksum = ip_csum_fold (sum0);
1371 
1372  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1373  {
1374  old_port0 = tcp0->src_port;
1375  tcp0->src_port = s0->out2in.port;
1376  new_port0 = tcp0->src_port;
1377 
1378  sum0 = tcp0->checksum;
1379  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1380  ip4_header_t,
1381  dst_address /* changed member */);
1382  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1383  ip4_header_t /* cheat */,
1384  length /* changed member */);
1385  tcp0->checksum = ip_csum_fold(sum0);
1386  }
1387  else
1388  {
1389  old_port0 = udp0->src_port;
1390  udp0->src_port = s0->out2in.port;
1391  udp0->checksum = 0;
1392  }
1393 
1394  /* Hairpinning */
1395  snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0);
1396 
1397  /* Accounting */
1398  s0->last_heard = now;
1399  s0->total_pkts++;
1400  s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1401  /* Per-user LRU list maintenance for dynamic translation */
1402  if (!snat_is_session_static (s0))
1403  {
1404  clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool,
1405  s0->per_user_index);
1406  clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
1407  s0->per_user_list_head_index,
1408  s0->per_user_index);
1409  }
1410 
1411  trace0:
1413  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1414  {
1415  snat_in2out_trace_t *t =
1416  vlib_add_trace (vm, node, b0, sizeof (*t));
1417  t->is_slow_path = is_slow_path;
1418  t->sw_if_index = sw_if_index0;
1419  t->next_index = next0;
1420  t->session_index = ~0;
1421  if (s0)
1422  t->session_index = s0 - sm->per_thread_data[cpu_index].sessions;
1423  }
1424 
1425  pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
1426 
1427  /* verify speculative enqueue, maybe switch current next frame */
1428  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1429  to_next, n_left_to_next,
1430  bi0, next0);
1431  }
1432 
1433  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1434  }
1435 
1436  vlib_node_increment_counter (vm, stats_node_index,
1437  SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
1438  pkts_processed);
1439  return frame->n_vectors;
1440 }
1441 
1442 static uword
1444  vlib_node_runtime_t * node,
1445  vlib_frame_t * frame)
1446 {
1447  return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */);
1448 }
1449 
1451  .function = snat_in2out_fast_path_fn,
1452  .name = "snat-in2out",
1453  .vector_size = sizeof (u32),
1454  .format_trace = format_snat_in2out_trace,
1455  .type = VLIB_NODE_TYPE_INTERNAL,
1456 
1457  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1458  .error_strings = snat_in2out_error_strings,
1459 
1460  .runtime_data_bytes = sizeof (snat_runtime_t),
1461 
1462  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1463 
1464  /* edit / add dispositions here */
1465  .next_nodes = {
1466  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1467  [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1468  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath",
1469  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1470  },
1471 };
1472 
1474 
1475 static uword
1477  vlib_node_runtime_t * node,
1478  vlib_frame_t * frame)
1479 {
1480  return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */);
1481 }
1482 
1484  .function = snat_in2out_slow_path_fn,
1485  .name = "snat-in2out-slowpath",
1486  .vector_size = sizeof (u32),
1487  .format_trace = format_snat_in2out_trace,
1488  .type = VLIB_NODE_TYPE_INTERNAL,
1489 
1490  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1491  .error_strings = snat_in2out_error_strings,
1492 
1493  .runtime_data_bytes = sizeof (snat_runtime_t),
1494 
1495  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1496 
1497  /* edit / add dispositions here */
1498  .next_nodes = {
1499  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1500  [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1501  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath",
1502  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1503  },
1504 };
1505 
1507 
1508 /**************************/
1509 /*** deterministic mode ***/
1510 /**************************/
1511 static uword
1513  vlib_node_runtime_t * node,
1514  vlib_frame_t * frame)
1515 {
1516  u32 n_left_from, * from, * to_next;
1517  snat_in2out_next_t next_index;
1518  u32 pkts_processed = 0;
1519  snat_main_t * sm = &snat_main;
1520  u32 now = (u32) vlib_time_now (vm);
1521 
1522  from = vlib_frame_vector_args (frame);
1523  n_left_from = frame->n_vectors;
1524  next_index = node->cached_next_index;
1525 
1526  while (n_left_from > 0)
1527  {
1528  u32 n_left_to_next;
1529 
1530  vlib_get_next_frame (vm, node, next_index,
1531  to_next, n_left_to_next);
1532 
1533  while (n_left_from >= 4 && n_left_to_next >= 2)
1534  {
1535  u32 bi0, bi1;
1536  vlib_buffer_t * b0, * b1;
1537  u32 next0, next1;
1538  u32 sw_if_index0, sw_if_index1;
1539  ip4_header_t * ip0, * ip1;
1540  ip_csum_t sum0, sum1;
1541  ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
1542  u16 old_port0, new_port0, lo_port0, i0;
1543  u16 old_port1, new_port1, lo_port1, i1;
1544  udp_header_t * udp0, * udp1;
1545  tcp_header_t * tcp0, * tcp1;
1546  u32 proto0, proto1;
1547  snat_det_out_key_t key0, key1;
1548  snat_det_map_t * dm0, * dm1;
1549  snat_det_session_t * ses0 = 0, * ses1 = 0;
1550 
1551  /* Prefetch next iteration. */
1552  {
1553  vlib_buffer_t * p2, * p3;
1554 
1555  p2 = vlib_get_buffer (vm, from[2]);
1556  p3 = vlib_get_buffer (vm, from[3]);
1557 
1558  vlib_prefetch_buffer_header (p2, LOAD);
1559  vlib_prefetch_buffer_header (p3, LOAD);
1560 
1563  }
1564 
1565  /* speculatively enqueue b0 and b1 to the current next frame */
1566  to_next[0] = bi0 = from[0];
1567  to_next[1] = bi1 = from[1];
1568  from += 2;
1569  to_next += 2;
1570  n_left_from -= 2;
1571  n_left_to_next -= 2;
1572 
1573  b0 = vlib_get_buffer (vm, bi0);
1574  b1 = vlib_get_buffer (vm, bi1);
1575 
1576  next0 = SNAT_IN2OUT_NEXT_LOOKUP;
1577  next1 = SNAT_IN2OUT_NEXT_LOOKUP;
1578 
1579  ip0 = vlib_buffer_get_current (b0);
1580  udp0 = ip4_next_header (ip0);
1581  tcp0 = (tcp_header_t *) udp0;
1582 
1583  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1584 
1585  dm0 = snat_det_map_by_user(sm, &ip0->src_address);
1586  if (PREDICT_FALSE(!dm0))
1587  {
1588  clib_warning("no match for internal host %U",
1590  next0 = SNAT_IN2OUT_NEXT_DROP;
1591  b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
1592  goto trace0;
1593  }
1594 
1595  snat_det_forward(dm0, &ip0->src_address, &new_addr0, &lo_port0);
1596 
1597  ses0 = snat_det_find_ses_by_in(dm0, &ip0->src_address, tcp0->src);
1598  if (PREDICT_FALSE(!ses0))
1599  {
1600  key0.ext_host_addr = ip0->dst_address;
1601  key0.ext_host_port = tcp0->dst;
1602  for (i0 = 0; i0 < dm0->ports_per_host; i0++)
1603  {
1604  key0.out_port = clib_host_to_net_u16 (lo_port0 +
1605  ((i0 + clib_net_to_host_u16 (tcp0->src)) % dm0->ports_per_host));
1606 
1607  if (snat_det_get_ses_by_out (dm0, &ip0->src_address, key0.as_u64))
1608  continue;
1609 
1610  ses0 = snat_det_ses_create(dm0, &ip0->src_address, tcp0->src, &key0);
1611  break;
1612  }
1613  if (PREDICT_FALSE(!ses0))
1614  {
1615  next0 = SNAT_IN2OUT_NEXT_DROP;
1616  b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
1617  goto trace0;
1618  }
1619  }
1620 
1621  new_port0 = ses0->out.out_port;
1622  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1623 
1624  old_addr0.as_u32 = ip0->src_address.as_u32;
1625  ip0->src_address.as_u32 = new_addr0.as_u32;
1626  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
1627 
1628  sum0 = ip0->checksum;
1629  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1630  ip4_header_t,
1631  src_address /* changed member */);
1632  ip0->checksum = ip_csum_fold (sum0);
1633 
1634  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1635  {
1636  if (tcp0->flags & TCP_FLAG_SYN)
1637  ses0->state = SNAT_SESSION_TCP_SYN_SENT;
1638  else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
1639  ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
1640  else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
1641  ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
1642  else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
1643  snat_det_ses_close(dm0, ses0);
1644  else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
1645  ses0->state = SNAT_SESSION_TCP_LAST_ACK;
1646  else if (tcp0->flags == 0 && ses0->state == SNAT_SESSION_UNKNOWN)
1647  ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
1648 
1649  old_port0 = tcp0->src;
1650  tcp0->src = new_port0;
1651 
1652  sum0 = tcp0->checksum;
1653  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1654  ip4_header_t,
1655  dst_address /* changed member */);
1656  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1657  ip4_header_t /* cheat */,
1658  length /* changed member */);
1659  tcp0->checksum = ip_csum_fold(sum0);
1660  }
1661  else
1662  {
1663  ses0->state = SNAT_SESSION_UDP_ACTIVE;
1664  old_port0 = udp0->src_port;
1665  udp0->src_port = new_port0;
1666  udp0->checksum = 0;
1667  }
1668 
1669  switch(ses0->state)
1670  {
1671  case SNAT_SESSION_UDP_ACTIVE:
1672  ses0->expire = now + SNAT_UDP_TIMEOUT;
1673  break;
1674  case SNAT_SESSION_TCP_SYN_SENT:
1675  case SNAT_SESSION_TCP_FIN_WAIT:
1676  case SNAT_SESSION_TCP_CLOSE_WAIT:
1677  case SNAT_SESSION_TCP_LAST_ACK:
1678  ses0->expire = now + SNAT_TCP_TRANSITORY_TIMEOUT;
1679  break;
1680  case SNAT_SESSION_TCP_ESTABLISHED:
1681  ses0->expire = now + SNAT_TCP_ESTABLISHED_TIMEOUT;
1682  break;
1683  }
1684 
1685  trace0:
1687  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1688  {
1689  snat_in2out_trace_t *t =
1690  vlib_add_trace (vm, node, b0, sizeof (*t));
1691  t->is_slow_path = 0;
1692  t->sw_if_index = sw_if_index0;
1693  t->next_index = next0;
1694  t->session_index = ~0;
1695  if (ses0)
1696  t->session_index = ses0 - dm0->sessions;
1697  }
1698 
1699  pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
1700 
1701  ip1 = vlib_buffer_get_current (b1);
1702  udp1 = ip4_next_header (ip1);
1703  tcp1 = (tcp_header_t *) udp1;
1704 
1705  sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1706 
1707  dm1 = snat_det_map_by_user(sm, &ip1->src_address);
1708  if (PREDICT_FALSE(!dm1))
1709  {
1710  clib_warning("no match for internal host %U",
1712  next1 = SNAT_IN2OUT_NEXT_DROP;
1713  b1->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
1714  goto trace1;
1715  }
1716 
1717  snat_det_forward(dm1, &ip1->src_address, &new_addr1, &lo_port1);
1718 
1719  ses1 = snat_det_find_ses_by_in(dm1, &ip1->src_address, tcp1->src);
1720  if (PREDICT_FALSE(!ses1))
1721  {
1722  key1.ext_host_addr = ip1->dst_address;
1723  key1.ext_host_port = tcp1->dst;
1724  for (i1 = 0; i1 < dm1->ports_per_host; i1++)
1725  {
1726  key1.out_port = clib_host_to_net_u16 (lo_port1 +
1727  ((i1 + clib_net_to_host_u16 (tcp1->src)) % dm1->ports_per_host));
1728 
1729  if (snat_det_get_ses_by_out (dm1, &ip1->src_address, key1.as_u64))
1730  continue;
1731 
1732  ses1 = snat_det_ses_create(dm1, &ip1->src_address, tcp1->src, &key1);
1733  break;
1734  }
1735  if (PREDICT_FALSE(!ses1))
1736  {
1737  next1 = SNAT_IN2OUT_NEXT_DROP;
1738  b1->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
1739  goto trace1;
1740  }
1741  }
1742 
1743  new_port1 = ses1->out.out_port;
1744  proto1 = ip_proto_to_snat_proto (ip1->protocol);
1745 
1746  old_addr1.as_u32 = ip1->src_address.as_u32;
1747  ip1->src_address.as_u32 = new_addr1.as_u32;
1748  vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
1749 
1750  sum1 = ip1->checksum;
1751  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
1752  ip4_header_t,
1753  src_address /* changed member */);
1754  ip1->checksum = ip_csum_fold (sum1);
1755 
1756  if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1757  {
1758  if (tcp1->flags & TCP_FLAG_SYN)
1759  ses1->state = SNAT_SESSION_TCP_SYN_SENT;
1760  else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_SYN_SENT)
1761  ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
1762  else if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
1763  ses1->state = SNAT_SESSION_TCP_FIN_WAIT;
1764  else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_FIN_WAIT)
1765  snat_det_ses_close(dm1, ses1);
1766  else if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_CLOSE_WAIT)
1767  ses1->state = SNAT_SESSION_TCP_LAST_ACK;
1768  else if (tcp1->flags == 0 && ses1->state == SNAT_SESSION_UNKNOWN)
1769  ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
1770 
1771  old_port1 = tcp1->src;
1772  tcp1->src = new_port1;
1773 
1774  sum1 = tcp1->checksum;
1775  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
1776  ip4_header_t,
1777  dst_address /* changed member */);
1778  sum1 = ip_csum_update (sum1, old_port1, new_port1,
1779  ip4_header_t /* cheat */,
1780  length /* changed member */);
1781  tcp1->checksum = ip_csum_fold(sum1);
1782  }
1783  else
1784  {
1785  ses1->state = SNAT_SESSION_UDP_ACTIVE;
1786  old_port1 = udp1->src_port;
1787  udp1->src_port = new_port1;
1788  udp1->checksum = 0;
1789  }
1790 
1791  switch(ses1->state)
1792  {
1793  case SNAT_SESSION_UDP_ACTIVE:
1794  ses1->expire = now + SNAT_UDP_TIMEOUT;
1795  break;
1796  case SNAT_SESSION_TCP_SYN_SENT:
1797  case SNAT_SESSION_TCP_FIN_WAIT:
1798  case SNAT_SESSION_TCP_CLOSE_WAIT:
1799  case SNAT_SESSION_TCP_LAST_ACK:
1800  ses1->expire = now + SNAT_TCP_TRANSITORY_TIMEOUT;
1801  break;
1802  case SNAT_SESSION_TCP_ESTABLISHED:
1803  ses1->expire = now + SNAT_TCP_ESTABLISHED_TIMEOUT;
1804  break;
1805  }
1806 
1807  trace1:
1809  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1810  {
1811  snat_in2out_trace_t *t =
1812  vlib_add_trace (vm, node, b1, sizeof (*t));
1813  t->is_slow_path = 0;
1814  t->sw_if_index = sw_if_index1;
1815  t->next_index = next1;
1816  t->session_index = ~0;
1817  if (ses1)
1818  t->session_index = ses1 - dm1->sessions;
1819  }
1820 
1821  pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP;
1822 
1823  /* verify speculative enqueues, maybe switch current next frame */
1824  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1825  to_next, n_left_to_next,
1826  bi0, bi1, next0, next1);
1827  }
1828 
1829  while (n_left_from > 0 && n_left_to_next > 0)
1830  {
1831  u32 bi0;
1832  vlib_buffer_t * b0;
1833  u32 next0;
1834  u32 sw_if_index0;
1835  ip4_header_t * ip0;
1836  ip_csum_t sum0;
1837  ip4_address_t new_addr0, old_addr0;
1838  u16 old_port0, new_port0, lo_port0, i0;
1839  udp_header_t * udp0;
1840  tcp_header_t * tcp0;
1841  u32 proto0;
1842  snat_det_out_key_t key0;
1843  snat_det_map_t * dm0;
1844  snat_det_session_t * ses0 = 0;
1845 
1846  /* speculatively enqueue b0 to the current next frame */
1847  bi0 = from[0];
1848  to_next[0] = bi0;
1849  from += 1;
1850  to_next += 1;
1851  n_left_from -= 1;
1852  n_left_to_next -= 1;
1853 
1854  b0 = vlib_get_buffer (vm, bi0);
1855  next0 = SNAT_IN2OUT_NEXT_LOOKUP;
1856 
1857  ip0 = vlib_buffer_get_current (b0);
1858  udp0 = ip4_next_header (ip0);
1859  tcp0 = (tcp_header_t *) udp0;
1860 
1861  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1862 
1863  dm0 = snat_det_map_by_user(sm, &ip0->src_address);
1864  if (PREDICT_FALSE(!dm0))
1865  {
1866  clib_warning("no match for internal host %U",
1868  next0 = SNAT_IN2OUT_NEXT_DROP;
1869  b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
1870  goto trace00;
1871  }
1872 
1873  snat_det_forward(dm0, &ip0->src_address, &new_addr0, &lo_port0);
1874 
1875  ses0 = snat_det_find_ses_by_in(dm0, &ip0->src_address, tcp0->src);
1876  if (PREDICT_FALSE(!ses0))
1877  {
1878  key0.ext_host_addr = ip0->dst_address;
1879  key0.ext_host_port = tcp0->dst;
1880  for (i0 = 0; i0 < dm0->ports_per_host; i0++)
1881  {
1882  key0.out_port = clib_host_to_net_u16 (lo_port0 +
1883  ((i0 + clib_net_to_host_u16 (tcp0->src)) % dm0->ports_per_host));
1884 
1885  if (snat_det_get_ses_by_out (dm0, &ip0->src_address, key0.as_u64))
1886  continue;
1887 
1888  ses0 = snat_det_ses_create(dm0, &ip0->src_address, tcp0->src, &key0);
1889  break;
1890  }
1891  if (PREDICT_FALSE(!ses0))
1892  {
1893  next0 = SNAT_IN2OUT_NEXT_DROP;
1894  b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
1895  goto trace00;
1896  }
1897  }
1898 
1899  new_port0 = ses0->out.out_port;
1900  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1901 
1902  old_addr0.as_u32 = ip0->src_address.as_u32;
1903  ip0->src_address.as_u32 = new_addr0.as_u32;
1904  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
1905 
1906  sum0 = ip0->checksum;
1907  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1908  ip4_header_t,
1909  src_address /* changed member */);
1910  ip0->checksum = ip_csum_fold (sum0);
1911 
1912  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1913  {
1914  if (tcp0->flags & TCP_FLAG_SYN)
1915  ses0->state = SNAT_SESSION_TCP_SYN_SENT;
1916  else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
1917  ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
1918  else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
1919  ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
1920  else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
1921  snat_det_ses_close(dm0, ses0);
1922  else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
1923  ses0->state = SNAT_SESSION_TCP_LAST_ACK;
1924  else if (tcp0->flags == 0 && ses0->state == SNAT_SESSION_UNKNOWN)
1925  ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
1926 
1927  old_port0 = tcp0->src;
1928  tcp0->src = new_port0;
1929 
1930  sum0 = tcp0->checksum;
1931  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1932  ip4_header_t,
1933  dst_address /* changed member */);
1934  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1935  ip4_header_t /* cheat */,
1936  length /* changed member */);
1937  tcp0->checksum = ip_csum_fold(sum0);
1938  }
1939  else
1940  {
1941  ses0->state = SNAT_SESSION_UDP_ACTIVE;
1942  old_port0 = udp0->src_port;
1943  udp0->src_port = new_port0;
1944  udp0->checksum = 0;
1945  }
1946 
1947  switch(ses0->state)
1948  {
1949  case SNAT_SESSION_UDP_ACTIVE:
1950  ses0->expire = now + SNAT_UDP_TIMEOUT;
1951  break;
1952  case SNAT_SESSION_TCP_SYN_SENT:
1953  case SNAT_SESSION_TCP_FIN_WAIT:
1954  case SNAT_SESSION_TCP_CLOSE_WAIT:
1955  case SNAT_SESSION_TCP_LAST_ACK:
1956  ses0->expire = now + SNAT_TCP_TRANSITORY_TIMEOUT;
1957  break;
1958  case SNAT_SESSION_TCP_ESTABLISHED:
1959  ses0->expire = now + SNAT_TCP_ESTABLISHED_TIMEOUT;
1960  break;
1961  }
1962 
1963  trace00:
1965  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1966  {
1967  snat_in2out_trace_t *t =
1968  vlib_add_trace (vm, node, b0, sizeof (*t));
1969  t->is_slow_path = 0;
1970  t->sw_if_index = sw_if_index0;
1971  t->next_index = next0;
1972  t->session_index = ~0;
1973  if (ses0)
1974  t->session_index = ses0 - dm0->sessions;
1975  }
1976 
1977  pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
1978 
1979  /* verify speculative enqueue, maybe switch current next frame */
1980  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1981  to_next, n_left_to_next,
1982  bi0, next0);
1983  }
1984 
1985  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1986  }
1987 
1989  SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
1990  pkts_processed);
1991  return frame->n_vectors;
1992 }
1993 
1995  .function = snat_det_in2out_node_fn,
1996  .name = "snat-det-in2out",
1997  .vector_size = sizeof (u32),
1998  .format_trace = format_snat_in2out_trace,
1999  .type = VLIB_NODE_TYPE_INTERNAL,
2000 
2001  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2002  .error_strings = snat_in2out_error_strings,
2003 
2004  .runtime_data_bytes = sizeof (snat_runtime_t),
2005 
2006  .n_next_nodes = 2,
2007 
2008  /* edit / add dispositions here */
2009  .next_nodes = {
2010  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2011  [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2012  },
2013 };
2014 
2016 
2017 /**********************/
2018 /*** worker handoff ***/
2019 /**********************/
2020 static uword
2022  vlib_node_runtime_t * node,
2023  vlib_frame_t * frame)
2024 {
2025  snat_main_t *sm = &snat_main;
2027  u32 n_left_from, *from, *to_next = 0;
2028  static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
2029  static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
2030  = 0;
2031  vlib_frame_queue_elt_t *hf = 0;
2032  vlib_frame_t *f = 0;
2033  int i;
2034  u32 n_left_to_next_worker = 0, *to_next_worker = 0;
2035  u32 next_worker_index = 0;
2036  u32 current_worker_index = ~0;
2037  u32 cpu_index = os_get_cpu_number ();
2038 
2039  ASSERT (vec_len (sm->workers));
2040 
2041  if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0))
2042  {
2043  vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
2044 
2045  vec_validate_init_empty (congested_handoff_queue_by_worker_index,
2046  sm->first_worker_index + sm->num_workers - 1,
2047  (vlib_frame_queue_t *) (~0));
2048  }
2049 
2050  from = vlib_frame_vector_args (frame);
2051  n_left_from = frame->n_vectors;
2052 
2053  while (n_left_from > 0)
2054  {
2055  u32 bi0;
2056  vlib_buffer_t *b0;
2057  u32 sw_if_index0;
2058  u32 rx_fib_index0;
2059  ip4_header_t * ip0;
2060  u8 do_handoff;
2061 
2062  bi0 = from[0];
2063  from += 1;
2064  n_left_from -= 1;
2065 
2066  b0 = vlib_get_buffer (vm, bi0);
2067 
2068  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
2069  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2070 
2071  ip0 = vlib_buffer_get_current (b0);
2072 
2073  next_worker_index = sm->worker_in2out_cb(ip0, rx_fib_index0);
2074 
2075  if (PREDICT_FALSE (next_worker_index != cpu_index))
2076  {
2077  do_handoff = 1;
2078 
2079  if (next_worker_index != current_worker_index)
2080  {
2081  if (hf)
2082  hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
2083 
2084  hf = vlib_get_worker_handoff_queue_elt (sm->fq_in2out_index,
2085  next_worker_index,
2086  handoff_queue_elt_by_worker_index);
2087 
2088  n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors;
2089  to_next_worker = &hf->buffer_index[hf->n_vectors];
2090  current_worker_index = next_worker_index;
2091  }
2092 
2093  /* enqueue to correct worker thread */
2094  to_next_worker[0] = bi0;
2095  to_next_worker++;
2096  n_left_to_next_worker--;
2097 
2098  if (n_left_to_next_worker == 0)
2099  {
2100  hf->n_vectors = VLIB_FRAME_SIZE;
2102  current_worker_index = ~0;
2103  handoff_queue_elt_by_worker_index[next_worker_index] = 0;
2104  hf = 0;
2105  }
2106  }
2107  else
2108  {
2109  do_handoff = 0;
2110  /* if this is 1st frame */
2111  if (!f)
2112  {
2113  f = vlib_get_frame_to_node (vm, sm->in2out_node_index);
2114  to_next = vlib_frame_vector_args (f);
2115  }
2116 
2117  to_next[0] = bi0;
2118  to_next += 1;
2119  f->n_vectors++;
2120  }
2121 
2123  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2124  {
2126  vlib_add_trace (vm, node, b0, sizeof (*t));
2127  t->next_worker_index = next_worker_index;
2128  t->do_handoff = do_handoff;
2129  }
2130  }
2131 
2132  if (f)
2133  vlib_put_frame_to_node (vm, sm->in2out_node_index, f);
2134 
2135  if (hf)
2136  hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
2137 
2138  /* Ship frames to the worker nodes */
2139  for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++)
2140  {
2141  if (handoff_queue_elt_by_worker_index[i])
2142  {
2143  hf = handoff_queue_elt_by_worker_index[i];
2144  /*
2145  * It works better to let the handoff node
2146  * rate-adapt, always ship the handoff queue element.
2147  */
2148  if (1 || hf->n_vectors == hf->last_n_vectors)
2149  {
2151  handoff_queue_elt_by_worker_index[i] = 0;
2152  }
2153  else
2154  hf->last_n_vectors = hf->n_vectors;
2155  }
2156  congested_handoff_queue_by_worker_index[i] =
2157  (vlib_frame_queue_t *) (~0);
2158  }
2159  hf = 0;
2160  current_worker_index = ~0;
2161  return frame->n_vectors;
2162 }
2163 
2165  .function = snat_in2out_worker_handoff_fn,
2166  .name = "snat-in2out-worker-handoff",
2167  .vector_size = sizeof (u32),
2169  .type = VLIB_NODE_TYPE_INTERNAL,
2170 
2171  .n_next_nodes = 1,
2172 
2173  .next_nodes = {
2174  [0] = "error-drop",
2175  },
2176 };
2177 
2179 
2180 static uword
2182  vlib_node_runtime_t * node,
2183  vlib_frame_t * frame)
2184 {
2185  u32 n_left_from, * from, * to_next;
2186  snat_in2out_next_t next_index;
2187  u32 pkts_processed = 0;
2188  snat_main_t * sm = &snat_main;
2189  u32 stats_node_index;
2190 
2191  stats_node_index = snat_in2out_fast_node.index;
2192 
2193  from = vlib_frame_vector_args (frame);
2194  n_left_from = frame->n_vectors;
2195  next_index = node->cached_next_index;
2196 
2197  while (n_left_from > 0)
2198  {
2199  u32 n_left_to_next;
2200 
2201  vlib_get_next_frame (vm, node, next_index,
2202  to_next, n_left_to_next);
2203 
2204  while (n_left_from > 0 && n_left_to_next > 0)
2205  {
2206  u32 bi0;
2207  vlib_buffer_t * b0;
2208  u32 next0;
2209  u32 sw_if_index0;
2210  ip4_header_t * ip0;
2211  ip_csum_t sum0;
2212  u32 new_addr0, old_addr0;
2213  u16 old_port0, new_port0;
2214  udp_header_t * udp0;
2215  tcp_header_t * tcp0;
2216  icmp46_header_t * icmp0;
2217  snat_session_key_t key0, sm0;
2218  u32 proto0;
2219  u32 rx_fib_index0;
2220 
2221  /* speculatively enqueue b0 to the current next frame */
2222  bi0 = from[0];
2223  to_next[0] = bi0;
2224  from += 1;
2225  to_next += 1;
2226  n_left_from -= 1;
2227  n_left_to_next -= 1;
2228 
2229  b0 = vlib_get_buffer (vm, bi0);
2230  next0 = SNAT_IN2OUT_NEXT_LOOKUP;
2231 
2232  ip0 = vlib_buffer_get_current (b0);
2233  udp0 = ip4_next_header (ip0);
2234  tcp0 = (tcp_header_t *) udp0;
2235  icmp0 = (icmp46_header_t *) udp0;
2236 
2237  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2238  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2239 
2240  proto0 = ip_proto_to_snat_proto (ip0->protocol);
2241 
2242  if (PREDICT_FALSE (proto0 == ~0))
2243  goto trace0;
2244 
2245  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2246  {
2247  next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0,
2248  rx_fib_index0, node, next0, ~0, 0);
2249  goto trace0;
2250  }
2251 
2252  key0.addr = ip0->src_address;
2253  key0.port = udp0->src_port;
2254  key0.fib_index = rx_fib_index0;
2255 
2256  if (snat_static_mapping_match(sm, key0, &sm0, 0, 0))
2257  {
2258  b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
2259  next0= SNAT_IN2OUT_NEXT_DROP;
2260  goto trace0;
2261  }
2262 
2263  new_addr0 = sm0.addr.as_u32;
2264  new_port0 = sm0.port;
2265  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
2266  old_addr0 = ip0->src_address.as_u32;
2267  ip0->src_address.as_u32 = new_addr0;
2268 
2269  sum0 = ip0->checksum;
2270  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2271  ip4_header_t,
2272  src_address /* changed member */);
2273  ip0->checksum = ip_csum_fold (sum0);
2274 
2275  if (PREDICT_FALSE(new_port0 != udp0->dst_port))
2276  {
2277  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2278  {
2279  old_port0 = tcp0->src_port;
2280  tcp0->src_port = new_port0;
2281 
2282  sum0 = tcp0->checksum;
2283  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2284  ip4_header_t,
2285  dst_address /* changed member */);
2286  sum0 = ip_csum_update (sum0, old_port0, new_port0,
2287  ip4_header_t /* cheat */,
2288  length /* changed member */);
2289  tcp0->checksum = ip_csum_fold(sum0);
2290  }
2291  else
2292  {
2293  old_port0 = udp0->src_port;
2294  udp0->src_port = new_port0;
2295  udp0->checksum = 0;
2296  }
2297  }
2298  else
2299  {
2300  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2301  {
2302  sum0 = tcp0->checksum;
2303  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2304  ip4_header_t,
2305  dst_address /* changed member */);
2306  tcp0->checksum = ip_csum_fold(sum0);
2307  }
2308  }
2309 
2310  /* Hairpinning */
2311  snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0);
2312 
2313  trace0:
2315  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2316  {
2317  snat_in2out_trace_t *t =
2318  vlib_add_trace (vm, node, b0, sizeof (*t));
2319  t->sw_if_index = sw_if_index0;
2320  t->next_index = next0;
2321  }
2322 
2323  pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
2324 
2325  /* verify speculative enqueue, maybe switch current next frame */
2326  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2327  to_next, n_left_to_next,
2328  bi0, next0);
2329  }
2330 
2331  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2332  }
2333 
2334  vlib_node_increment_counter (vm, stats_node_index,
2335  SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
2336  pkts_processed);
2337  return frame->n_vectors;
2338 }
2339 
2340 
2342  .function = snat_in2out_fast_static_map_fn,
2343  .name = "snat-in2out-fast",
2344  .vector_size = sizeof (u32),
2345  .format_trace = format_snat_in2out_fast_trace,
2346  .type = VLIB_NODE_TYPE_INTERNAL,
2347 
2348  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2349  .error_strings = snat_in2out_error_strings,
2350 
2351  .runtime_data_bytes = sizeof (snat_runtime_t),
2352 
2353  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
2354 
2355  /* edit / add dispositions here */
2356  .next_nodes = {
2357  [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2358  [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2359  [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath",
2360  [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2361  },
2362 };
2363 
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:169
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:187
u32 sessions_per_user_list_head_index
Definition: snat.h:148
static u8 * format_snat_in2out_trace(u8 *s, va_list *args)
Definition: in2out.c:45
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
#define CLIB_UNUSED(x)
Definition: clib.h:79
snat_in2out_error_t
Definition: in2out.c:100
u16 ext_host_port
Definition: snat.h:57
#define SNAT_UDP_TIMEOUT
Definition: snat.h:32
static uword snat_in2out_slow_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out.c:1476
static void clib_dlist_init(dlist_elt_t *pool, u32 index)
Definition: dlist.h:36
u8 runtime_data[0]
Function dependent node-runtime data.
Definition: node.h:463
static snat_det_session_t * snat_det_find_ses_by_in(snat_det_map_t *dm, ip4_address_t *in_addr, u16 in_port)
Definition: snat_det.h:128
ip4_address_t src_address
Definition: ip4_packet.h:163
static u32 slow_path(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, u32 rx_fib_index0, snat_session_key_t *key0, snat_session_t **sessionp, vlib_node_runtime_t *node, u32 next0, u32 cpu_index)
Definition: in2out.c:208
static u8 * format_snat_in2out_fast_trace(u8 *s, va_list *args)
Definition: in2out.c:60
#define TCP_FLAG_SYN
Definition: fa_node.h:8
u16 fib_index
Definition: snat.h:83
#define PREDICT_TRUE(x)
Definition: clib.h:98
u32 nsessions
Definition: snat.h:149
int snat_alloc_outside_address_and_port(snat_main_t *sm, u32 fib_index, snat_session_key_t *k, u32 *address_indexp)
Definition: snat.c:1901
static int ip4_header_bytes(ip4_header_t *i)
Definition: ip4_packet.h:226
ip4_address_t * ip4_interface_first_address(ip4_main_t *im, u32 sw_if_index, ip_interface_address_t **result_ia)
Definition: ip4_forward.c:710
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:185
static char * snat_in2out_error_strings[]
Definition: in2out.c:107
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:459
static_always_inline u8 icmp_is_error_message(icmp46_header_t *icmp)
Definition: snat.h:427
static uword snat_in2out_worker_handoff_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out.c:2021
u32 nstaticsessions
Definition: snat.h:150
struct _vlib_node_registration vlib_node_registration_t
static uword snat_in2out_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_slow_path)
Definition: in2out.c:898
static void snat_det_forward(snat_det_map_t *dm, ip4_address_t *in_addr, ip4_address_t *out_addr, u16 *lo_port)
Definition: snat_det.h:74
uword ip_csum_t
Definition: ip_packet.h:90
snat_in2out_next_t
Definition: in2out.c:113
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
u32 fib_index
Definition: snat.h:147
void snat_ipfix_logging_nat44_ses_delete(u32 src_ip, u32 nat_src_ip, snat_protocol_t snat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session delete event.
u32 buffer_index[VLIB_FRAME_SIZE]
Definition: threads.h:82
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:418
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:100
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
struct _tcp_header tcp_header_t
VLIB_NODE_FUNCTION_MULTIARCH(snat_in2out_node, snat_in2out_fast_path_fn)
static void snat_hairpinning(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, udp_header_t *udp0, tcp_header_t *tcp0, u32 proto0)
Hairpinning.
Definition: in2out.c:776
u32 cached_sw_if_index
Definition: snat.h:356
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:211
format_function_t format_ip4_address
Definition: format.h:79
#define static_always_inline
Definition: clib.h:85
static uword ip4_header_checksum_is_valid(ip4_header_t *i)
Definition: ip4_packet.h:259
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:376
ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_checksum.c:43
vlib_node_registration_t snat_in2out_fast_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_fast_node)
Definition: in2out.c:88
ip4_address_t ext_host_addr
Definition: snat.h:56
ip4_address_t dst_address
Definition: ip4_packet.h:163
#define TCP_FLAG_ACK
Definition: fa_node.h:11
ip4_address_t addr
Definition: snat.h:146
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:164
static uword snat_det_in2out_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out.c:1512
Aggregrate type for a prefix.
Definition: fib_types.h:160
static u8 * format_snat_in2out_worker_handoff_trace(u8 *s, va_list *args)
Definition: in2out.c:72
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:232
vlib_node_registration_t snat_in2out_slowpath_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_slowpath_node)
Definition: in2out.c:87
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 cpu_index, snat_session_t **p_s0)
Definition: in2out.c:863
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:66
#define foreach_snat_in2out_error
Definition: in2out.c:92
#define SNAT_TCP_TRANSITORY_TIMEOUT
Definition: snat.h:33
#define hash_get(h, key)
Definition: hash.h:248
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:397
deterministic NAT definitions
snat_det_session_t * sessions
Definition: snat.h:179
u64 key
the key
Definition: bihash_8_8.h:35
u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 cpu_index, vlib_buffer_t *b0, snat_session_key_t *p_key, snat_session_key_t *p_value, u8 *p_dont_translate, void *d)
Get address and port values to be used for packet SNAT translation and create session if needed...
Definition: in2out.c:477
static void clib_dlist_addtail(dlist_elt_t *pool, u32 head_index, u32 new_index)
Definition: dlist.h:43
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:188
snat_main_t snat_main
Definition: jvpp_snat.h:39
static 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 cpu_index, void *d)
Definition: in2out.c:641
#define PREDICT_FALSE(x)
Definition: clib.h:97
static vlib_frame_queue_elt_t * vlib_get_worker_handoff_queue_elt(u32 frame_queue_index, u32 vlib_worker_index, vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index)
Definition: threads.h:450
#define TCP_FLAG_FIN
Definition: fa_node.h:7
#define VLIB_FRAME_SIZE
Definition: node.h:328
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:216
#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:350
static int snat_not_translate(snat_main_t *sm, snat_runtime_t *rt, u32 sw_if_index0, ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0)
Check if packet should be translated.
Definition: in2out.c:137
int snat_static_mapping_match(snat_main_t *sm, snat_session_key_t match, snat_session_key_t *mapping, u8 by_external, u8 *is_addr_only)
Match SNAT static mapping.
Definition: snat.c:1845
ip4_address_t addr
Definition: snat.h:81
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:113
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1115
u32 fib_entry_get_resolving_interface(fib_node_index_t entry_index)
Definition: fib_entry.c:1321
u64 value
the value
Definition: bihash_8_8.h:36
u16 n_vectors
Definition: node.h:344
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
vlib_main_t * vm
Definition: buffer.c:276
vlib_node_registration_t snat_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_node)
Definition: in2out.c:86
void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.c:431
#define clib_warning(format, args...)
Definition: error.h:59
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:85
static uword snat_in2out_fast_static_map_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out.c:2181
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:28
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:33
#define ARRAY_LEN(x)
Definition: clib.h:59
ip4_address_t addr
Definition: snat.h:42
static_always_inline snat_in2out_error_t icmp_get_key(ip4_header_t *ip0, snat_session_key_t *p_key0)
Definition: in2out.c:420
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:455
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
static snat_protocol_t ip_proto_to_snat_proto(u8 ip_proto)
Definition: snat.h:378
u64 as_u64
Definition: snat.h:72
ip4_address_t addr
Definition: snat.h:69
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
static void clib_dlist_remove(dlist_elt_t *pool, u32 index)
Definition: dlist.h:99
void snat_ipfix_logging_nat44_ses_create(u32 src_ip, u32 nat_src_ip, snat_protocol_t snat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session create event.
static snat_det_session_t * snat_det_get_ses_by_out(snat_det_map_t *dm, ip4_address_t *in_addr, u64 out_key)
Definition: snat_det.h:111
u32 value
Definition: dlist.h:32
u64 uword
Definition: types.h:112
vlib_node_registration_t snat_det_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_det_in2out_node)
Definition: in2out.c:90
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
#define vec_elt(v, i)
Get vector value at index i.
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:29
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
static snat_det_map_t * snat_det_map_by_user(snat_main_t *sm, ip4_address_t *user_addr)
Definition: snat_det.h:44
u16 ports_per_host
Definition: snat.h:176
vlib_node_registration_t snat_in2out_worker_handoff_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_worker_handoff_node)
Definition: in2out.c:89
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:139
snat_det_out_key_t out
Definition: snat.h:165
u32 fib_index
Definition: snat.h:70
void snat_free_outside_address_and_port(snat_main_t *sm, snat_session_key_t *k, u32 address_index)
Definition: snat.c:1804
static void vlib_put_frame_queue_elt(vlib_frame_queue_elt_t *hf)
Definition: threads.h:380
static uword snat_in2out_fast_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: in2out.c:1443
#define vnet_buffer(b)
Definition: buffer.h:294
static void snat_det_ses_close(snat_det_map_t *dm, snat_det_session_t *ses)
Definition: snat_det.h:173
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
u8 data[0]
Packet data.
Definition: buffer.h:152
u16 flags
Copy of main node flags.
Definition: node.h:449
u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 cpu_index, vlib_buffer_t *b0, snat_session_key_t *p_key, snat_session_key_t *p_value, u8 *p_dont_translate, void *d)
Get address and port values to be used for packet SNAT translation.
Definition: in2out.c:571
#define SNAT_SESSION_FLAG_STATIC_MAPPING
Definition: snat.h:118
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:196
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:485
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:74
static snat_det_session_t * snat_det_ses_create(snat_det_map_t *dm, ip4_address_t *in_addr, u16 in_port, snat_det_out_key_t *out)
Definition: snat_det.h:145
u32 cached_ip4_address
Definition: snat.h:357
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
#define snat_is_session_static(s)
Check if SNAT session is created from static mapping.
Definition: snat.h:364
#define SNAT_TCP_ESTABLISHED_TIMEOUT
Definition: snat.h:34
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:145
Definition: defs.h:46
static u32 clib_dlist_remove_head(dlist_elt_t *pool, u32 head_index)
Definition: dlist.h:117