FD.io VPP  v17.04-9-g99c0734
Vector Packet Processing
out2in.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #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/udp/udp.h>
23 #include <vnet/ethernet/ethernet.h>
24 #include <vnet/fib/ip4_fib.h>
25 #include <snat/snat.h>
27 #include <snat/snat_det.h>
28 
29 #include <vppinfra/hash.h>
30 #include <vppinfra/error.h>
31 #include <vppinfra/elog.h>
32 
33 typedef struct {
38 
39 typedef struct {
43 
44 /* packet trace format function */
45 static u8 * format_snat_out2in_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_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *);
50 
51  s = format (s, "SNAT_OUT2IN: sw_if_index %d, next index %d, session index %d",
53  return s;
54 }
55 
56 static u8 * format_snat_out2in_fast_trace (u8 * s, va_list * args)
57 {
58  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
59  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
60  snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *);
61 
62  s = format (s, "SNAT_OUT2IN_FAST: sw_if_index %d, next index %d",
63  t->sw_if_index, t->next_index);
64  return s;
65 }
66 
67 static u8 * format_snat_out2in_worker_handoff_trace (u8 * s, va_list * args)
68 {
69  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
70  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
72  va_arg (*args, snat_out2in_worker_handoff_trace_t *);
73  char * m;
74 
75  m = t->do_handoff ? "next worker" : "same worker";
76  s = format (s, "SNAT_OUT2IN_WORKER_HANDOFF: %s %d", m, t->next_worker_index);
77 
78  return s;
79 }
80 
85 
86 #define foreach_snat_out2in_error \
87 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
88 _(OUT2IN_PACKETS, "Good out2in packets processed") \
89 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
90 _(NO_TRANSLATION, "No translation")
91 
92 typedef enum {
93 #define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
95 #undef _
98 
99 static char * snat_out2in_error_strings[] = {
100 #define _(sym,string) string,
102 #undef _
103 };
104 
105 typedef enum {
111 
112 /**
113  * @brief Create session for static mapping.
114  *
115  * Create NAT session initiated by host from external network with static
116  * mapping.
117  *
118  * @param sm SNAT main.
119  * @param b0 Vlib buffer.
120  * @param in2out In2out SNAT session key.
121  * @param out2in Out2in SNAT session key.
122  * @param node Vlib node.
123  *
124  * @returns SNAT session if successfully created otherwise 0.
125  */
126 static inline snat_session_t *
128  vlib_buffer_t *b0,
129  snat_session_key_t in2out,
130  snat_session_key_t out2in,
131  vlib_node_runtime_t * node,
132  u32 cpu_index)
133 {
134  snat_user_t *u;
135  snat_user_key_t user_key;
136  snat_session_t *s;
137  clib_bihash_kv_8_8_t kv0, value0;
138  dlist_elt_t * per_user_translation_list_elt;
139  dlist_elt_t * per_user_list_head_elt;
140 
141  user_key.addr = in2out.addr;
142  user_key.fib_index = in2out.fib_index;
143  kv0.key = user_key.as_u64;
144 
145  /* Ever heard of the "user" = inside ip4 address before? */
146  if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0))
147  {
148  /* no, make a new one */
149  pool_get (sm->per_thread_data[cpu_index].users, u);
150  memset (u, 0, sizeof (*u));
151  u->addr = in2out.addr;
152  u->fib_index = in2out.fib_index;
153 
154  pool_get (sm->per_thread_data[cpu_index].list_pool,
155  per_user_list_head_elt);
156 
157  u->sessions_per_user_list_head_index = per_user_list_head_elt -
158  sm->per_thread_data[cpu_index].list_pool;
159 
160  clib_dlist_init (sm->per_thread_data[cpu_index].list_pool,
162 
163  kv0.value = u - sm->per_thread_data[cpu_index].users;
164 
165  /* add user */
166  clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */);
167 
168  /* add non-traslated packets worker lookup */
169  kv0.value = cpu_index;
170  clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1);
171  }
172  else
173  {
174  u = pool_elt_at_index (sm->per_thread_data[cpu_index].users,
175  value0.value);
176  }
177 
178  pool_get (sm->per_thread_data[cpu_index].sessions, s);
179  memset (s, 0, sizeof (*s));
180 
181  s->outside_address_index = ~0;
183  u->nstaticsessions++;
184 
185  /* Create list elts */
186  pool_get (sm->per_thread_data[cpu_index].list_pool,
187  per_user_translation_list_elt);
188  clib_dlist_init (sm->per_thread_data[cpu_index].list_pool,
189  per_user_translation_list_elt -
190  sm->per_thread_data[cpu_index].list_pool);
191 
192  per_user_translation_list_elt->value =
193  s - sm->per_thread_data[cpu_index].sessions;
194  s->per_user_index =
195  per_user_translation_list_elt - sm->per_thread_data[cpu_index].list_pool;
196  s->per_user_list_head_index = u->sessions_per_user_list_head_index;
197 
198  clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
199  s->per_user_list_head_index,
200  per_user_translation_list_elt -
201  sm->per_thread_data[cpu_index].list_pool);
202 
203  s->in2out = in2out;
204  s->out2in = out2in;
205  s->in2out.protocol = out2in.protocol;
206 
207  /* Add to translation hashes */
208  kv0.key = s->in2out.as_u64;
209  kv0.value = s - sm->per_thread_data[cpu_index].sessions;
210  if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */))
211  clib_warning ("in2out key add failed");
212 
213  kv0.key = s->out2in.as_u64;
214  kv0.value = s - sm->per_thread_data[cpu_index].sessions;
215 
216  if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */))
217  clib_warning ("out2in key add failed");
218 
219  /* log NAT event */
220  snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32,
221  s->out2in.addr.as_u32,
222  s->in2out.protocol,
223  s->in2out.port,
224  s->out2in.port,
225  s->in2out.fib_index);
226  return s;
227 }
228 
231  snat_session_key_t *p_key0)
232 {
233  icmp46_header_t *icmp0;
234  snat_session_key_t key0;
235  icmp_echo_header_t *echo0, *inner_echo0 = 0;
236  ip4_header_t *inner_ip0;
237  void *l4_header = 0;
238  icmp46_header_t *inner_icmp0;
239 
240  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
241  echo0 = (icmp_echo_header_t *)(icmp0+1);
242 
243  if (!icmp_is_error_message (icmp0))
244  {
245  key0.protocol = SNAT_PROTOCOL_ICMP;
246  key0.addr = ip0->dst_address;
247  key0.port = echo0->identifier;
248  }
249  else
250  {
251  inner_ip0 = (ip4_header_t *)(echo0+1);
252  l4_header = ip4_next_header (inner_ip0);
253  key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
254  key0.addr = inner_ip0->src_address;
255  switch (key0.protocol)
256  {
257  case SNAT_PROTOCOL_ICMP:
258  inner_icmp0 = (icmp46_header_t*)l4_header;
259  inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
260  key0.port = inner_echo0->identifier;
261  break;
262  case SNAT_PROTOCOL_UDP:
263  case SNAT_PROTOCOL_TCP:
264  key0.port = ((tcp_udp_header_t*)l4_header)->src_port;
265  break;
266  default:
267  return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
268  }
269  }
270  *p_key0 = key0;
271  return -1; /* success */
272 }
273 
276  u32 ip4_addr)
277 {
279  ip4_address_t * first_int_addr;
280 
281  if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0))
282  {
283  first_int_addr =
284  ip4_interface_first_address (sm->ip4_main, sw_if_index0,
285  0 /* just want the address */);
286  rt->cached_sw_if_index = sw_if_index0;
287  if (first_int_addr)
288  rt->cached_ip4_address = first_int_addr->as_u32;
289  else
290  rt->cached_ip4_address = 0;
291  }
292 
293  if (PREDICT_FALSE(ip4_addr == rt->cached_ip4_address))
294  return 1;
295  else
296  return 0;
297 }
298 
299 /**
300  * Get address and port values to be used for packet SNAT translation
301  * and create session if needed
302  *
303  * @param[in,out] sm SNAT main
304  * @param[in,out] node SNAT node runtime
305  * @param[in] cpu_index CPU index
306  * @param[in,out] b0 buffer containing packet to be translated
307  * @param[out] p_key address and port before NAT translation
308  * @param[out] p_value address and port after NAT translation
309  * @param[out] p_dont_translate if packet should not be translated
310  * @param d optional parameter
311  */
313  u32 cpu_index, vlib_buffer_t *b0,
314  snat_session_key_t *p_key,
315  snat_session_key_t *p_value,
316  u8 *p_dont_translate, void *d)
317 {
318  ip4_header_t *ip0;
319  icmp46_header_t *icmp0;
320  u32 sw_if_index0;
321  u32 rx_fib_index0;
322  snat_session_key_t key0;
323  snat_session_key_t sm0;
324  snat_session_t *s0 = 0;
325  u8 dont_translate = 0;
326  clib_bihash_kv_8_8_t kv0, value0;
327  u8 is_addr_only;
328  u32 next0 = ~0;
329  int err;
330 
331  ip0 = vlib_buffer_get_current (b0);
332  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
333  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
334  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
335 
336  err = icmp_get_key (ip0, &key0);
337  if (err != -1)
338  {
339  b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
340  next0 = SNAT_OUT2IN_NEXT_DROP;
341  goto out;
342  }
343  key0.fib_index = rx_fib_index0;
344 
345  kv0.key = key0.as_u64;
346 
347  if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
348  {
349  /* Try to match static mapping by external address and port,
350  destination address and port in packet */
351  if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only))
352  {
353  /* Don't NAT packet aimed at the intfc address */
354  if (is_interface_addr(sm, node, sw_if_index0,
355  ip0->dst_address.as_u32))
356  {
357  dont_translate = 1;
358  goto out;
359  }
360  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
361  next0 = SNAT_OUT2IN_NEXT_DROP;
362  goto out;
363  }
364 
365  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
366  (icmp0->type != ICMP4_echo_request || !is_addr_only)))
367  {
368  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
369  next0 = SNAT_OUT2IN_NEXT_DROP;
370  goto out;
371  }
372 
373  /* Create session initiated by host from external network */
374  s0 = create_session_for_static_mapping(sm, b0, sm0, key0,
375  node, cpu_index);
376 
377  if (!s0)
378  {
379  next0 = SNAT_OUT2IN_NEXT_DROP;
380  goto out;
381  }
382  }
383  else
384  {
385  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
386  icmp0->type != ICMP4_echo_request &&
387  !icmp_is_error_message (icmp0)))
388  {
389  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
390  next0 = SNAT_OUT2IN_NEXT_DROP;
391  goto out;
392  }
393 
394  s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
395  value0.value);
396  }
397 
398 out:
399  *p_key = key0;
400  if (s0)
401  *p_value = s0->in2out;
402  *p_dont_translate = dont_translate;
403  if (d)
404  *(snat_session_t**)d = s0;
405  return next0;
406 }
407 
408 /**
409  * Get address and port values to be used for packet SNAT translation
410  *
411  * @param[in] sm SNAT main
412  * @param[in,out] node SNAT node runtime
413  * @param[in] cpu_index CPU index
414  * @param[in,out] b0 buffer containing packet to be translated
415  * @param[out] p_key address and port before NAT translation
416  * @param[out] p_value address and port after NAT translation
417  * @param[out] p_dont_translate if packet should not be translated
418  * @param d optional parameter
419  */
421  u32 cpu_index, vlib_buffer_t *b0,
422  snat_session_key_t *p_key,
423  snat_session_key_t *p_value,
424  u8 *p_dont_translate, void *d)
425 {
426  ip4_header_t *ip0;
427  icmp46_header_t *icmp0;
428  u32 sw_if_index0;
429  u32 rx_fib_index0;
430  snat_session_key_t key0;
431  snat_session_key_t sm0;
432  u8 dont_translate = 0;
433  u8 is_addr_only;
434  u32 next0 = ~0;
435  int err;
436 
437  ip0 = vlib_buffer_get_current (b0);
438  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
439  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
440  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
441 
442  err = icmp_get_key (ip0, &key0);
443  if (err != -1)
444  {
445  b0->error = node->errors[err];
446  next0 = SNAT_OUT2IN_NEXT_DROP;
447  goto out2;
448  }
449  key0.fib_index = rx_fib_index0;
450 
451  if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only))
452  {
453  /* Don't NAT packet aimed at the intfc address */
454  if (is_interface_addr(sm, node, sw_if_index0, ip0->dst_address.as_u32))
455  {
456  dont_translate = 1;
457  goto out;
458  }
459  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
460  next0 = SNAT_OUT2IN_NEXT_DROP;
461  goto out;
462  }
463 
464  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
465  (icmp0->type != ICMP4_echo_request || !is_addr_only) &&
466  !icmp_is_error_message (icmp0)))
467  {
468  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
469  next0 = SNAT_OUT2IN_NEXT_DROP;
470  goto out;
471  }
472 
473 out:
474  *p_value = sm0;
475 out2:
476  *p_key = key0;
477  *p_dont_translate = dont_translate;
478  return next0;
479 }
480 
481 static inline u32 icmp_out2in (snat_main_t *sm,
482  vlib_buffer_t * b0,
483  ip4_header_t * ip0,
484  icmp46_header_t * icmp0,
485  u32 sw_if_index0,
486  u32 rx_fib_index0,
487  vlib_node_runtime_t * node,
488  u32 next0,
489  u32 cpu_index,
490  void *d)
491 {
492  snat_session_key_t key0, sm0;
493  icmp_echo_header_t *echo0, *inner_echo0 = 0;
494  ip4_header_t *inner_ip0 = 0;
495  void *l4_header = 0;
496  icmp46_header_t *inner_icmp0;
497  u8 dont_translate;
498  u32 new_addr0, old_addr0;
499  u16 old_id0, new_id0;
500  ip_csum_t sum0;
501  u16 checksum0;
502  u32 next0_tmp;
503 
504  echo0 = (icmp_echo_header_t *)(icmp0+1);
505 
506  next0_tmp = sm->icmp_match_out2in_cb(sm, node, cpu_index, b0,
507  &key0, &sm0, &dont_translate, d);
508  if (next0_tmp != ~0)
509  next0 = next0_tmp;
510  if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
511  goto out;
512 
513  sum0 = ip_incremental_checksum (0, icmp0,
514  ntohs(ip0->length) - ip4_header_bytes (ip0));
515  checksum0 = ~ip_csum_fold (sum0);
516  if (checksum0 != 0 && checksum0 != 0xffff)
517  {
518  next0 = SNAT_OUT2IN_NEXT_DROP;
519  goto out;
520  }
521 
522  old_addr0 = ip0->dst_address.as_u32;
523  new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32;
524  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
525 
526  sum0 = ip0->checksum;
527  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
528  dst_address /* changed member */);
529  ip0->checksum = ip_csum_fold (sum0);
530 
531  if (!icmp_is_error_message (icmp0))
532  {
533  new_id0 = sm0.port;
534  if (PREDICT_FALSE(new_id0 != echo0->identifier))
535  {
536  old_id0 = echo0->identifier;
537  new_id0 = sm0.port;
538  echo0->identifier = new_id0;
539 
540  sum0 = icmp0->checksum;
541  sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
542  identifier /* changed member */);
543  icmp0->checksum = ip_csum_fold (sum0);
544  }
545  }
546  else
547  {
548  inner_ip0 = (ip4_header_t *)(echo0+1);
549  l4_header = ip4_next_header (inner_ip0);
550 
551  if (!ip4_header_checksum_is_valid (inner_ip0))
552  {
553  next0 = SNAT_OUT2IN_NEXT_DROP;
554  goto out;
555  }
556 
557  old_addr0 = inner_ip0->src_address.as_u32;
558  inner_ip0->src_address = sm0.addr;
559  new_addr0 = inner_ip0->src_address.as_u32;
560 
561  sum0 = icmp0->checksum;
562  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
563  src_address /* changed member */);
564  icmp0->checksum = ip_csum_fold (sum0);
565 
566  switch (key0.protocol)
567  {
568  case SNAT_PROTOCOL_ICMP:
569  inner_icmp0 = (icmp46_header_t*)l4_header;
570  inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
571 
572  old_id0 = inner_echo0->identifier;
573  new_id0 = sm0.port;
574  inner_echo0->identifier = new_id0;
575 
576  sum0 = icmp0->checksum;
577  sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
578  identifier);
579  icmp0->checksum = ip_csum_fold (sum0);
580  break;
581  case SNAT_PROTOCOL_UDP:
582  case SNAT_PROTOCOL_TCP:
583  old_id0 = ((tcp_udp_header_t*)l4_header)->src_port;
584  new_id0 = sm0.port;
585  ((tcp_udp_header_t*)l4_header)->src_port = new_id0;
586 
587  sum0 = icmp0->checksum;
588  sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
589  src_port);
590  icmp0->checksum = ip_csum_fold (sum0);
591  break;
592  default:
593  ASSERT(0);
594  }
595  }
596 
597 out:
598  return next0;
599 }
600 
601 
603  vlib_buffer_t * b0,
604  ip4_header_t * ip0,
605  icmp46_header_t * icmp0,
606  u32 sw_if_index0,
607  u32 rx_fib_index0,
608  vlib_node_runtime_t * node,
609  u32 next0, f64 now,
610  u32 cpu_index,
611  snat_session_t ** p_s0)
612 {
613  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
614  next0, cpu_index, p_s0);
615  snat_session_t * s0 = *p_s0;
616  if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0))
617  {
618  /* Accounting */
619  s0->last_heard = now;
620  s0->total_pkts++;
621  s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0);
622  /* Per-user LRU list maintenance for dynamic translation */
623  if (!snat_is_session_static (s0))
624  {
625  clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool,
626  s0->per_user_index);
627  clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
628  s0->per_user_list_head_index,
629  s0->per_user_index);
630  }
631  }
632  return next0;
633 }
634 
635 static uword
637  vlib_node_runtime_t * node,
638  vlib_frame_t * frame)
639 {
640  u32 n_left_from, * from, * to_next;
641  snat_out2in_next_t next_index;
642  u32 pkts_processed = 0;
643  snat_main_t * sm = &snat_main;
644  f64 now = vlib_time_now (vm);
645  u32 cpu_index = os_get_cpu_number ();
646 
647  from = vlib_frame_vector_args (frame);
648  n_left_from = frame->n_vectors;
649  next_index = node->cached_next_index;
650 
651  while (n_left_from > 0)
652  {
653  u32 n_left_to_next;
654 
655  vlib_get_next_frame (vm, node, next_index,
656  to_next, n_left_to_next);
657 
658  while (n_left_from >= 4 && n_left_to_next >= 2)
659  {
660  u32 bi0, bi1;
661  vlib_buffer_t * b0, * b1;
664  u32 sw_if_index0, sw_if_index1;
665  ip4_header_t * ip0, *ip1;
666  ip_csum_t sum0, sum1;
667  u32 new_addr0, old_addr0;
668  u16 new_port0, old_port0;
669  u32 new_addr1, old_addr1;
670  u16 new_port1, old_port1;
671  udp_header_t * udp0, * udp1;
672  tcp_header_t * tcp0, * tcp1;
673  icmp46_header_t * icmp0, * icmp1;
674  snat_session_key_t key0, key1, sm0, sm1;
675  u32 rx_fib_index0, rx_fib_index1;
676  u32 proto0, proto1;
677  snat_session_t * s0 = 0, * s1 = 0;
678  clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
679 
680  /* Prefetch next iteration. */
681  {
682  vlib_buffer_t * p2, * p3;
683 
684  p2 = vlib_get_buffer (vm, from[2]);
685  p3 = vlib_get_buffer (vm, from[3]);
686 
687  vlib_prefetch_buffer_header (p2, LOAD);
688  vlib_prefetch_buffer_header (p3, LOAD);
689 
692  }
693 
694  /* speculatively enqueue b0 and b1 to the current next frame */
695  to_next[0] = bi0 = from[0];
696  to_next[1] = bi1 = from[1];
697  from += 2;
698  to_next += 2;
699  n_left_from -= 2;
700  n_left_to_next -= 2;
701 
702  b0 = vlib_get_buffer (vm, bi0);
703  b1 = vlib_get_buffer (vm, bi1);
704 
705  ip0 = vlib_buffer_get_current (b0);
706  udp0 = ip4_next_header (ip0);
707  tcp0 = (tcp_header_t *) udp0;
708  icmp0 = (icmp46_header_t *) udp0;
709 
710  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
711  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
712  sw_if_index0);
713 
714  if (PREDICT_FALSE(ip0->ttl == 1))
715  {
716  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
717  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
718  ICMP4_time_exceeded_ttl_exceeded_in_transit,
719  0);
721  goto trace0;
722  }
723 
724  proto0 = ip_proto_to_snat_proto (ip0->protocol);
725 
726  if (PREDICT_FALSE (proto0 == ~0))
727  goto trace0;
728 
729  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
730  {
731  next0 = icmp_out2in_slow_path
732  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
733  next0, now, cpu_index, &s0);
734  goto trace0;
735  }
736 
737  key0.addr = ip0->dst_address;
738  key0.port = udp0->dst_port;
739  key0.protocol = proto0;
740  key0.fib_index = rx_fib_index0;
741 
742  kv0.key = key0.as_u64;
743 
744  if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
745  {
746  /* Try to match static mapping by external address and port,
747  destination address and port in packet */
748  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0))
749  {
750  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
751  /*
752  * Send DHCP packets to the ipv4 stack, or we won't
753  * be able to use dhcp client on the outside interface
754  */
755  if (proto0 != SNAT_PROTOCOL_UDP
756  || (udp0->dst_port
757  != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
758  next0 = SNAT_OUT2IN_NEXT_DROP;
759  goto trace0;
760  }
761 
762  /* Create session initiated by host from external network */
763  s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
764  cpu_index);
765  if (!s0)
766  {
767  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
768  next0 = SNAT_OUT2IN_NEXT_DROP;
769  goto trace0;
770  }
771  }
772  else
773  s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
774  value0.value);
775 
776  old_addr0 = ip0->dst_address.as_u32;
777  ip0->dst_address = s0->in2out.addr;
778  new_addr0 = ip0->dst_address.as_u32;
779  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
780 
781  sum0 = ip0->checksum;
782  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
783  ip4_header_t,
784  dst_address /* changed member */);
785  ip0->checksum = ip_csum_fold (sum0);
786 
787  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
788  {
789  old_port0 = tcp0->dst_port;
790  tcp0->dst_port = s0->in2out.port;
791  new_port0 = tcp0->dst_port;
792 
793  sum0 = tcp0->checksum;
794  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
795  ip4_header_t,
796  dst_address /* changed member */);
797 
798  sum0 = ip_csum_update (sum0, old_port0, new_port0,
799  ip4_header_t /* cheat */,
800  length /* changed member */);
801  tcp0->checksum = ip_csum_fold(sum0);
802  }
803  else
804  {
805  old_port0 = udp0->dst_port;
806  udp0->dst_port = s0->in2out.port;
807  udp0->checksum = 0;
808  }
809 
810  /* Accounting */
811  s0->last_heard = now;
812  s0->total_pkts++;
813  s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
814  /* Per-user LRU list maintenance for dynamic translation */
815  if (!snat_is_session_static (s0))
816  {
817  clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool,
818  s0->per_user_index);
819  clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
820  s0->per_user_list_head_index,
821  s0->per_user_index);
822  }
823  trace0:
824 
826  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
827  {
828  snat_out2in_trace_t *t =
829  vlib_add_trace (vm, node, b0, sizeof (*t));
830  t->sw_if_index = sw_if_index0;
831  t->next_index = next0;
832  t->session_index = ~0;
833  if (s0)
834  t->session_index = s0 - sm->per_thread_data[cpu_index].sessions;
835  }
836 
837  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
838 
839 
840  ip1 = vlib_buffer_get_current (b1);
841  udp1 = ip4_next_header (ip1);
842  tcp1 = (tcp_header_t *) udp1;
843  icmp1 = (icmp46_header_t *) udp1;
844 
845  sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
846  rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
847  sw_if_index1);
848 
849  if (PREDICT_FALSE(ip1->ttl == 1))
850  {
851  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
852  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
853  ICMP4_time_exceeded_ttl_exceeded_in_transit,
854  0);
856  goto trace1;
857  }
858 
859  proto1 = ip_proto_to_snat_proto (ip1->protocol);
860 
861  if (PREDICT_FALSE (proto1 == ~0))
862  goto trace1;
863 
864  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
865  {
866  next1 = icmp_out2in_slow_path
867  (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
868  next1, now, cpu_index, &s1);
869  goto trace1;
870  }
871 
872  key1.addr = ip1->dst_address;
873  key1.port = udp1->dst_port;
874  key1.protocol = proto1;
875  key1.fib_index = rx_fib_index1;
876 
877  kv1.key = key1.as_u64;
878 
879  if (clib_bihash_search_8_8 (&sm->out2in, &kv1, &value1))
880  {
881  /* Try to match static mapping by external address and port,
882  destination address and port in packet */
883  if (snat_static_mapping_match(sm, key1, &sm1, 1, 0))
884  {
885  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
886  /*
887  * Send DHCP packets to the ipv4 stack, or we won't
888  * be able to use dhcp client on the outside interface
889  */
890  if (proto1 != SNAT_PROTOCOL_UDP
891  || (udp1->dst_port
892  != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
893  next1 = SNAT_OUT2IN_NEXT_DROP;
894  goto trace1;
895  }
896 
897  /* Create session initiated by host from external network */
898  s1 = create_session_for_static_mapping(sm, b1, sm1, key1, node,
899  cpu_index);
900  if (!s1)
901  {
902  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
903  next1 = SNAT_OUT2IN_NEXT_DROP;
904  goto trace1;
905  }
906  }
907  else
908  s1 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
909  value1.value);
910 
911  old_addr1 = ip1->dst_address.as_u32;
912  ip1->dst_address = s1->in2out.addr;
913  new_addr1 = ip1->dst_address.as_u32;
914  vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
915 
916  sum1 = ip1->checksum;
917  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
918  ip4_header_t,
919  dst_address /* changed member */);
920  ip1->checksum = ip_csum_fold (sum1);
921 
922  if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
923  {
924  old_port1 = tcp1->dst_port;
925  tcp1->dst_port = s1->in2out.port;
926  new_port1 = tcp1->dst_port;
927 
928  sum1 = tcp1->checksum;
929  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
930  ip4_header_t,
931  dst_address /* changed member */);
932 
933  sum1 = ip_csum_update (sum1, old_port1, new_port1,
934  ip4_header_t /* cheat */,
935  length /* changed member */);
936  tcp1->checksum = ip_csum_fold(sum1);
937  }
938  else
939  {
940  old_port1 = udp1->dst_port;
941  udp1->dst_port = s1->in2out.port;
942  udp1->checksum = 0;
943  }
944 
945  /* Accounting */
946  s1->last_heard = now;
947  s1->total_pkts++;
948  s1->total_bytes += vlib_buffer_length_in_chain (vm, b1);
949  /* Per-user LRU list maintenance for dynamic translation */
950  if (!snat_is_session_static (s1))
951  {
952  clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool,
953  s1->per_user_index);
954  clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
955  s1->per_user_list_head_index,
956  s1->per_user_index);
957  }
958  trace1:
959 
961  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
962  {
963  snat_out2in_trace_t *t =
964  vlib_add_trace (vm, node, b1, sizeof (*t));
965  t->sw_if_index = sw_if_index1;
966  t->next_index = next1;
967  t->session_index = ~0;
968  if (s1)
969  t->session_index = s1 - sm->per_thread_data[cpu_index].sessions;
970  }
971 
972  pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
973 
974  /* verify speculative enqueues, maybe switch current next frame */
975  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
976  to_next, n_left_to_next,
977  bi0, bi1, next0, next1);
978  }
979 
980  while (n_left_from > 0 && n_left_to_next > 0)
981  {
982  u32 bi0;
983  vlib_buffer_t * b0;
985  u32 sw_if_index0;
986  ip4_header_t * ip0;
987  ip_csum_t sum0;
988  u32 new_addr0, old_addr0;
989  u16 new_port0, old_port0;
990  udp_header_t * udp0;
991  tcp_header_t * tcp0;
992  icmp46_header_t * icmp0;
993  snat_session_key_t key0, sm0;
994  u32 rx_fib_index0;
995  u32 proto0;
996  snat_session_t * s0 = 0;
997  clib_bihash_kv_8_8_t kv0, value0;
998 
999  /* speculatively enqueue b0 to the current next frame */
1000  bi0 = from[0];
1001  to_next[0] = bi0;
1002  from += 1;
1003  to_next += 1;
1004  n_left_from -= 1;
1005  n_left_to_next -= 1;
1006 
1007  b0 = vlib_get_buffer (vm, bi0);
1008 
1009  ip0 = vlib_buffer_get_current (b0);
1010  udp0 = ip4_next_header (ip0);
1011  tcp0 = (tcp_header_t *) udp0;
1012  icmp0 = (icmp46_header_t *) udp0;
1013 
1014  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1015  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1016  sw_if_index0);
1017 
1018  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1019 
1020  if (PREDICT_FALSE (proto0 == ~0))
1021  goto trace00;
1022 
1023  if (PREDICT_FALSE(ip0->ttl == 1))
1024  {
1025  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1026  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1027  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1028  0);
1030  goto trace00;
1031  }
1032 
1033  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1034  {
1035  next0 = icmp_out2in_slow_path
1036  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1037  next0, now, cpu_index, &s0);
1038  goto trace00;
1039  }
1040 
1041  key0.addr = ip0->dst_address;
1042  key0.port = udp0->dst_port;
1043  key0.protocol = proto0;
1044  key0.fib_index = rx_fib_index0;
1045 
1046  kv0.key = key0.as_u64;
1047 
1048  if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
1049  {
1050  /* Try to match static mapping by external address and port,
1051  destination address and port in packet */
1052  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0))
1053  {
1054  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1055  /*
1056  * Send DHCP packets to the ipv4 stack, or we won't
1057  * be able to use dhcp client on the outside interface
1058  */
1059  if (proto0 != SNAT_PROTOCOL_UDP
1060  || (udp0->dst_port
1061  != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
1062 
1063  next0 = SNAT_OUT2IN_NEXT_DROP;
1064  goto trace00;
1065  }
1066 
1067  /* Create session initiated by host from external network */
1068  s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1069  cpu_index);
1070  if (!s0)
1071  {
1072  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1073  next0 = SNAT_OUT2IN_NEXT_DROP;
1074  goto trace00;
1075  }
1076  }
1077  else
1078  s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
1079  value0.value);
1080 
1081  old_addr0 = ip0->dst_address.as_u32;
1082  ip0->dst_address = s0->in2out.addr;
1083  new_addr0 = ip0->dst_address.as_u32;
1084  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1085 
1086  sum0 = ip0->checksum;
1087  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1088  ip4_header_t,
1089  dst_address /* changed member */);
1090  ip0->checksum = ip_csum_fold (sum0);
1091 
1092  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1093  {
1094  old_port0 = tcp0->dst_port;
1095  tcp0->dst_port = s0->in2out.port;
1096  new_port0 = tcp0->dst_port;
1097 
1098  sum0 = tcp0->checksum;
1099  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1100  ip4_header_t,
1101  dst_address /* changed member */);
1102 
1103  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1104  ip4_header_t /* cheat */,
1105  length /* changed member */);
1106  tcp0->checksum = ip_csum_fold(sum0);
1107  }
1108  else
1109  {
1110  old_port0 = udp0->dst_port;
1111  udp0->dst_port = s0->in2out.port;
1112  udp0->checksum = 0;
1113  }
1114 
1115  /* Accounting */
1116  s0->last_heard = now;
1117  s0->total_pkts++;
1118  s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1119  /* Per-user LRU list maintenance for dynamic translation */
1120  if (!snat_is_session_static (s0))
1121  {
1122  clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool,
1123  s0->per_user_index);
1124  clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
1125  s0->per_user_list_head_index,
1126  s0->per_user_index);
1127  }
1128  trace00:
1129 
1131  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1132  {
1133  snat_out2in_trace_t *t =
1134  vlib_add_trace (vm, node, b0, sizeof (*t));
1135  t->sw_if_index = sw_if_index0;
1136  t->next_index = next0;
1137  t->session_index = ~0;
1138  if (s0)
1139  t->session_index = s0 - sm->per_thread_data[cpu_index].sessions;
1140  }
1141 
1142  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1143 
1144  /* verify speculative enqueue, maybe switch current next frame */
1145  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1146  to_next, n_left_to_next,
1147  bi0, next0);
1148  }
1149 
1150  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1151  }
1152 
1154  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1155  pkts_processed);
1156  return frame->n_vectors;
1157 }
1158 
1160  .function = snat_out2in_node_fn,
1161  .name = "snat-out2in",
1162  .vector_size = sizeof (u32),
1163  .format_trace = format_snat_out2in_trace,
1164  .type = VLIB_NODE_TYPE_INTERNAL,
1165 
1166  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1167  .error_strings = snat_out2in_error_strings,
1168 
1169  .runtime_data_bytes = sizeof (snat_runtime_t),
1170 
1171  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1172 
1173  /* edit / add dispositions here */
1174  .next_nodes = {
1175  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1176  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1177  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1178  },
1179 };
1181 
1182 /**************************/
1183 /*** deterministic mode ***/
1184 /**************************/
1185 static uword
1187  vlib_node_runtime_t * node,
1188  vlib_frame_t * frame)
1189 {
1190  u32 n_left_from, * from, * to_next;
1191  snat_out2in_next_t next_index;
1192  u32 pkts_processed = 0;
1193  snat_main_t * sm = &snat_main;
1194 
1195  from = vlib_frame_vector_args (frame);
1196  n_left_from = frame->n_vectors;
1197  next_index = node->cached_next_index;
1198 
1199  while (n_left_from > 0)
1200  {
1201  u32 n_left_to_next;
1202 
1203  vlib_get_next_frame (vm, node, next_index,
1204  to_next, n_left_to_next);
1205 
1206  while (n_left_from >= 4 && n_left_to_next >= 2)
1207  {
1208  u32 bi0, bi1;
1209  vlib_buffer_t * b0, * b1;
1210  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1211  u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
1212  u32 sw_if_index0, sw_if_index1;
1213  ip4_header_t * ip0, * ip1;
1214  ip_csum_t sum0, sum1;
1215  ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
1216  u16 new_port0, old_port0, old_port1, new_port1;
1217  udp_header_t * udp0, * udp1;
1218  tcp_header_t * tcp0, * tcp1;
1219  u32 proto0, proto1;
1220  snat_det_out_key_t key0, key1;
1221  snat_det_map_t * dm0, * dm1;
1222  snat_det_session_t * ses0 = 0, * ses1 = 0;
1223 
1224  /* Prefetch next iteration. */
1225  {
1226  vlib_buffer_t * p2, * p3;
1227 
1228  p2 = vlib_get_buffer (vm, from[2]);
1229  p3 = vlib_get_buffer (vm, from[3]);
1230 
1231  vlib_prefetch_buffer_header (p2, LOAD);
1232  vlib_prefetch_buffer_header (p3, LOAD);
1233 
1236  }
1237 
1238  /* speculatively enqueue b0 and b1 to the current next frame */
1239  to_next[0] = bi0 = from[0];
1240  to_next[1] = bi1 = from[1];
1241  from += 2;
1242  to_next += 2;
1243  n_left_from -= 2;
1244  n_left_to_next -= 2;
1245 
1246  b0 = vlib_get_buffer (vm, bi0);
1247  b1 = vlib_get_buffer (vm, bi1);
1248 
1249  ip0 = vlib_buffer_get_current (b0);
1250  udp0 = ip4_next_header (ip0);
1251  tcp0 = (tcp_header_t *) udp0;
1252 
1253  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1254 
1255  key0.ext_host_addr = ip0->src_address;
1256  key0.ext_host_port = tcp0->src;
1257  key0.out_port = tcp0->dst;
1258 
1259  dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
1260  if (PREDICT_FALSE(!dm0))
1261  {
1262  clib_warning("unknown dst address: %U",
1264  next0 = SNAT_OUT2IN_NEXT_DROP;
1265  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1266  goto trace0;
1267  }
1268 
1269  snat_det_reverse(dm0, &ip0->dst_address,
1270  clib_net_to_host_u16(tcp0->dst), &new_addr0);
1271 
1272  ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
1273  if (PREDICT_FALSE(!ses0))
1274  {
1275  clib_warning("no match src %U:%d dst %U:%d for user %U",
1277  clib_net_to_host_u16 (tcp0->src),
1279  clib_net_to_host_u16 (tcp0->dst),
1280  format_ip4_address, &new_addr0);
1281  next0 = SNAT_OUT2IN_NEXT_DROP;
1282  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1283  goto trace0;
1284  }
1285  new_port0 = ses0->in_port;
1286 
1287  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1288 
1289  old_addr0 = ip0->dst_address;
1290  ip0->dst_address = new_addr0;
1291  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
1292 
1293  sum0 = ip0->checksum;
1294  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1295  ip4_header_t,
1296  dst_address /* changed member */);
1297  ip0->checksum = ip_csum_fold (sum0);
1298 
1299  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1300  {
1301  if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
1302  ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
1303  else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
1304  snat_det_ses_close(dm0, ses0);
1305 
1306  old_port0 = tcp0->dst;
1307  tcp0->dst = new_port0;
1308 
1309  sum0 = tcp0->checksum;
1310  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1311  ip4_header_t,
1312  dst_address /* changed member */);
1313 
1314  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1315  ip4_header_t /* cheat */,
1316  length /* changed member */);
1317  tcp0->checksum = ip_csum_fold(sum0);
1318  }
1319  else
1320  {
1321  old_port0 = udp0->dst_port;
1322  udp0->dst_port = new_port0;
1323  udp0->checksum = 0;
1324  }
1325 
1326  trace0:
1327 
1329  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1330  {
1331  snat_out2in_trace_t *t =
1332  vlib_add_trace (vm, node, b0, sizeof (*t));
1333  t->sw_if_index = sw_if_index0;
1334  t->next_index = next0;
1335  t->session_index = ~0;
1336  if (ses0)
1337  t->session_index = ses0 - dm0->sessions;
1338  }
1339 
1340  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1341 
1342  b1 = vlib_get_buffer (vm, bi1);
1343 
1344  ip1 = vlib_buffer_get_current (b1);
1345  udp1 = ip4_next_header (ip1);
1346  tcp1 = (tcp_header_t *) udp1;
1347 
1348  sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1349 
1350  key1.ext_host_addr = ip1->src_address;
1351  key1.ext_host_port = tcp1->src;
1352  key1.out_port = tcp1->dst;
1353 
1354  dm1 = snat_det_map_by_out(sm, &ip1->dst_address);
1355  if (PREDICT_FALSE(!dm1))
1356  {
1357  clib_warning("unknown dst address: %U",
1359  next1 = SNAT_OUT2IN_NEXT_DROP;
1360  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1361  goto trace1;
1362  }
1363 
1364  snat_det_reverse(dm1, &ip1->dst_address,
1365  clib_net_to_host_u16(tcp1->dst), &new_addr1);
1366 
1367  ses1 = snat_det_get_ses_by_out (dm1, &new_addr1, key1.as_u64);
1368  if (PREDICT_FALSE(!ses1))
1369  {
1370  clib_warning("no match src %U:%d dst %U:%d for user %U",
1372  clib_net_to_host_u16 (tcp1->src),
1374  clib_net_to_host_u16 (tcp1->dst),
1375  format_ip4_address, &new_addr1);
1376  next1 = SNAT_OUT2IN_NEXT_DROP;
1377  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1378  goto trace1;
1379  }
1380  new_port1 = ses1->in_port;
1381 
1382  proto1 = ip_proto_to_snat_proto (ip1->protocol);
1383 
1384  old_addr1 = ip1->dst_address;
1385  ip1->dst_address = new_addr1;
1386  vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
1387 
1388  sum1 = ip1->checksum;
1389  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
1390  ip4_header_t,
1391  dst_address /* changed member */);
1392  ip1->checksum = ip_csum_fold (sum1);
1393 
1394  if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1395  {
1396  if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
1397  ses1->state = SNAT_SESSION_TCP_CLOSE_WAIT;
1398  else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_LAST_ACK)
1399  snat_det_ses_close(dm1, ses1);
1400 
1401  old_port1 = tcp1->dst;
1402  tcp1->dst = new_port1;
1403 
1404  sum1 = tcp1->checksum;
1405  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
1406  ip4_header_t,
1407  dst_address /* changed member */);
1408 
1409  sum1 = ip_csum_update (sum1, old_port1, new_port1,
1410  ip4_header_t /* cheat */,
1411  length /* changed member */);
1412  tcp1->checksum = ip_csum_fold(sum1);
1413  }
1414  else
1415  {
1416  old_port1 = udp1->dst_port;
1417  udp1->dst_port = new_port1;
1418  udp1->checksum = 0;
1419  }
1420 
1421  trace1:
1422 
1424  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1425  {
1426  snat_out2in_trace_t *t =
1427  vlib_add_trace (vm, node, b1, sizeof (*t));
1428  t->sw_if_index = sw_if_index1;
1429  t->next_index = next1;
1430  t->session_index = ~0;
1431  if (ses1)
1432  t->session_index = ses1 - dm1->sessions;
1433  }
1434 
1435  pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
1436 
1437  /* verify speculative enqueues, maybe switch current next frame */
1438  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1439  to_next, n_left_to_next,
1440  bi0, bi1, next0, next1);
1441  }
1442 
1443  while (n_left_from > 0 && n_left_to_next > 0)
1444  {
1445  u32 bi0;
1446  vlib_buffer_t * b0;
1447  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1448  u32 sw_if_index0;
1449  ip4_header_t * ip0;
1450  ip_csum_t sum0;
1451  ip4_address_t new_addr0, old_addr0;
1452  u16 new_port0, old_port0;
1453  udp_header_t * udp0;
1454  tcp_header_t * tcp0;
1455  u32 proto0;
1456  snat_det_out_key_t key0;
1457  snat_det_map_t * dm0;
1458  snat_det_session_t * ses0 = 0;
1459 
1460  /* speculatively enqueue b0 to the current next frame */
1461  bi0 = from[0];
1462  to_next[0] = bi0;
1463  from += 1;
1464  to_next += 1;
1465  n_left_from -= 1;
1466  n_left_to_next -= 1;
1467 
1468  b0 = vlib_get_buffer (vm, bi0);
1469 
1470  ip0 = vlib_buffer_get_current (b0);
1471  udp0 = ip4_next_header (ip0);
1472  tcp0 = (tcp_header_t *) udp0;
1473 
1474  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1475 
1476  key0.ext_host_addr = ip0->src_address;
1477  key0.ext_host_port = tcp0->src;
1478  key0.out_port = tcp0->dst;
1479 
1480  dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
1481  if (PREDICT_FALSE(!dm0))
1482  {
1483  clib_warning("unknown dst address: %U",
1485  next0 = SNAT_OUT2IN_NEXT_DROP;
1486  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1487  goto trace00;
1488  }
1489 
1490  snat_det_reverse(dm0, &ip0->dst_address,
1491  clib_net_to_host_u16(tcp0->dst), &new_addr0);
1492 
1493  ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
1494  if (PREDICT_FALSE(!ses0))
1495  {
1496  clib_warning("no match src %U:%d dst %U:%d for user %U",
1498  clib_net_to_host_u16 (tcp0->src),
1500  clib_net_to_host_u16 (tcp0->dst),
1501  format_ip4_address, &new_addr0);
1502  next0 = SNAT_OUT2IN_NEXT_DROP;
1503  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1504  goto trace00;
1505  }
1506  new_port0 = ses0->in_port;
1507 
1508  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1509 
1510  old_addr0 = ip0->dst_address;
1511  ip0->dst_address = new_addr0;
1512  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
1513 
1514  sum0 = ip0->checksum;
1515  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1516  ip4_header_t,
1517  dst_address /* changed member */);
1518  ip0->checksum = ip_csum_fold (sum0);
1519 
1520  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1521  {
1522  if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
1523  ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
1524  else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
1525  snat_det_ses_close(dm0, ses0);
1526 
1527  old_port0 = tcp0->dst;
1528  tcp0->dst = new_port0;
1529 
1530  sum0 = tcp0->checksum;
1531  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1532  ip4_header_t,
1533  dst_address /* changed member */);
1534 
1535  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1536  ip4_header_t /* cheat */,
1537  length /* changed member */);
1538  tcp0->checksum = ip_csum_fold(sum0);
1539  }
1540  else
1541  {
1542  old_port0 = udp0->dst_port;
1543  udp0->dst_port = new_port0;
1544  udp0->checksum = 0;
1545  }
1546 
1547  trace00:
1548 
1550  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1551  {
1552  snat_out2in_trace_t *t =
1553  vlib_add_trace (vm, node, b0, sizeof (*t));
1554  t->sw_if_index = sw_if_index0;
1555  t->next_index = next0;
1556  t->session_index = ~0;
1557  if (ses0)
1558  t->session_index = ses0 - dm0->sessions;
1559  }
1560 
1561  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1562 
1563  /* verify speculative enqueue, maybe switch current next frame */
1564  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1565  to_next, n_left_to_next,
1566  bi0, next0);
1567  }
1568 
1569  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1570  }
1571 
1573  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1574  pkts_processed);
1575  return frame->n_vectors;
1576 }
1577 
1579  .function = snat_det_out2in_node_fn,
1580  .name = "snat-det-out2in",
1581  .vector_size = sizeof (u32),
1582  .format_trace = format_snat_out2in_trace,
1583  .type = VLIB_NODE_TYPE_INTERNAL,
1584 
1585  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1586  .error_strings = snat_out2in_error_strings,
1587 
1588  .runtime_data_bytes = sizeof (snat_runtime_t),
1589 
1590  .n_next_nodes = 2,
1591 
1592  /* edit / add dispositions here */
1593  .next_nodes = {
1594  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1595  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1596  },
1597 };
1599 
1600 /**********************/
1601 /*** worker handoff ***/
1602 /**********************/
1603 static uword
1605  vlib_node_runtime_t * node,
1606  vlib_frame_t * frame)
1607 {
1608  snat_main_t *sm = &snat_main;
1610  u32 n_left_from, *from, *to_next = 0;
1611  static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
1612  static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
1613  = 0;
1614  vlib_frame_queue_elt_t *hf = 0;
1615  vlib_frame_t *f = 0;
1616  int i;
1617  u32 n_left_to_next_worker = 0, *to_next_worker = 0;
1618  u32 next_worker_index = 0;
1619  u32 current_worker_index = ~0;
1620  u32 cpu_index = os_get_cpu_number ();
1621 
1622  ASSERT (vec_len (sm->workers));
1623 
1624  if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0))
1625  {
1626  vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
1627 
1628  vec_validate_init_empty (congested_handoff_queue_by_worker_index,
1629  sm->first_worker_index + sm->num_workers - 1,
1630  (vlib_frame_queue_t *) (~0));
1631  }
1632 
1633  from = vlib_frame_vector_args (frame);
1634  n_left_from = frame->n_vectors;
1635 
1636  while (n_left_from > 0)
1637  {
1638  u32 bi0;
1639  vlib_buffer_t *b0;
1640  u32 sw_if_index0;
1641  u32 rx_fib_index0;
1642  ip4_header_t * ip0;
1643  u8 do_handoff;
1644 
1645  bi0 = from[0];
1646  from += 1;
1647  n_left_from -= 1;
1648 
1649  b0 = vlib_get_buffer (vm, bi0);
1650 
1651  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1652  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
1653 
1654  ip0 = vlib_buffer_get_current (b0);
1655 
1656  next_worker_index = sm->worker_out2in_cb(ip0, rx_fib_index0);
1657 
1658  if (PREDICT_FALSE (next_worker_index != cpu_index))
1659  {
1660  do_handoff = 1;
1661 
1662  if (next_worker_index != current_worker_index)
1663  {
1664  if (hf)
1665  hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
1666 
1667  hf = vlib_get_worker_handoff_queue_elt (sm->fq_out2in_index,
1668  next_worker_index,
1669  handoff_queue_elt_by_worker_index);
1670 
1671  n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors;
1672  to_next_worker = &hf->buffer_index[hf->n_vectors];
1673  current_worker_index = next_worker_index;
1674  }
1675 
1676  /* enqueue to correct worker thread */
1677  to_next_worker[0] = bi0;
1678  to_next_worker++;
1679  n_left_to_next_worker--;
1680 
1681  if (n_left_to_next_worker == 0)
1682  {
1683  hf->n_vectors = VLIB_FRAME_SIZE;
1685  current_worker_index = ~0;
1686  handoff_queue_elt_by_worker_index[next_worker_index] = 0;
1687  hf = 0;
1688  }
1689  }
1690  else
1691  {
1692  do_handoff = 0;
1693  /* if this is 1st frame */
1694  if (!f)
1695  {
1696  f = vlib_get_frame_to_node (vm, sm->out2in_node_index);
1697  to_next = vlib_frame_vector_args (f);
1698  }
1699 
1700  to_next[0] = bi0;
1701  to_next += 1;
1702  f->n_vectors++;
1703  }
1704 
1706  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1707  {
1709  vlib_add_trace (vm, node, b0, sizeof (*t));
1710  t->next_worker_index = next_worker_index;
1711  t->do_handoff = do_handoff;
1712  }
1713  }
1714 
1715  if (f)
1716  vlib_put_frame_to_node (vm, sm->out2in_node_index, f);
1717 
1718  if (hf)
1719  hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
1720 
1721  /* Ship frames to the worker nodes */
1722  for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++)
1723  {
1724  if (handoff_queue_elt_by_worker_index[i])
1725  {
1726  hf = handoff_queue_elt_by_worker_index[i];
1727  /*
1728  * It works better to let the handoff node
1729  * rate-adapt, always ship the handoff queue element.
1730  */
1731  if (1 || hf->n_vectors == hf->last_n_vectors)
1732  {
1734  handoff_queue_elt_by_worker_index[i] = 0;
1735  }
1736  else
1737  hf->last_n_vectors = hf->n_vectors;
1738  }
1739  congested_handoff_queue_by_worker_index[i] =
1740  (vlib_frame_queue_t *) (~0);
1741  }
1742  hf = 0;
1743  current_worker_index = ~0;
1744  return frame->n_vectors;
1745 }
1746 
1748  .function = snat_out2in_worker_handoff_fn,
1749  .name = "snat-out2in-worker-handoff",
1750  .vector_size = sizeof (u32),
1752  .type = VLIB_NODE_TYPE_INTERNAL,
1753 
1754  .n_next_nodes = 1,
1755 
1756  .next_nodes = {
1757  [0] = "error-drop",
1758  },
1759 };
1760 
1762 
1763 static uword
1765  vlib_node_runtime_t * node,
1766  vlib_frame_t * frame)
1767 {
1768  u32 n_left_from, * from, * to_next;
1769  snat_out2in_next_t next_index;
1770  u32 pkts_processed = 0;
1771  snat_main_t * sm = &snat_main;
1772 
1773  from = vlib_frame_vector_args (frame);
1774  n_left_from = frame->n_vectors;
1775  next_index = node->cached_next_index;
1776 
1777  while (n_left_from > 0)
1778  {
1779  u32 n_left_to_next;
1780 
1781  vlib_get_next_frame (vm, node, next_index,
1782  to_next, n_left_to_next);
1783 
1784  while (n_left_from > 0 && n_left_to_next > 0)
1785  {
1786  u32 bi0;
1787  vlib_buffer_t * b0;
1788  u32 next0 = SNAT_OUT2IN_NEXT_DROP;
1789  u32 sw_if_index0;
1790  ip4_header_t * ip0;
1791  ip_csum_t sum0;
1792  u32 new_addr0, old_addr0;
1793  u16 new_port0, old_port0;
1794  udp_header_t * udp0;
1795  tcp_header_t * tcp0;
1796  icmp46_header_t * icmp0;
1797  snat_session_key_t key0, sm0;
1798  u32 proto0;
1799  u32 rx_fib_index0;
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 
1811  ip0 = vlib_buffer_get_current (b0);
1812  udp0 = ip4_next_header (ip0);
1813  tcp0 = (tcp_header_t *) udp0;
1814  icmp0 = (icmp46_header_t *) udp0;
1815 
1816  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1817  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
1818 
1819  vnet_feature_next (sw_if_index0, &next0, b0);
1820 
1821  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1822 
1823  if (PREDICT_FALSE (proto0 == ~0))
1824  goto trace00;
1825 
1826  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1827  {
1828  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
1829  rx_fib_index0, node, next0, ~0, 0);
1830  goto trace00;
1831  }
1832 
1833  key0.addr = ip0->dst_address;
1834  key0.port = udp0->dst_port;
1835  key0.fib_index = rx_fib_index0;
1836 
1837  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0))
1838  {
1839  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1840  goto trace00;
1841  }
1842 
1843  new_addr0 = sm0.addr.as_u32;
1844  new_port0 = sm0.port;
1845  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
1846  old_addr0 = ip0->dst_address.as_u32;
1847  ip0->dst_address.as_u32 = new_addr0;
1848 
1849  sum0 = ip0->checksum;
1850  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1851  ip4_header_t,
1852  dst_address /* changed member */);
1853  ip0->checksum = ip_csum_fold (sum0);
1854 
1855  if (PREDICT_FALSE(new_port0 != udp0->dst_port))
1856  {
1857  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1858  {
1859  old_port0 = tcp0->dst_port;
1860  tcp0->dst_port = new_port0;
1861 
1862  sum0 = tcp0->checksum;
1863  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1864  ip4_header_t,
1865  dst_address /* changed member */);
1866 
1867  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1868  ip4_header_t /* cheat */,
1869  length /* changed member */);
1870  tcp0->checksum = ip_csum_fold(sum0);
1871  }
1872  else
1873  {
1874  old_port0 = udp0->dst_port;
1875  udp0->dst_port = new_port0;
1876  udp0->checksum = 0;
1877  }
1878  }
1879  else
1880  {
1881  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1882  {
1883  sum0 = tcp0->checksum;
1884  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1885  ip4_header_t,
1886  dst_address /* changed member */);
1887 
1888  tcp0->checksum = ip_csum_fold(sum0);
1889  }
1890  }
1891 
1892  trace00:
1893 
1895  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1896  {
1897  snat_out2in_trace_t *t =
1898  vlib_add_trace (vm, node, b0, sizeof (*t));
1899  t->sw_if_index = sw_if_index0;
1900  t->next_index = next0;
1901  }
1902 
1903  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1904 
1905  /* verify speculative enqueue, maybe switch current next frame */
1906  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1907  to_next, n_left_to_next,
1908  bi0, next0);
1909  }
1910 
1911  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1912  }
1913 
1915  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1916  pkts_processed);
1917  return frame->n_vectors;
1918 }
1919 
1921  .function = snat_out2in_fast_node_fn,
1922  .name = "snat-out2in-fast",
1923  .vector_size = sizeof (u32),
1924  .format_trace = format_snat_out2in_fast_trace,
1925  .type = VLIB_NODE_TYPE_INTERNAL,
1926 
1927  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1928  .error_strings = snat_out2in_error_strings,
1929 
1930  .runtime_data_bytes = sizeof (snat_runtime_t),
1931 
1932  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1933 
1934  /* edit / add dispositions here */
1935  .next_nodes = {
1936  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1937  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1938  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1939  },
1940 };
vlib_node_registration_t snat_out2in_fast_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_fast_node)
Definition: out2in.c:82
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:187
VLIB_NODE_FUNCTION_MULTIARCH(snat_out2in_node, snat_out2in_node_fn)
u32 sessions_per_user_list_head_index
Definition: snat.h:148
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
#define CLIB_UNUSED(x)
Definition: clib.h:79
u16 ext_host_port
Definition: snat.h:57
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
ip4_address_t src_address
Definition: ip4_packet.h:163
static u8 * format_snat_out2in_fast_trace(u8 *s, va_list *args)
Definition: out2in.c:56
#define PREDICT_TRUE(x)
Definition: clib.h:98
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 void snat_det_reverse(snat_det_map_t *dm, ip4_address_t *out_addr, u16 out_port, ip4_address_t *in_addr)
Definition: snat_det.h:89
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 snat_det_map_t * snat_det_map_by_out(snat_main_t *sm, ip4_address_t *out_addr)
Definition: snat_det.h:59
u32 nstaticsessions
Definition: snat.h:150
struct _vlib_node_registration vlib_node_registration_t
static u32 icmp_out2in_slow_path(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0, f64 now, u32 cpu_index, snat_session_t **p_s0)
Definition: out2in.c:602
uword ip_csum_t
Definition: ip_packet.h:90
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
u32 fib_index
Definition: snat.h:147
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
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
vlib_node_registration_t snat_det_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_det_out2in_node)
Definition: out2in.c:84
ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_checksum.c:43
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 void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:232
#define foreach_snat_out2in_error
Definition: out2in.c:86
static uword snat_out2in_worker_handoff_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:1604
u32 icmp_match_out2in_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: out2in.c:420
snat_out2in_next_t
Definition: out2in.c:105
#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
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
u32 icmp_match_out2in_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: out2in.c:312
#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
vlib_node_registration_t snat_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_node)
Definition: out2in.c:81
static_always_inline void vnet_feature_next(u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:221
#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
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
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:1112
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
void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.c:431
static u32 icmp_out2in(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0, u32 cpu_index, void *d)
Definition: out2in.c:481
#define clib_warning(format, args...)
Definition: error.h:59
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:85
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
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
static uword snat_det_out2in_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:1186
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
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
vlib_node_registration_t snat_out2in_worker_handoff_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node)
Definition: out2in.c:83
snat_out2in_error_t
Definition: out2in.c:92
static snat_session_t * create_session_for_static_mapping(snat_main_t *sm, vlib_buffer_t *b0, snat_session_key_t in2out, snat_session_key_t out2in, vlib_node_runtime_t *node, u32 cpu_index)
Create session for static mapping.
Definition: out2in.c:127
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
static char * snat_out2in_error_strings[]
Definition: out2in.c:99
unsigned char u8
Definition: types.h:56
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
static_always_inline snat_out2in_error_t icmp_get_key(ip4_header_t *ip0, snat_session_key_t *p_key0)
Definition: out2in.c:230
u32 fib_index
Definition: snat.h:70
static u8 * format_snat_out2in_trace(u8 *s, va_list *args)
Definition: out2in.c:45
static void vlib_put_frame_queue_elt(vlib_frame_queue_elt_t *hf)
Definition: threads.h:380
static uword snat_out2in_fast_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:1764
#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
static uword snat_out2in_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:636
u8 data[0]
Packet data.
Definition: buffer.h:152
u16 flags
Copy of main node flags.
Definition: node.h:449
#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
static_always_inline u8 is_interface_addr(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, u32 ip4_addr)
Definition: out2in.c:275
#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
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
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:145
static u8 * format_snat_out2in_worker_handoff_trace(u8 *s, va_list *args)
Definition: out2in.c:67
Definition: defs.h:46