FD.io VPP  v18.01-8-g0eacf49
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 <nat/nat.h>
26 #include <nat/nat_ipfix_logging.h>
27 #include <nat/nat_det.h>
28 #include <nat/nat_reass.h>
29 
30 #include <vppinfra/hash.h>
31 #include <vppinfra/error.h>
32 #include <vppinfra/elog.h>
33 
34 typedef struct {
39 
40 typedef struct {
44 
45 /* packet trace format function */
46 static u8 * format_snat_out2in_trace (u8 * s, va_list * args)
47 {
48  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
49  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
50  snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *);
51 
52  s = format (s, "NAT44_OUT2IN: sw_if_index %d, next index %d, session index %d",
54  return s;
55 }
56 
57 static u8 * format_snat_out2in_fast_trace (u8 * s, va_list * args)
58 {
59  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
60  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
61  snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *);
62 
63  s = format (s, "NAT44_OUT2IN_FAST: sw_if_index %d, next index %d",
64  t->sw_if_index, t->next_index);
65  return s;
66 }
67 
68 static u8 * format_snat_out2in_worker_handoff_trace (u8 * s, va_list * args)
69 {
70  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
71  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
73  va_arg (*args, snat_out2in_worker_handoff_trace_t *);
74  char * m;
75 
76  m = t->do_handoff ? "next worker" : "same worker";
77  s = format (s, "NAT44_OUT2IN_WORKER_HANDOFF: %s %d", m, t->next_worker_index);
78 
79  return s;
80 }
81 
82 typedef struct {
87 
88 static u8 * format_nat44_out2in_reass_trace (u8 * s, va_list * args)
89 {
90  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
91  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
93 
94  s = format (s, "NAT44_OUT2IN_REASS: sw_if_index %d, next index %d, status %s",
95  t->sw_if_index, t->next_index,
96  t->cached ? "cached" : "translated");
97 
98  return s;
99 }
100 
106 
107 #define foreach_snat_out2in_error \
108 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
109 _(OUT2IN_PACKETS, "Good out2in packets processed") \
110 _(OUT_OF_PORTS, "Out of ports") \
111 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
112 _(NO_TRANSLATION, "No translation") \
113 _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded") \
114 _(DROP_FRAGMENT, "Drop fragment") \
115 _(MAX_REASS, "Maximum reassemblies exceeded") \
116 _(MAX_FRAG, "Maximum fragments per reassembly exceeded")
117 
118 typedef enum {
119 #define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
121 #undef _
124 
125 static char * snat_out2in_error_strings[] = {
126 #define _(sym,string) string,
128 #undef _
129 };
130 
131 typedef enum {
138 
139 /**
140  * @brief Create session for static mapping.
141  *
142  * Create NAT session initiated by host from external network with static
143  * mapping.
144  *
145  * @param sm NAT main.
146  * @param b0 Vlib buffer.
147  * @param in2out In2out NAT44 session key.
148  * @param out2in Out2in NAT44 session key.
149  * @param node Vlib node.
150  *
151  * @returns SNAT session if successfully created otherwise 0.
152  */
153 static inline snat_session_t *
155  vlib_buffer_t *b0,
156  snat_session_key_t in2out,
157  snat_session_key_t out2in,
158  vlib_node_runtime_t * node,
159  u32 thread_index)
160 {
161  snat_user_t *u;
162  snat_session_t *s;
164  ip4_header_t *ip0;
165  udp_header_t *udp0;
166 
167  if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
168  {
169  b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
170  return 0;
171  }
172 
173  ip0 = vlib_buffer_get_current (b0);
174  udp0 = ip4_next_header (ip0);
175 
176  u = nat_user_get_or_create (sm, &in2out.addr, in2out.fib_index, thread_index);
177  if (!u)
178  {
179  clib_warning ("create NAT user failed");
180  return 0;
181  }
182 
183  s = nat_session_alloc_or_recycle (sm, u, thread_index);
184  if (!s)
185  {
186  clib_warning ("create NAT session failed");
187  return 0;
188  }
189 
190  s->outside_address_index = ~0;
192  s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
193  s->ext_host_port = udp0->src_port;
194  u->nstaticsessions++;
195  s->in2out = in2out;
196  s->out2in = out2in;
197  s->in2out.protocol = out2in.protocol;
198 
199  /* Add to translation hashes */
200  kv0.key = s->in2out.as_u64;
201  kv0.value = s - sm->per_thread_data[thread_index].sessions;
202  if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0,
203  1 /* is_add */))
204  clib_warning ("in2out key add failed");
205 
206  kv0.key = s->out2in.as_u64;
207 
208  if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
209  1 /* is_add */))
210  clib_warning ("out2in key add failed");
211 
212  /* log NAT event */
213  snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32,
214  s->out2in.addr.as_u32,
215  s->in2out.protocol,
216  s->in2out.port,
217  s->out2in.port,
218  s->in2out.fib_index);
219  return s;
220 }
221 
224  snat_session_key_t *p_key0)
225 {
226  icmp46_header_t *icmp0;
227  snat_session_key_t key0;
228  icmp_echo_header_t *echo0, *inner_echo0 = 0;
229  ip4_header_t *inner_ip0;
230  void *l4_header = 0;
231  icmp46_header_t *inner_icmp0;
232 
233  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
234  echo0 = (icmp_echo_header_t *)(icmp0+1);
235 
236  if (!icmp_is_error_message (icmp0))
237  {
238  key0.protocol = SNAT_PROTOCOL_ICMP;
239  key0.addr = ip0->dst_address;
240  key0.port = echo0->identifier;
241  }
242  else
243  {
244  inner_ip0 = (ip4_header_t *)(echo0+1);
245  l4_header = ip4_next_header (inner_ip0);
246  key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
247  key0.addr = inner_ip0->src_address;
248  switch (key0.protocol)
249  {
250  case SNAT_PROTOCOL_ICMP:
251  inner_icmp0 = (icmp46_header_t*)l4_header;
252  inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
253  key0.port = inner_echo0->identifier;
254  break;
255  case SNAT_PROTOCOL_UDP:
256  case SNAT_PROTOCOL_TCP:
257  key0.port = ((tcp_udp_header_t*)l4_header)->src_port;
258  break;
259  default:
260  return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
261  }
262  }
263  *p_key0 = key0;
264  return -1; /* success */
265 }
266 
267 /**
268  * Get address and port values to be used for ICMP packet translation
269  * and create session if needed
270  *
271  * @param[in,out] sm NAT main
272  * @param[in,out] node NAT node runtime
273  * @param[in] thread_index thread index
274  * @param[in,out] b0 buffer containing packet to be translated
275  * @param[out] p_proto protocol used for matching
276  * @param[out] p_value address and port after NAT translation
277  * @param[out] p_dont_translate if packet should not be translated
278  * @param d optional parameter
279  * @param e optional parameter
280  */
282  u32 thread_index, vlib_buffer_t *b0,
283  ip4_header_t *ip0, u8 *p_proto,
284  snat_session_key_t *p_value,
285  u8 *p_dont_translate, void *d, void *e)
286 {
287  icmp46_header_t *icmp0;
288  u32 sw_if_index0;
289  u32 rx_fib_index0;
290  snat_session_key_t key0;
291  snat_session_key_t sm0;
292  snat_session_t *s0 = 0;
293  u8 dont_translate = 0;
294  clib_bihash_kv_8_8_t kv0, value0;
295  u8 is_addr_only;
296  u32 next0 = ~0;
297  int err;
298 
299  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
300  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
301  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
302 
303  key0.protocol = 0;
304 
305  err = icmp_get_key (ip0, &key0);
306  if (err != -1)
307  {
308  b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
309  next0 = SNAT_OUT2IN_NEXT_DROP;
310  goto out;
311  }
312  key0.fib_index = rx_fib_index0;
313 
314  kv0.key = key0.as_u64;
315 
316  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
317  &value0))
318  {
319  /* Try to match static mapping by external address and port,
320  destination address and port in packet */
321  if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0))
322  {
323  if (!sm->forwarding_enabled)
324  {
325  /* Don't NAT packet aimed at the intfc address */
326  if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
327  ip0->dst_address.as_u32)))
328  {
329  dont_translate = 1;
330  goto out;
331  }
332  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
333  next0 = SNAT_OUT2IN_NEXT_DROP;
334  goto out;
335  }
336  else
337  {
338  dont_translate = 1;
339  goto out;
340  }
341  }
342 
343  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
344  (icmp0->type != ICMP4_echo_request || !is_addr_only)))
345  {
346  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
347  next0 = SNAT_OUT2IN_NEXT_DROP;
348  goto out;
349  }
350 
351  /* Create session initiated by host from external network */
352  s0 = create_session_for_static_mapping(sm, b0, sm0, key0,
353  node, thread_index);
354 
355  if (!s0)
356  {
357  next0 = SNAT_OUT2IN_NEXT_DROP;
358  goto out;
359  }
360  }
361  else
362  {
363  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
364  icmp0->type != ICMP4_echo_request &&
365  !icmp_is_error_message (icmp0)))
366  {
367  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
368  next0 = SNAT_OUT2IN_NEXT_DROP;
369  goto out;
370  }
371 
372  s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
373  value0.value);
374  }
375 
376 out:
377  *p_proto = key0.protocol;
378  if (s0)
379  *p_value = s0->in2out;
380  *p_dont_translate = dont_translate;
381  if (d)
382  *(snat_session_t**)d = s0;
383  return next0;
384 }
385 
386 /**
387  * Get address and port values to be used for ICMP packet translation
388  *
389  * @param[in] sm NAT main
390  * @param[in,out] node NAT node runtime
391  * @param[in] thread_index thread index
392  * @param[in,out] b0 buffer containing packet to be translated
393  * @param[out] p_proto protocol used for matching
394  * @param[out] p_value address and port after NAT translation
395  * @param[out] p_dont_translate if packet should not be translated
396  * @param d optional parameter
397  * @param e optional parameter
398  */
400  u32 thread_index, vlib_buffer_t *b0,
401  ip4_header_t *ip0, u8 *p_proto,
402  snat_session_key_t *p_value,
403  u8 *p_dont_translate, void *d, void *e)
404 {
405  icmp46_header_t *icmp0;
406  u32 sw_if_index0;
407  u32 rx_fib_index0;
408  snat_session_key_t key0;
409  snat_session_key_t sm0;
410  u8 dont_translate = 0;
411  u8 is_addr_only;
412  u32 next0 = ~0;
413  int err;
414 
415  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
416  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
417  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
418 
419  err = icmp_get_key (ip0, &key0);
420  if (err != -1)
421  {
422  b0->error = node->errors[err];
423  next0 = SNAT_OUT2IN_NEXT_DROP;
424  goto out2;
425  }
426  key0.fib_index = rx_fib_index0;
427 
428  if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0))
429  {
430  /* Don't NAT packet aimed at the intfc address */
431  if (is_interface_addr(sm, node, sw_if_index0, ip0->dst_address.as_u32))
432  {
433  dont_translate = 1;
434  goto out;
435  }
436  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
437  next0 = SNAT_OUT2IN_NEXT_DROP;
438  goto out;
439  }
440 
441  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
442  (icmp0->type != ICMP4_echo_request || !is_addr_only) &&
443  !icmp_is_error_message (icmp0)))
444  {
445  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
446  next0 = SNAT_OUT2IN_NEXT_DROP;
447  goto out;
448  }
449 
450 out:
451  *p_value = sm0;
452 out2:
453  *p_proto = key0.protocol;
454  *p_dont_translate = dont_translate;
455  return next0;
456 }
457 
458 static inline u32 icmp_out2in (snat_main_t *sm,
459  vlib_buffer_t * b0,
460  ip4_header_t * ip0,
461  icmp46_header_t * icmp0,
462  u32 sw_if_index0,
463  u32 rx_fib_index0,
464  vlib_node_runtime_t * node,
465  u32 next0,
466  u32 thread_index,
467  void *d,
468  void *e)
469 {
470  snat_session_key_t sm0;
471  u8 protocol;
472  icmp_echo_header_t *echo0, *inner_echo0 = 0;
473  ip4_header_t *inner_ip0 = 0;
474  void *l4_header = 0;
475  icmp46_header_t *inner_icmp0;
476  u8 dont_translate;
477  u32 new_addr0, old_addr0;
478  u16 old_id0, new_id0;
479  ip_csum_t sum0;
480  u16 checksum0;
481  u32 next0_tmp;
482 
483  echo0 = (icmp_echo_header_t *)(icmp0+1);
484 
485  next0_tmp = sm->icmp_match_out2in_cb(sm, node, thread_index, b0, ip0,
486  &protocol, &sm0, &dont_translate, d, e);
487  if (next0_tmp != ~0)
488  next0 = next0_tmp;
489  if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
490  goto out;
491 
492  sum0 = ip_incremental_checksum (0, icmp0,
493  ntohs(ip0->length) - ip4_header_bytes (ip0));
494  checksum0 = ~ip_csum_fold (sum0);
495  if (checksum0 != 0 && checksum0 != 0xffff)
496  {
497  next0 = SNAT_OUT2IN_NEXT_DROP;
498  goto out;
499  }
500 
501  old_addr0 = ip0->dst_address.as_u32;
502  new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32;
503  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
504 
505  sum0 = ip0->checksum;
506  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
507  dst_address /* changed member */);
508  ip0->checksum = ip_csum_fold (sum0);
509 
510  if (!icmp_is_error_message (icmp0))
511  {
512  new_id0 = sm0.port;
513  if (PREDICT_FALSE(new_id0 != echo0->identifier))
514  {
515  old_id0 = echo0->identifier;
516  new_id0 = sm0.port;
517  echo0->identifier = new_id0;
518 
519  sum0 = icmp0->checksum;
520  sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
521  identifier /* changed member */);
522  icmp0->checksum = ip_csum_fold (sum0);
523  }
524  }
525  else
526  {
527  inner_ip0 = (ip4_header_t *)(echo0+1);
528  l4_header = ip4_next_header (inner_ip0);
529 
530  if (!ip4_header_checksum_is_valid (inner_ip0))
531  {
532  next0 = SNAT_OUT2IN_NEXT_DROP;
533  goto out;
534  }
535 
536  old_addr0 = inner_ip0->src_address.as_u32;
537  inner_ip0->src_address = sm0.addr;
538  new_addr0 = inner_ip0->src_address.as_u32;
539 
540  sum0 = icmp0->checksum;
541  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
542  src_address /* changed member */);
543  icmp0->checksum = ip_csum_fold (sum0);
544 
545  switch (protocol)
546  {
547  case SNAT_PROTOCOL_ICMP:
548  inner_icmp0 = (icmp46_header_t*)l4_header;
549  inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
550 
551  old_id0 = inner_echo0->identifier;
552  new_id0 = sm0.port;
553  inner_echo0->identifier = new_id0;
554 
555  sum0 = icmp0->checksum;
556  sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
557  identifier);
558  icmp0->checksum = ip_csum_fold (sum0);
559  break;
560  case SNAT_PROTOCOL_UDP:
561  case SNAT_PROTOCOL_TCP:
562  old_id0 = ((tcp_udp_header_t*)l4_header)->src_port;
563  new_id0 = sm0.port;
564  ((tcp_udp_header_t*)l4_header)->src_port = new_id0;
565 
566  sum0 = icmp0->checksum;
567  sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
568  src_port);
569  icmp0->checksum = ip_csum_fold (sum0);
570  break;
571  default:
572  ASSERT(0);
573  }
574  }
575 
576 out:
577  return next0;
578 }
579 
580 
582  vlib_buffer_t * b0,
583  ip4_header_t * ip0,
584  icmp46_header_t * icmp0,
585  u32 sw_if_index0,
586  u32 rx_fib_index0,
587  vlib_node_runtime_t * node,
588  u32 next0, f64 now,
589  u32 thread_index,
590  snat_session_t ** p_s0)
591 {
592  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
593  next0, thread_index, p_s0, 0);
594  snat_session_t * s0 = *p_s0;
595  if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0))
596  {
597  /* Accounting */
598  s0->last_heard = now;
599  s0->total_pkts++;
600  s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0);
601  /* Per-user LRU list maintenance */
602  clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
603  s0->per_user_index);
604  clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
605  s0->per_user_list_head_index,
606  s0->per_user_index);
607  }
608  return next0;
609 }
610 
611 static snat_session_t *
613  vlib_buffer_t * b,
614  ip4_header_t * ip,
615  u32 rx_fib_index,
616  u32 thread_index,
617  f64 now,
618  vlib_main_t * vm,
619  vlib_node_runtime_t * node)
620 {
621  clib_bihash_kv_8_8_t kv, value;
622  clib_bihash_kv_16_8_t s_kv, s_value;
624  snat_session_key_t m_key;
625  u32 old_addr, new_addr;
626  ip_csum_t sum;
627  nat_ed_ses_key_t key;
628  snat_session_t * s;
629  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
630  snat_user_t *u;
631 
632  old_addr = ip->dst_address.as_u32;
633 
634  key.l_addr = ip->dst_address;
635  key.r_addr = ip->src_address;
636  key.fib_index = rx_fib_index;
637  key.proto = ip->protocol;
638  key.r_port = 0;
639  key.l_port = 0;
640  s_kv.key[0] = key.as_u64[0];
641  s_kv.key[1] = key.as_u64[1];
642 
643  if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
644  {
645  s = pool_elt_at_index (tsm->sessions, s_value.value);
646  new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
647  }
648  else
649  {
650  if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
651  {
652  b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
653  return 0;
654  }
655 
656  m_key.addr = ip->dst_address;
657  m_key.port = 0;
658  m_key.protocol = 0;
659  m_key.fib_index = rx_fib_index;
660  kv.key = m_key.as_u64;
661  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
662  {
663  b->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
664  return 0;
665  }
666 
667  m = pool_elt_at_index (sm->static_mappings, value.value);
668 
669  new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
670 
671  u = nat_user_get_or_create (sm, &ip->src_address, m->fib_index,
672  thread_index);
673  if (!u)
674  {
675  clib_warning ("create NAT user failed");
676  return 0;
677  }
678 
679  /* Create a new session */
680  s = nat_session_alloc_or_recycle (sm, u, thread_index);
681  if (!s)
682  {
683  clib_warning ("create NAT session failed");
684  return 0;
685  }
686 
687  s->ext_host_addr.as_u32 = ip->src_address.as_u32;
690  s->outside_address_index = ~0;
691  s->out2in.addr.as_u32 = old_addr;
692  s->out2in.fib_index = rx_fib_index;
693  s->in2out.addr.as_u32 = new_addr;
694  s->in2out.fib_index = m->fib_index;
695  s->in2out.port = s->out2in.port = ip->protocol;
696  u->nstaticsessions++;
697 
698  /* Add to lookup tables */
699  s_kv.value = s - tsm->sessions;
700  if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
701  clib_warning ("out2in key add failed");
702 
703  key.l_addr = ip->dst_address;
704  key.fib_index = m->fib_index;
705  s_kv.key[0] = key.as_u64[0];
706  s_kv.key[1] = key.as_u64[1];
707  if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
708  clib_warning ("in2out key add failed");
709  }
710 
711  /* Update IP checksum */
712  sum = ip->checksum;
713  sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
714  ip->checksum = ip_csum_fold (sum);
715 
716  vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
717 
718  /* Accounting */
719  s->last_heard = now;
720  s->total_pkts++;
721  s->total_bytes += vlib_buffer_length_in_chain (vm, b);
722  /* Per-user LRU list maintenance */
723  clib_dlist_remove (tsm->list_pool, s->per_user_index);
724  clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
725  s->per_user_index);
726 
727  return s;
728 }
729 
730 static snat_session_t *
732  vlib_buffer_t * b,
733  ip4_header_t * ip,
734  u32 rx_fib_index,
735  u32 thread_index,
736  f64 now,
737  vlib_main_t * vm,
738  vlib_node_runtime_t * node)
739 {
740  nat_ed_ses_key_t key;
741  clib_bihash_kv_16_8_t s_kv, s_value;
742  udp_header_t *udp = ip4_next_header (ip);
743  tcp_header_t *tcp = (tcp_header_t *) udp;
744  snat_session_t *s = 0;
745  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
746  snat_session_key_t e_key, l_key;
747  u32 old_addr, new_addr;
748  u32 proto = ip_proto_to_snat_proto (ip->protocol);
749  u16 new_port, old_port;
750  ip_csum_t sum;
751  snat_user_t *u;
752  u32 address_index;
753  snat_session_key_t eh_key;
754  u8 twice_nat;
755 
756  old_addr = ip->dst_address.as_u32;
757 
758  key.l_addr = ip->dst_address;
759  key.r_addr = ip->src_address;
760  key.fib_index = rx_fib_index;
761  key.proto = ip->protocol;
762  key.r_port = udp->src_port;
763  key.l_port = udp->dst_port;
764  s_kv.key[0] = key.as_u64[0];
765  s_kv.key[1] = key.as_u64[1];
766 
767  if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
768  {
769  s = pool_elt_at_index (tsm->sessions, s_value.value);
770  }
771  else
772  {
773  if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
774  {
775  b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
776  return 0;
777  }
778 
779  e_key.addr = ip->dst_address;
780  e_key.port = udp->dst_port;
781  e_key.protocol = proto;
782  e_key.fib_index = rx_fib_index;
783  if (snat_static_mapping_match(sm, e_key, &l_key, 1, 0, &twice_nat))
784  return 0;
785 
786  u = nat_user_get_or_create (sm, &l_key.addr, l_key.fib_index,
787  thread_index);
788  if (!u)
789  {
790  clib_warning ("create NAT user failed");
791  return 0;
792  }
793 
794  s = nat_session_alloc_or_recycle (sm, u, thread_index);
795  if (!s)
796  {
797  clib_warning ("create NAT session failed");
798  return 0;
799  }
800 
801  s->ext_host_addr.as_u32 = ip->src_address.as_u32;
802  s->ext_host_port = udp->src_port;
805  s->outside_address_index = ~0;
806  s->out2in = e_key;
807  s->in2out = l_key;
808  u->nstaticsessions++;
809 
810  /* Add to lookup tables */
811  s_kv.value = s - tsm->sessions;
812  if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
813  clib_warning ("out2in-ed key add failed");
814 
815  if (twice_nat)
816  {
817  eh_key.protocol = proto;
819  thread_index, &eh_key,
820  &address_index,
821  sm->port_per_thread,
822  sm->per_thread_data[thread_index].snat_thread_index))
823  {
824  b->error = node->errors[SNAT_OUT2IN_ERROR_OUT_OF_PORTS];
825  return 0;
826  }
827  key.r_addr.as_u32 = s->ext_host_nat_addr.as_u32 = eh_key.addr.as_u32;
828  key.r_port = s->ext_host_nat_port = eh_key.port;
829  s->flags |= SNAT_SESSION_FLAG_TWICE_NAT;
830  }
831  key.l_addr = l_key.addr;
832  key.fib_index = l_key.fib_index;
833  key.l_port = l_key.port;
834  s_kv.key[0] = key.as_u64[0];
835  s_kv.key[1] = key.as_u64[1];
836  if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
837  clib_warning ("in2out-ed key add failed");
838  }
839 
840  new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
841 
842  /* Update IP checksum */
843  sum = ip->checksum;
844  sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
845  if (is_twice_nat_session (s))
846  sum = ip_csum_update (sum, ip->src_address.as_u32,
847  s->ext_host_nat_addr.as_u32, ip4_header_t,
848  src_address);
849  ip->checksum = ip_csum_fold (sum);
850 
851  if (PREDICT_TRUE(proto == SNAT_PROTOCOL_TCP))
852  {
853  old_port = tcp->dst_port;
854  tcp->dst_port = s->in2out.port;
855  new_port = tcp->dst_port;
856 
857  sum = tcp->checksum;
858  sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
859  sum = ip_csum_update (sum, old_port, new_port, ip4_header_t, length);
860  if (is_twice_nat_session (s))
861  {
862  sum = ip_csum_update (sum, ip->src_address.as_u32,
863  s->ext_host_nat_addr.as_u32, ip4_header_t,
864  dst_address);
865  sum = ip_csum_update (sum, tcp->src_port, s->ext_host_nat_port,
866  ip4_header_t, length);
867  tcp->src_port = s->ext_host_nat_port;
868  ip->src_address.as_u32 = s->ext_host_nat_addr.as_u32;
869  }
870  tcp->checksum = ip_csum_fold(sum);
871  }
872  else
873  {
874  udp->dst_port = s->in2out.port;
875  if (is_twice_nat_session (s))
876  {
877  udp->src_port = s->ext_host_nat_port;
878  ip->src_address.as_u32 = s->ext_host_nat_addr.as_u32;
879  }
880  udp->checksum = 0;
881  }
882 
883  vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
884 
885  /* Accounting */
886  s->last_heard = now;
887  s->total_pkts++;
888  s->total_bytes += vlib_buffer_length_in_chain (vm, b);
889  /* Per-user LRU list maintenance */
890  clib_dlist_remove (tsm->list_pool, s->per_user_index);
891  clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
892  s->per_user_index);
893 
894  return s;
895 }
896 
897 static uword
899  vlib_node_runtime_t * node,
900  vlib_frame_t * frame)
901 {
902  u32 n_left_from, * from, * to_next;
903  snat_out2in_next_t next_index;
904  u32 pkts_processed = 0;
905  snat_main_t * sm = &snat_main;
906  f64 now = vlib_time_now (vm);
907  u32 thread_index = vlib_get_thread_index ();
908 
909  from = vlib_frame_vector_args (frame);
910  n_left_from = frame->n_vectors;
911  next_index = node->cached_next_index;
912 
913  while (n_left_from > 0)
914  {
915  u32 n_left_to_next;
916 
917  vlib_get_next_frame (vm, node, next_index,
918  to_next, n_left_to_next);
919 
920  while (n_left_from >= 4 && n_left_to_next >= 2)
921  {
922  u32 bi0, bi1;
923  vlib_buffer_t * b0, * b1;
926  u32 sw_if_index0, sw_if_index1;
927  ip4_header_t * ip0, *ip1;
928  ip_csum_t sum0, sum1;
929  u32 new_addr0, old_addr0;
930  u16 new_port0, old_port0;
931  u32 new_addr1, old_addr1;
932  u16 new_port1, old_port1;
933  udp_header_t * udp0, * udp1;
934  tcp_header_t * tcp0, * tcp1;
935  icmp46_header_t * icmp0, * icmp1;
936  snat_session_key_t key0, key1, sm0, sm1;
937  u32 rx_fib_index0, rx_fib_index1;
938  u32 proto0, proto1;
939  snat_session_t * s0 = 0, * s1 = 0;
940  clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
941 
942  /* Prefetch next iteration. */
943  {
944  vlib_buffer_t * p2, * p3;
945 
946  p2 = vlib_get_buffer (vm, from[2]);
947  p3 = vlib_get_buffer (vm, from[3]);
948 
949  vlib_prefetch_buffer_header (p2, LOAD);
950  vlib_prefetch_buffer_header (p3, LOAD);
951 
954  }
955 
956  /* speculatively enqueue b0 and b1 to the current next frame */
957  to_next[0] = bi0 = from[0];
958  to_next[1] = bi1 = from[1];
959  from += 2;
960  to_next += 2;
961  n_left_from -= 2;
962  n_left_to_next -= 2;
963 
964  b0 = vlib_get_buffer (vm, bi0);
965  b1 = vlib_get_buffer (vm, bi1);
966 
967  vnet_buffer (b0)->snat.flags = 0;
968  vnet_buffer (b1)->snat.flags = 0;
969 
970  ip0 = vlib_buffer_get_current (b0);
971  udp0 = ip4_next_header (ip0);
972  tcp0 = (tcp_header_t *) udp0;
973  icmp0 = (icmp46_header_t *) udp0;
974 
975  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
976  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
977  sw_if_index0);
978 
979  if (PREDICT_FALSE(ip0->ttl == 1))
980  {
981  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
982  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
983  ICMP4_time_exceeded_ttl_exceeded_in_transit,
984  0);
986  goto trace0;
987  }
988 
989  proto0 = ip_proto_to_snat_proto (ip0->protocol);
990 
991  if (PREDICT_FALSE (proto0 == ~0))
992  {
993  s0 = snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0,
994  thread_index, now, vm, node);
995  if (!s0)
996  next0 = SNAT_OUT2IN_NEXT_DROP;
997  goto trace0;
998  }
999 
1000  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1001  {
1002  next0 = icmp_out2in_slow_path
1003  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1004  next0, now, thread_index, &s0);
1005  goto trace0;
1006  }
1007 
1008  if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1009  {
1010  next0 = SNAT_OUT2IN_NEXT_REASS;
1011  goto trace0;
1012  }
1013 
1014  key0.addr = ip0->dst_address;
1015  key0.port = udp0->dst_port;
1016  key0.protocol = proto0;
1017  key0.fib_index = rx_fib_index0;
1018 
1019  kv0.key = key0.as_u64;
1020 
1021  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1022  &kv0, &value0))
1023  {
1024  /* Try to match static mapping by external address and port,
1025  destination address and port in packet */
1026  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
1027  {
1028  if (!sm->forwarding_enabled)
1029  {
1030  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1031  /*
1032  * Send DHCP packets to the ipv4 stack, or we won't
1033  * be able to use dhcp client on the outside interface
1034  */
1035  if (proto0 != SNAT_PROTOCOL_UDP
1036  || (udp0->dst_port
1037  != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
1038  next0 = SNAT_OUT2IN_NEXT_DROP;
1039  goto trace0;
1040  }
1041  else
1042  goto trace0;
1043  }
1044 
1045  /* Create session initiated by host from external network */
1046  s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1047  thread_index);
1048  if (!s0)
1049  {
1050  next0 = SNAT_OUT2IN_NEXT_DROP;
1051  goto trace0;
1052  }
1053  }
1054  else
1055  {
1056  if (PREDICT_FALSE (value0.value == ~0ULL))
1057  {
1058  s0 = snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index,
1059  now, vm, node);
1060  if (!s0)
1061  next0 = SNAT_OUT2IN_NEXT_DROP;
1062  goto trace0;
1063  }
1064  else
1065  {
1066  s0 = pool_elt_at_index (
1067  sm->per_thread_data[thread_index].sessions,
1068  value0.value);
1069  }
1070  }
1071 
1072  old_addr0 = ip0->dst_address.as_u32;
1073  ip0->dst_address = s0->in2out.addr;
1074  new_addr0 = ip0->dst_address.as_u32;
1075  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1076 
1077  sum0 = ip0->checksum;
1078  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1079  ip4_header_t,
1080  dst_address /* changed member */);
1081  ip0->checksum = ip_csum_fold (sum0);
1082 
1083  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1084  {
1085  old_port0 = tcp0->dst_port;
1086  tcp0->dst_port = s0->in2out.port;
1087  new_port0 = tcp0->dst_port;
1088 
1089  sum0 = tcp0->checksum;
1090  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1091  ip4_header_t,
1092  dst_address /* changed member */);
1093 
1094  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1095  ip4_header_t /* cheat */,
1096  length /* changed member */);
1097  tcp0->checksum = ip_csum_fold(sum0);
1098  }
1099  else
1100  {
1101  old_port0 = udp0->dst_port;
1102  udp0->dst_port = s0->in2out.port;
1103  udp0->checksum = 0;
1104  }
1105 
1106  /* Accounting */
1107  s0->last_heard = now;
1108  s0->total_pkts++;
1109  s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1110  /* Per-user LRU list maintenance */
1111  clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1112  s0->per_user_index);
1113  clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1114  s0->per_user_list_head_index,
1115  s0->per_user_index);
1116  trace0:
1117 
1119  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1120  {
1121  snat_out2in_trace_t *t =
1122  vlib_add_trace (vm, node, b0, sizeof (*t));
1123  t->sw_if_index = sw_if_index0;
1124  t->next_index = next0;
1125  t->session_index = ~0;
1126  if (s0)
1127  t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1128  }
1129 
1130  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1131 
1132 
1133  ip1 = vlib_buffer_get_current (b1);
1134  udp1 = ip4_next_header (ip1);
1135  tcp1 = (tcp_header_t *) udp1;
1136  icmp1 = (icmp46_header_t *) udp1;
1137 
1138  sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1139  rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1140  sw_if_index1);
1141 
1142  if (PREDICT_FALSE(ip1->ttl == 1))
1143  {
1144  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1145  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1146  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1147  0);
1149  goto trace1;
1150  }
1151 
1152  proto1 = ip_proto_to_snat_proto (ip1->protocol);
1153 
1154  if (PREDICT_FALSE (proto1 == ~0))
1155  {
1156  s1 = snat_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1,
1157  thread_index, now, vm, node);
1158  if (!s1)
1159  next1 = SNAT_OUT2IN_NEXT_DROP;
1160  goto trace1;
1161  }
1162 
1163  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1164  {
1165  next1 = icmp_out2in_slow_path
1166  (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1167  next1, now, thread_index, &s1);
1168  goto trace1;
1169  }
1170 
1171  if (PREDICT_FALSE (ip4_is_fragment (ip1)))
1172  {
1173  next1 = SNAT_OUT2IN_NEXT_REASS;
1174  goto trace1;
1175  }
1176 
1177  key1.addr = ip1->dst_address;
1178  key1.port = udp1->dst_port;
1179  key1.protocol = proto1;
1180  key1.fib_index = rx_fib_index1;
1181 
1182  kv1.key = key1.as_u64;
1183 
1184  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1185  &kv1, &value1))
1186  {
1187  /* Try to match static mapping by external address and port,
1188  destination address and port in packet */
1189  if (snat_static_mapping_match(sm, key1, &sm1, 1, 0, 0))
1190  {
1191  if (!sm->forwarding_enabled)
1192  {
1193  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1194  /*
1195  * Send DHCP packets to the ipv4 stack, or we won't
1196  * be able to use dhcp client on the outside interface
1197  */
1198  if (proto1 != SNAT_PROTOCOL_UDP
1199  || (udp1->dst_port
1200  != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
1201  next1 = SNAT_OUT2IN_NEXT_DROP;
1202  goto trace1;
1203  }
1204  else
1205  goto trace1;
1206  }
1207 
1208  /* Create session initiated by host from external network */
1209  s1 = create_session_for_static_mapping(sm, b1, sm1, key1, node,
1210  thread_index);
1211  if (!s1)
1212  {
1213  next1 = SNAT_OUT2IN_NEXT_DROP;
1214  goto trace1;
1215  }
1216  }
1217  else
1218  {
1219  if (PREDICT_FALSE (value1.value == ~0ULL))
1220  {
1221  s1 = snat_out2in_lb(sm, b1, ip1, rx_fib_index1, thread_index,
1222  now, vm, node);
1223  if (!s1)
1224  next1 = SNAT_OUT2IN_NEXT_DROP;
1225  goto trace1;
1226  }
1227  else
1228  {
1229  s1 = pool_elt_at_index (
1230  sm->per_thread_data[thread_index].sessions,
1231  value1.value);
1232  }
1233  }
1234 
1235  old_addr1 = ip1->dst_address.as_u32;
1236  ip1->dst_address = s1->in2out.addr;
1237  new_addr1 = ip1->dst_address.as_u32;
1238  vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1239 
1240  sum1 = ip1->checksum;
1241  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1242  ip4_header_t,
1243  dst_address /* changed member */);
1244  ip1->checksum = ip_csum_fold (sum1);
1245 
1246  if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1247  {
1248  old_port1 = tcp1->dst_port;
1249  tcp1->dst_port = s1->in2out.port;
1250  new_port1 = tcp1->dst_port;
1251 
1252  sum1 = tcp1->checksum;
1253  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1254  ip4_header_t,
1255  dst_address /* changed member */);
1256 
1257  sum1 = ip_csum_update (sum1, old_port1, new_port1,
1258  ip4_header_t /* cheat */,
1259  length /* changed member */);
1260  tcp1->checksum = ip_csum_fold(sum1);
1261  }
1262  else
1263  {
1264  old_port1 = udp1->dst_port;
1265  udp1->dst_port = s1->in2out.port;
1266  udp1->checksum = 0;
1267  }
1268 
1269  /* Accounting */
1270  s1->last_heard = now;
1271  s1->total_pkts++;
1272  s1->total_bytes += vlib_buffer_length_in_chain (vm, b1);
1273  /* Per-user LRU list maintenance */
1274  clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1275  s1->per_user_index);
1276  clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1277  s1->per_user_list_head_index,
1278  s1->per_user_index);
1279  trace1:
1280 
1282  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1283  {
1284  snat_out2in_trace_t *t =
1285  vlib_add_trace (vm, node, b1, sizeof (*t));
1286  t->sw_if_index = sw_if_index1;
1287  t->next_index = next1;
1288  t->session_index = ~0;
1289  if (s1)
1290  t->session_index = s1 - sm->per_thread_data[thread_index].sessions;
1291  }
1292 
1293  pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
1294 
1295  /* verify speculative enqueues, maybe switch current next frame */
1296  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1297  to_next, n_left_to_next,
1298  bi0, bi1, next0, next1);
1299  }
1300 
1301  while (n_left_from > 0 && n_left_to_next > 0)
1302  {
1303  u32 bi0;
1304  vlib_buffer_t * b0;
1305  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1306  u32 sw_if_index0;
1307  ip4_header_t * ip0;
1308  ip_csum_t sum0;
1309  u32 new_addr0, old_addr0;
1310  u16 new_port0, old_port0;
1311  udp_header_t * udp0;
1312  tcp_header_t * tcp0;
1313  icmp46_header_t * icmp0;
1314  snat_session_key_t key0, sm0;
1315  u32 rx_fib_index0;
1316  u32 proto0;
1317  snat_session_t * s0 = 0;
1318  clib_bihash_kv_8_8_t kv0, value0;
1319 
1320  /* speculatively enqueue b0 to the current next frame */
1321  bi0 = from[0];
1322  to_next[0] = bi0;
1323  from += 1;
1324  to_next += 1;
1325  n_left_from -= 1;
1326  n_left_to_next -= 1;
1327 
1328  b0 = vlib_get_buffer (vm, bi0);
1329 
1330  vnet_buffer (b0)->snat.flags = 0;
1331 
1332  ip0 = vlib_buffer_get_current (b0);
1333  udp0 = ip4_next_header (ip0);
1334  tcp0 = (tcp_header_t *) udp0;
1335  icmp0 = (icmp46_header_t *) udp0;
1336 
1337  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1338  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1339  sw_if_index0);
1340 
1341  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1342 
1343  if (PREDICT_FALSE (proto0 == ~0))
1344  {
1345  s0 = snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0,
1346  thread_index, now, vm, node);
1347  if (!s0)
1348  next0 = SNAT_OUT2IN_NEXT_DROP;
1349  goto trace00;
1350  }
1351 
1352  if (PREDICT_FALSE(ip0->ttl == 1))
1353  {
1354  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1355  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1356  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1357  0);
1359  goto trace00;
1360  }
1361 
1362  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1363  {
1364  next0 = icmp_out2in_slow_path
1365  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1366  next0, now, thread_index, &s0);
1367  goto trace00;
1368  }
1369 
1370  if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1371  {
1372  next0 = SNAT_OUT2IN_NEXT_REASS;
1373  goto trace00;
1374  }
1375 
1376  key0.addr = ip0->dst_address;
1377  key0.port = udp0->dst_port;
1378  key0.protocol = proto0;
1379  key0.fib_index = rx_fib_index0;
1380 
1381  kv0.key = key0.as_u64;
1382 
1383  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1384  &kv0, &value0))
1385  {
1386  /* Try to match static mapping by external address and port,
1387  destination address and port in packet */
1388  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
1389  {
1390  if (!sm->forwarding_enabled)
1391  {
1392  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1393  /*
1394  * Send DHCP packets to the ipv4 stack, or we won't
1395  * be able to use dhcp client on the outside interface
1396  */
1397  if (proto0 != SNAT_PROTOCOL_UDP
1398  || (udp0->dst_port
1399  != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
1400  next0 = SNAT_OUT2IN_NEXT_DROP;
1401  goto trace00;
1402  }
1403  else
1404  goto trace00;
1405  }
1406 
1407  /* Create session initiated by host from external network */
1408  s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1409  thread_index);
1410  if (!s0)
1411  {
1412  next0 = SNAT_OUT2IN_NEXT_DROP;
1413  goto trace00;
1414  }
1415  }
1416  else
1417  {
1418  if (PREDICT_FALSE (value0.value == ~0ULL))
1419  {
1420  s0 = snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index,
1421  now, vm, node);
1422  if (!s0)
1423  next0 = SNAT_OUT2IN_NEXT_DROP;
1424  goto trace00;
1425  }
1426  else
1427  {
1428  s0 = pool_elt_at_index (
1429  sm->per_thread_data[thread_index].sessions,
1430  value0.value);
1431  }
1432  }
1433 
1434  old_addr0 = ip0->dst_address.as_u32;
1435  ip0->dst_address = s0->in2out.addr;
1436  new_addr0 = ip0->dst_address.as_u32;
1437  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1438 
1439  sum0 = ip0->checksum;
1440  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1441  ip4_header_t,
1442  dst_address /* changed member */);
1443  ip0->checksum = ip_csum_fold (sum0);
1444 
1445  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1446  {
1447  old_port0 = tcp0->dst_port;
1448  tcp0->dst_port = s0->in2out.port;
1449  new_port0 = tcp0->dst_port;
1450 
1451  sum0 = tcp0->checksum;
1452  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1453  ip4_header_t,
1454  dst_address /* changed member */);
1455 
1456  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1457  ip4_header_t /* cheat */,
1458  length /* changed member */);
1459  tcp0->checksum = ip_csum_fold(sum0);
1460  }
1461  else
1462  {
1463  old_port0 = udp0->dst_port;
1464  udp0->dst_port = s0->in2out.port;
1465  udp0->checksum = 0;
1466  }
1467 
1468  /* Accounting */
1469  s0->last_heard = now;
1470  s0->total_pkts++;
1471  s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1472  /* Per-user LRU list maintenance */
1473  clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1474  s0->per_user_index);
1475  clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1476  s0->per_user_list_head_index,
1477  s0->per_user_index);
1478  trace00:
1479 
1481  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1482  {
1483  snat_out2in_trace_t *t =
1484  vlib_add_trace (vm, node, b0, sizeof (*t));
1485  t->sw_if_index = sw_if_index0;
1486  t->next_index = next0;
1487  t->session_index = ~0;
1488  if (s0)
1489  t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1490  }
1491 
1492  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1493 
1494  /* verify speculative enqueue, maybe switch current next frame */
1495  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1496  to_next, n_left_to_next,
1497  bi0, next0);
1498  }
1499 
1500  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1501  }
1502 
1504  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1505  pkts_processed);
1506  return frame->n_vectors;
1507 }
1508 
1510  .function = snat_out2in_node_fn,
1511  .name = "nat44-out2in",
1512  .vector_size = sizeof (u32),
1513  .format_trace = format_snat_out2in_trace,
1514  .type = VLIB_NODE_TYPE_INTERNAL,
1515 
1516  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1517  .error_strings = snat_out2in_error_strings,
1518 
1519  .runtime_data_bytes = sizeof (snat_runtime_t),
1520 
1521  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1522 
1523  /* edit / add dispositions here */
1524  .next_nodes = {
1525  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1526  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1527  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1528  [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1529  },
1530 };
1532 
1533 static uword
1535  vlib_node_runtime_t * node,
1536  vlib_frame_t * frame)
1537 {
1538  u32 n_left_from, *from, *to_next;
1539  snat_out2in_next_t next_index;
1540  u32 pkts_processed = 0;
1541  snat_main_t *sm = &snat_main;
1542  f64 now = vlib_time_now (vm);
1543  u32 thread_index = vlib_get_thread_index ();
1544  snat_main_per_thread_data_t *per_thread_data =
1545  &sm->per_thread_data[thread_index];
1546  u32 *fragments_to_drop = 0;
1547  u32 *fragments_to_loopback = 0;
1548 
1549  from = vlib_frame_vector_args (frame);
1550  n_left_from = frame->n_vectors;
1551  next_index = node->cached_next_index;
1552 
1553  while (n_left_from > 0)
1554  {
1555  u32 n_left_to_next;
1556 
1557  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1558 
1559  while (n_left_from > 0 && n_left_to_next > 0)
1560  {
1561  u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1562  vlib_buffer_t *b0;
1563  u32 next0;
1564  u8 cached0 = 0;
1565  ip4_header_t *ip0;
1566  nat_reass_ip4_t *reass0;
1567  udp_header_t * udp0;
1568  tcp_header_t * tcp0;
1569  snat_session_key_t key0, sm0;
1570  clib_bihash_kv_8_8_t kv0, value0;
1571  snat_session_t * s0 = 0;
1572  u16 old_port0, new_port0;
1573  ip_csum_t sum0;
1574 
1575  /* speculatively enqueue b0 to the current next frame */
1576  bi0 = from[0];
1577  to_next[0] = bi0;
1578  from += 1;
1579  to_next += 1;
1580  n_left_from -= 1;
1581  n_left_to_next -= 1;
1582 
1583  b0 = vlib_get_buffer (vm, bi0);
1584  next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1585 
1586  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1588  sw_if_index0);
1589 
1591  {
1592  next0 = SNAT_OUT2IN_NEXT_DROP;
1593  b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
1594  goto trace0;
1595  }
1596 
1597  ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1598  udp0 = ip4_next_header (ip0);
1599  tcp0 = (tcp_header_t *) udp0;
1600  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1601 
1603  ip0->dst_address,
1604  ip0->fragment_id,
1605  ip0->protocol,
1606  1,
1607  &fragments_to_drop);
1608 
1609  if (PREDICT_FALSE (!reass0))
1610  {
1611  next0 = SNAT_OUT2IN_NEXT_DROP;
1612  b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
1613  goto trace0;
1614  }
1615 
1617  {
1618  key0.addr = ip0->dst_address;
1619  key0.port = udp0->dst_port;
1620  key0.protocol = proto0;
1621  key0.fib_index = rx_fib_index0;
1622  kv0.key = key0.as_u64;
1623 
1624  if (clib_bihash_search_8_8 (&per_thread_data->out2in, &kv0, &value0))
1625  {
1626  /* Try to match static mapping by external address and port,
1627  destination address and port in packet */
1628  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
1629  {
1630  if (!sm->forwarding_enabled)
1631  {
1632  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1633  /*
1634  * Send DHCP packets to the ipv4 stack, or we won't
1635  * be able to use dhcp client on the outside interface
1636  */
1637  if (proto0 != SNAT_PROTOCOL_UDP
1638  || (udp0->dst_port
1639  != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
1640  next0 = SNAT_OUT2IN_NEXT_DROP;
1641  goto trace0;
1642  }
1643  else
1644  goto trace0;
1645  }
1646 
1647  /* Create session initiated by host from external network */
1648  s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1649  thread_index);
1650  if (!s0)
1651  {
1652  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1653  next0 = SNAT_OUT2IN_NEXT_DROP;
1654  goto trace0;
1655  }
1656  reass0->sess_index = s0 - per_thread_data->sessions;
1657  reass0->thread_index = thread_index;
1658  }
1659  else
1660  {
1661  s0 = pool_elt_at_index (per_thread_data->sessions,
1662  value0.value);
1663  reass0->sess_index = value0.value;
1664  }
1665  nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1666  }
1667  else
1668  {
1669  if (PREDICT_FALSE (reass0->sess_index == (u32) ~0))
1670  {
1671  if (nat_ip4_reass_add_fragment (reass0, bi0))
1672  {
1673  b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
1674  next0 = SNAT_OUT2IN_NEXT_DROP;
1675  goto trace0;
1676  }
1677  cached0 = 1;
1678  goto trace0;
1679  }
1680  s0 = pool_elt_at_index (per_thread_data->sessions,
1681  reass0->sess_index);
1682  }
1683 
1684  old_addr0 = ip0->dst_address.as_u32;
1685  ip0->dst_address = s0->in2out.addr;
1686  new_addr0 = ip0->dst_address.as_u32;
1687  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1688 
1689  sum0 = ip0->checksum;
1690  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1691  ip4_header_t,
1692  dst_address /* changed member */);
1693  ip0->checksum = ip_csum_fold (sum0);
1694 
1696  {
1697  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1698  {
1699  old_port0 = tcp0->dst_port;
1700  tcp0->dst_port = s0->in2out.port;
1701  new_port0 = tcp0->dst_port;
1702 
1703  sum0 = tcp0->checksum;
1704  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1705  ip4_header_t,
1706  dst_address /* changed member */);
1707 
1708  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1709  ip4_header_t /* cheat */,
1710  length /* changed member */);
1711  tcp0->checksum = ip_csum_fold(sum0);
1712  }
1713  else
1714  {
1715  old_port0 = udp0->dst_port;
1716  udp0->dst_port = s0->in2out.port;
1717  udp0->checksum = 0;
1718  }
1719  }
1720 
1721  /* Accounting */
1722  s0->last_heard = now;
1723  s0->total_pkts++;
1724  s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1725  /* Per-user LRU list maintenance */
1726  clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1727  s0->per_user_index);
1728  clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1729  s0->per_user_list_head_index,
1730  s0->per_user_index);
1731 
1732  trace0:
1734  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1735  {
1737  vlib_add_trace (vm, node, b0, sizeof (*t));
1738  t->cached = cached0;
1739  t->sw_if_index = sw_if_index0;
1740  t->next_index = next0;
1741  }
1742 
1743  if (cached0)
1744  {
1745  n_left_to_next++;
1746  to_next--;
1747  }
1748  else
1749  {
1750  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1751 
1752  /* verify speculative enqueue, maybe switch current next frame */
1753  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1754  to_next, n_left_to_next,
1755  bi0, next0);
1756  }
1757 
1758  if (n_left_from == 0 && vec_len (fragments_to_loopback))
1759  {
1760  from = vlib_frame_vector_args (frame);
1761  u32 len = vec_len (fragments_to_loopback);
1762  if (len <= VLIB_FRAME_SIZE)
1763  {
1764  clib_memcpy (from, fragments_to_loopback, sizeof (u32) * len);
1765  n_left_from = len;
1766  vec_reset_length (fragments_to_loopback);
1767  }
1768  else
1769  {
1770  clib_memcpy (from,
1771  fragments_to_loopback + (len - VLIB_FRAME_SIZE),
1772  sizeof (u32) * VLIB_FRAME_SIZE);
1773  n_left_from = VLIB_FRAME_SIZE;
1774  _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1775  }
1776  }
1777  }
1778 
1779  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1780  }
1781 
1783  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1784  pkts_processed);
1785 
1786  nat_send_all_to_node (vm, fragments_to_drop, node,
1787  &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
1789 
1790  vec_free (fragments_to_drop);
1791  vec_free (fragments_to_loopback);
1792  return frame->n_vectors;
1793 }
1794 
1796  .function = nat44_out2in_reass_node_fn,
1797  .name = "nat44-out2in-reass",
1798  .vector_size = sizeof (u32),
1799  .format_trace = format_nat44_out2in_reass_trace,
1800  .type = VLIB_NODE_TYPE_INTERNAL,
1801 
1802  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1803  .error_strings = snat_out2in_error_strings,
1804 
1805  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1806 
1807  /* edit / add dispositions here */
1808  .next_nodes = {
1809  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1810  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1811  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1812  [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1813  },
1814 };
1817 
1818 /**************************/
1819 /*** deterministic mode ***/
1820 /**************************/
1821 static uword
1823  vlib_node_runtime_t * node,
1824  vlib_frame_t * frame)
1825 {
1826  u32 n_left_from, * from, * to_next;
1827  snat_out2in_next_t next_index;
1828  u32 pkts_processed = 0;
1829  snat_main_t * sm = &snat_main;
1830  u32 thread_index = vlib_get_thread_index ();
1831 
1832  from = vlib_frame_vector_args (frame);
1833  n_left_from = frame->n_vectors;
1834  next_index = node->cached_next_index;
1835 
1836  while (n_left_from > 0)
1837  {
1838  u32 n_left_to_next;
1839 
1840  vlib_get_next_frame (vm, node, next_index,
1841  to_next, n_left_to_next);
1842 
1843  while (n_left_from >= 4 && n_left_to_next >= 2)
1844  {
1845  u32 bi0, bi1;
1846  vlib_buffer_t * b0, * b1;
1847  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1848  u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
1849  u32 sw_if_index0, sw_if_index1;
1850  ip4_header_t * ip0, * ip1;
1851  ip_csum_t sum0, sum1;
1852  ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
1853  u16 new_port0, old_port0, old_port1, new_port1;
1854  udp_header_t * udp0, * udp1;
1855  tcp_header_t * tcp0, * tcp1;
1856  u32 proto0, proto1;
1857  snat_det_out_key_t key0, key1;
1858  snat_det_map_t * dm0, * dm1;
1859  snat_det_session_t * ses0 = 0, * ses1 = 0;
1860  u32 rx_fib_index0, rx_fib_index1;
1861  icmp46_header_t * icmp0, * icmp1;
1862 
1863  /* Prefetch next iteration. */
1864  {
1865  vlib_buffer_t * p2, * p3;
1866 
1867  p2 = vlib_get_buffer (vm, from[2]);
1868  p3 = vlib_get_buffer (vm, from[3]);
1869 
1870  vlib_prefetch_buffer_header (p2, LOAD);
1871  vlib_prefetch_buffer_header (p3, LOAD);
1872 
1875  }
1876 
1877  /* speculatively enqueue b0 and b1 to the current next frame */
1878  to_next[0] = bi0 = from[0];
1879  to_next[1] = bi1 = from[1];
1880  from += 2;
1881  to_next += 2;
1882  n_left_from -= 2;
1883  n_left_to_next -= 2;
1884 
1885  b0 = vlib_get_buffer (vm, bi0);
1886  b1 = vlib_get_buffer (vm, bi1);
1887 
1888  ip0 = vlib_buffer_get_current (b0);
1889  udp0 = ip4_next_header (ip0);
1890  tcp0 = (tcp_header_t *) udp0;
1891 
1892  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1893 
1894  if (PREDICT_FALSE(ip0->ttl == 1))
1895  {
1896  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1897  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1898  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1899  0);
1901  goto trace0;
1902  }
1903 
1904  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1905 
1906  if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
1907  {
1908  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
1909  icmp0 = (icmp46_header_t *) udp0;
1910 
1911  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
1912  rx_fib_index0, node, next0, thread_index,
1913  &ses0, &dm0);
1914  goto trace0;
1915  }
1916 
1917  key0.ext_host_addr = ip0->src_address;
1918  key0.ext_host_port = tcp0->src;
1919  key0.out_port = tcp0->dst;
1920 
1921  dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
1922  if (PREDICT_FALSE(!dm0))
1923  {
1924  clib_warning("unknown dst address: %U",
1926  next0 = SNAT_OUT2IN_NEXT_DROP;
1927  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1928  goto trace0;
1929  }
1930 
1931  snat_det_reverse(dm0, &ip0->dst_address,
1932  clib_net_to_host_u16(tcp0->dst), &new_addr0);
1933 
1934  ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
1935  if (PREDICT_FALSE(!ses0))
1936  {
1937  clib_warning("no match src %U:%d dst %U:%d for user %U",
1939  clib_net_to_host_u16 (tcp0->src),
1941  clib_net_to_host_u16 (tcp0->dst),
1942  format_ip4_address, &new_addr0);
1943  next0 = SNAT_OUT2IN_NEXT_DROP;
1944  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1945  goto trace0;
1946  }
1947  new_port0 = ses0->in_port;
1948 
1949  old_addr0 = ip0->dst_address;
1950  ip0->dst_address = new_addr0;
1951  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
1952 
1953  sum0 = ip0->checksum;
1954  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1955  ip4_header_t,
1956  dst_address /* changed member */);
1957  ip0->checksum = ip_csum_fold (sum0);
1958 
1959  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1960  {
1961  if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
1962  ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
1963  else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
1964  snat_det_ses_close(dm0, ses0);
1965 
1966  old_port0 = tcp0->dst;
1967  tcp0->dst = new_port0;
1968 
1969  sum0 = tcp0->checksum;
1970  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1971  ip4_header_t,
1972  dst_address /* changed member */);
1973 
1974  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1975  ip4_header_t /* cheat */,
1976  length /* changed member */);
1977  tcp0->checksum = ip_csum_fold(sum0);
1978  }
1979  else
1980  {
1981  old_port0 = udp0->dst_port;
1982  udp0->dst_port = new_port0;
1983  udp0->checksum = 0;
1984  }
1985 
1986  trace0:
1987 
1989  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1990  {
1991  snat_out2in_trace_t *t =
1992  vlib_add_trace (vm, node, b0, sizeof (*t));
1993  t->sw_if_index = sw_if_index0;
1994  t->next_index = next0;
1995  t->session_index = ~0;
1996  if (ses0)
1997  t->session_index = ses0 - dm0->sessions;
1998  }
1999 
2000  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2001 
2002  b1 = vlib_get_buffer (vm, bi1);
2003 
2004  ip1 = vlib_buffer_get_current (b1);
2005  udp1 = ip4_next_header (ip1);
2006  tcp1 = (tcp_header_t *) udp1;
2007 
2008  sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
2009 
2010  if (PREDICT_FALSE(ip1->ttl == 1))
2011  {
2012  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2013  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
2014  ICMP4_time_exceeded_ttl_exceeded_in_transit,
2015  0);
2017  goto trace1;
2018  }
2019 
2020  proto1 = ip_proto_to_snat_proto (ip1->protocol);
2021 
2022  if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP))
2023  {
2024  rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1);
2025  icmp1 = (icmp46_header_t *) udp1;
2026 
2027  next1 = icmp_out2in(sm, b1, ip1, icmp1, sw_if_index1,
2028  rx_fib_index1, node, next1, thread_index,
2029  &ses1, &dm1);
2030  goto trace1;
2031  }
2032 
2033  key1.ext_host_addr = ip1->src_address;
2034  key1.ext_host_port = tcp1->src;
2035  key1.out_port = tcp1->dst;
2036 
2037  dm1 = snat_det_map_by_out(sm, &ip1->dst_address);
2038  if (PREDICT_FALSE(!dm1))
2039  {
2040  clib_warning("unknown dst address: %U",
2042  next1 = SNAT_OUT2IN_NEXT_DROP;
2043  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2044  goto trace1;
2045  }
2046 
2047  snat_det_reverse(dm1, &ip1->dst_address,
2048  clib_net_to_host_u16(tcp1->dst), &new_addr1);
2049 
2050  ses1 = snat_det_get_ses_by_out (dm1, &new_addr1, key1.as_u64);
2051  if (PREDICT_FALSE(!ses1))
2052  {
2053  clib_warning("no match src %U:%d dst %U:%d for user %U",
2055  clib_net_to_host_u16 (tcp1->src),
2057  clib_net_to_host_u16 (tcp1->dst),
2058  format_ip4_address, &new_addr1);
2059  next1 = SNAT_OUT2IN_NEXT_DROP;
2060  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2061  goto trace1;
2062  }
2063  new_port1 = ses1->in_port;
2064 
2065  old_addr1 = ip1->dst_address;
2066  ip1->dst_address = new_addr1;
2067  vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
2068 
2069  sum1 = ip1->checksum;
2070  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
2071  ip4_header_t,
2072  dst_address /* changed member */);
2073  ip1->checksum = ip_csum_fold (sum1);
2074 
2075  if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
2076  {
2077  if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
2078  ses1->state = SNAT_SESSION_TCP_CLOSE_WAIT;
2079  else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_LAST_ACK)
2080  snat_det_ses_close(dm1, ses1);
2081 
2082  old_port1 = tcp1->dst;
2083  tcp1->dst = new_port1;
2084 
2085  sum1 = tcp1->checksum;
2086  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
2087  ip4_header_t,
2088  dst_address /* changed member */);
2089 
2090  sum1 = ip_csum_update (sum1, old_port1, new_port1,
2091  ip4_header_t /* cheat */,
2092  length /* changed member */);
2093  tcp1->checksum = ip_csum_fold(sum1);
2094  }
2095  else
2096  {
2097  old_port1 = udp1->dst_port;
2098  udp1->dst_port = new_port1;
2099  udp1->checksum = 0;
2100  }
2101 
2102  trace1:
2103 
2105  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
2106  {
2107  snat_out2in_trace_t *t =
2108  vlib_add_trace (vm, node, b1, sizeof (*t));
2109  t->sw_if_index = sw_if_index1;
2110  t->next_index = next1;
2111  t->session_index = ~0;
2112  if (ses1)
2113  t->session_index = ses1 - dm1->sessions;
2114  }
2115 
2116  pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
2117 
2118  /* verify speculative enqueues, maybe switch current next frame */
2119  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2120  to_next, n_left_to_next,
2121  bi0, bi1, next0, next1);
2122  }
2123 
2124  while (n_left_from > 0 && n_left_to_next > 0)
2125  {
2126  u32 bi0;
2127  vlib_buffer_t * b0;
2128  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
2129  u32 sw_if_index0;
2130  ip4_header_t * ip0;
2131  ip_csum_t sum0;
2132  ip4_address_t new_addr0, old_addr0;
2133  u16 new_port0, old_port0;
2134  udp_header_t * udp0;
2135  tcp_header_t * tcp0;
2136  u32 proto0;
2137  snat_det_out_key_t key0;
2138  snat_det_map_t * dm0;
2139  snat_det_session_t * ses0 = 0;
2140  u32 rx_fib_index0;
2141  icmp46_header_t * icmp0;
2142 
2143  /* speculatively enqueue b0 to the current next frame */
2144  bi0 = from[0];
2145  to_next[0] = bi0;
2146  from += 1;
2147  to_next += 1;
2148  n_left_from -= 1;
2149  n_left_to_next -= 1;
2150 
2151  b0 = vlib_get_buffer (vm, bi0);
2152 
2153  ip0 = vlib_buffer_get_current (b0);
2154  udp0 = ip4_next_header (ip0);
2155  tcp0 = (tcp_header_t *) udp0;
2156 
2157  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2158 
2159  if (PREDICT_FALSE(ip0->ttl == 1))
2160  {
2161  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2162  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2163  ICMP4_time_exceeded_ttl_exceeded_in_transit,
2164  0);
2166  goto trace00;
2167  }
2168 
2169  proto0 = ip_proto_to_snat_proto (ip0->protocol);
2170 
2171  if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
2172  {
2173  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2174  icmp0 = (icmp46_header_t *) udp0;
2175 
2176  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2177  rx_fib_index0, node, next0, thread_index,
2178  &ses0, &dm0);
2179  goto trace00;
2180  }
2181 
2182  key0.ext_host_addr = ip0->src_address;
2183  key0.ext_host_port = tcp0->src;
2184  key0.out_port = tcp0->dst;
2185 
2186  dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
2187  if (PREDICT_FALSE(!dm0))
2188  {
2189  clib_warning("unknown dst address: %U",
2191  next0 = SNAT_OUT2IN_NEXT_DROP;
2192  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2193  goto trace00;
2194  }
2195 
2196  snat_det_reverse(dm0, &ip0->dst_address,
2197  clib_net_to_host_u16(tcp0->dst), &new_addr0);
2198 
2199  ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
2200  if (PREDICT_FALSE(!ses0))
2201  {
2202  clib_warning("no match src %U:%d dst %U:%d for user %U",
2204  clib_net_to_host_u16 (tcp0->src),
2206  clib_net_to_host_u16 (tcp0->dst),
2207  format_ip4_address, &new_addr0);
2208  next0 = SNAT_OUT2IN_NEXT_DROP;
2209  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2210  goto trace00;
2211  }
2212  new_port0 = ses0->in_port;
2213 
2214  old_addr0 = ip0->dst_address;
2215  ip0->dst_address = new_addr0;
2216  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
2217 
2218  sum0 = ip0->checksum;
2219  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2220  ip4_header_t,
2221  dst_address /* changed member */);
2222  ip0->checksum = ip_csum_fold (sum0);
2223 
2224  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2225  {
2226  if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
2227  ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
2228  else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
2229  snat_det_ses_close(dm0, ses0);
2230 
2231  old_port0 = tcp0->dst;
2232  tcp0->dst = new_port0;
2233 
2234  sum0 = tcp0->checksum;
2235  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2236  ip4_header_t,
2237  dst_address /* changed member */);
2238 
2239  sum0 = ip_csum_update (sum0, old_port0, new_port0,
2240  ip4_header_t /* cheat */,
2241  length /* changed member */);
2242  tcp0->checksum = ip_csum_fold(sum0);
2243  }
2244  else
2245  {
2246  old_port0 = udp0->dst_port;
2247  udp0->dst_port = new_port0;
2248  udp0->checksum = 0;
2249  }
2250 
2251  trace00:
2252 
2254  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2255  {
2256  snat_out2in_trace_t *t =
2257  vlib_add_trace (vm, node, b0, sizeof (*t));
2258  t->sw_if_index = sw_if_index0;
2259  t->next_index = next0;
2260  t->session_index = ~0;
2261  if (ses0)
2262  t->session_index = ses0 - dm0->sessions;
2263  }
2264 
2265  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2266 
2267  /* verify speculative enqueue, maybe switch current next frame */
2268  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2269  to_next, n_left_to_next,
2270  bi0, next0);
2271  }
2272 
2273  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2274  }
2275 
2277  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
2278  pkts_processed);
2279  return frame->n_vectors;
2280 }
2281 
2283  .function = snat_det_out2in_node_fn,
2284  .name = "nat44-det-out2in",
2285  .vector_size = sizeof (u32),
2286  .format_trace = format_snat_out2in_trace,
2287  .type = VLIB_NODE_TYPE_INTERNAL,
2288 
2289  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2290  .error_strings = snat_out2in_error_strings,
2291 
2292  .runtime_data_bytes = sizeof (snat_runtime_t),
2293 
2294  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
2295 
2296  /* edit / add dispositions here */
2297  .next_nodes = {
2298  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
2299  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2300  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2301  [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
2302  },
2303 };
2305 
2306 /**
2307  * Get address and port values to be used for ICMP packet translation
2308  * and create session if needed
2309  *
2310  * @param[in,out] sm NAT main
2311  * @param[in,out] node NAT node runtime
2312  * @param[in] thread_index thread index
2313  * @param[in,out] b0 buffer containing packet to be translated
2314  * @param[out] p_proto protocol used for matching
2315  * @param[out] p_value address and port after NAT translation
2316  * @param[out] p_dont_translate if packet should not be translated
2317  * @param d optional parameter
2318  * @param e optional parameter
2319  */
2321  u32 thread_index, vlib_buffer_t *b0,
2322  ip4_header_t *ip0, u8 *p_proto,
2323  snat_session_key_t *p_value,
2324  u8 *p_dont_translate, void *d, void *e)
2325 {
2326  icmp46_header_t *icmp0;
2327  u32 sw_if_index0;
2328  u8 protocol;
2329  snat_det_out_key_t key0;
2330  u8 dont_translate = 0;
2331  u32 next0 = ~0;
2332  icmp_echo_header_t *echo0, *inner_echo0 = 0;
2333  ip4_header_t *inner_ip0;
2334  void *l4_header = 0;
2335  icmp46_header_t *inner_icmp0;
2336  snat_det_map_t * dm0 = 0;
2337  ip4_address_t new_addr0 = {{0}};
2338  snat_det_session_t * ses0 = 0;
2339  ip4_address_t out_addr;
2340 
2341  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
2342  echo0 = (icmp_echo_header_t *)(icmp0+1);
2343  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2344 
2345  if (!icmp_is_error_message (icmp0))
2346  {
2347  protocol = SNAT_PROTOCOL_ICMP;
2348  key0.ext_host_addr = ip0->src_address;
2349  key0.ext_host_port = 0;
2350  key0.out_port = echo0->identifier;
2351  out_addr = ip0->dst_address;
2352  }
2353  else
2354  {
2355  inner_ip0 = (ip4_header_t *)(echo0+1);
2356  l4_header = ip4_next_header (inner_ip0);
2357  protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
2358  key0.ext_host_addr = inner_ip0->dst_address;
2359  out_addr = inner_ip0->src_address;
2360  switch (protocol)
2361  {
2362  case SNAT_PROTOCOL_ICMP:
2363  inner_icmp0 = (icmp46_header_t*)l4_header;
2364  inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
2365  key0.ext_host_port = 0;
2366  key0.out_port = inner_echo0->identifier;
2367  break;
2368  case SNAT_PROTOCOL_UDP:
2369  case SNAT_PROTOCOL_TCP:
2370  key0.ext_host_port = ((tcp_udp_header_t*)l4_header)->dst_port;
2371  key0.out_port = ((tcp_udp_header_t*)l4_header)->src_port;
2372  break;
2373  default:
2374  b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
2375  next0 = SNAT_OUT2IN_NEXT_DROP;
2376  goto out;
2377  }
2378  }
2379 
2380  dm0 = snat_det_map_by_out(sm, &out_addr);
2381  if (PREDICT_FALSE(!dm0))
2382  {
2383  /* Don't NAT packet aimed at the intfc address */
2384  if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
2385  ip0->dst_address.as_u32)))
2386  {
2387  dont_translate = 1;
2388  goto out;
2389  }
2390  clib_warning("unknown dst address: %U",
2392  goto out;
2393  }
2394 
2395  snat_det_reverse(dm0, &ip0->dst_address,
2396  clib_net_to_host_u16(key0.out_port), &new_addr0);
2397 
2398  ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
2399  if (PREDICT_FALSE(!ses0))
2400  {
2401  /* Don't NAT packet aimed at the intfc address */
2402  if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
2403  ip0->dst_address.as_u32)))
2404  {
2405  dont_translate = 1;
2406  goto out;
2407  }
2408  clib_warning("no match src %U:%d dst %U:%d for user %U",
2410  clib_net_to_host_u16 (key0.ext_host_port),
2411  format_ip4_address, &out_addr,
2412  clib_net_to_host_u16 (key0.out_port),
2413  format_ip4_address, &new_addr0);
2414  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2415  next0 = SNAT_OUT2IN_NEXT_DROP;
2416  goto out;
2417  }
2418 
2419  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
2420  !icmp_is_error_message (icmp0)))
2421  {
2422  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
2423  next0 = SNAT_OUT2IN_NEXT_DROP;
2424  goto out;
2425  }
2426 
2427  goto out;
2428 
2429 out:
2430  *p_proto = protocol;
2431  if (ses0)
2432  {
2433  p_value->addr = new_addr0;
2434  p_value->fib_index = sm->inside_fib_index;
2435  p_value->port = ses0->in_port;
2436  }
2437  *p_dont_translate = dont_translate;
2438  if (d)
2439  *(snat_det_session_t**)d = ses0;
2440  if (e)
2441  *(snat_det_map_t**)e = dm0;
2442  return next0;
2443 }
2444 
2445 /**********************/
2446 /*** worker handoff ***/
2447 /**********************/
2448 static uword
2450  vlib_node_runtime_t * node,
2451  vlib_frame_t * frame)
2452 {
2453  snat_main_t *sm = &snat_main;
2455  u32 n_left_from, *from, *to_next = 0;
2456  static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
2457  static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
2458  = 0;
2459  vlib_frame_queue_elt_t *hf = 0;
2460  vlib_frame_t *f = 0;
2461  int i;
2462  u32 n_left_to_next_worker = 0, *to_next_worker = 0;
2463  u32 next_worker_index = 0;
2464  u32 current_worker_index = ~0;
2465  u32 thread_index = vlib_get_thread_index ();
2466 
2467  ASSERT (vec_len (sm->workers));
2468 
2469  if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0))
2470  {
2471  vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
2472 
2473  vec_validate_init_empty (congested_handoff_queue_by_worker_index,
2474  sm->first_worker_index + sm->num_workers - 1,
2475  (vlib_frame_queue_t *) (~0));
2476  }
2477 
2478  from = vlib_frame_vector_args (frame);
2479  n_left_from = frame->n_vectors;
2480 
2481  while (n_left_from > 0)
2482  {
2483  u32 bi0;
2484  vlib_buffer_t *b0;
2485  u32 sw_if_index0;
2486  u32 rx_fib_index0;
2487  ip4_header_t * ip0;
2488  u8 do_handoff;
2489 
2490  bi0 = from[0];
2491  from += 1;
2492  n_left_from -= 1;
2493 
2494  b0 = vlib_get_buffer (vm, bi0);
2495 
2496  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
2497  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2498 
2499  ip0 = vlib_buffer_get_current (b0);
2500 
2501  next_worker_index = sm->worker_out2in_cb(ip0, rx_fib_index0);
2502 
2503  if (PREDICT_FALSE (next_worker_index != thread_index))
2504  {
2505  do_handoff = 1;
2506 
2507  if (next_worker_index != current_worker_index)
2508  {
2509  if (hf)
2510  hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
2511 
2513  next_worker_index,
2514  handoff_queue_elt_by_worker_index);
2515 
2516  n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors;
2517  to_next_worker = &hf->buffer_index[hf->n_vectors];
2518  current_worker_index = next_worker_index;
2519  }
2520 
2521  /* enqueue to correct worker thread */
2522  to_next_worker[0] = bi0;
2523  to_next_worker++;
2524  n_left_to_next_worker--;
2525 
2526  if (n_left_to_next_worker == 0)
2527  {
2528  hf->n_vectors = VLIB_FRAME_SIZE;
2530  current_worker_index = ~0;
2531  handoff_queue_elt_by_worker_index[next_worker_index] = 0;
2532  hf = 0;
2533  }
2534  }
2535  else
2536  {
2537  do_handoff = 0;
2538  /* if this is 1st frame */
2539  if (!f)
2540  {
2542  to_next = vlib_frame_vector_args (f);
2543  }
2544 
2545  to_next[0] = bi0;
2546  to_next += 1;
2547  f->n_vectors++;
2548  }
2549 
2551  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2552  {
2554  vlib_add_trace (vm, node, b0, sizeof (*t));
2555  t->next_worker_index = next_worker_index;
2556  t->do_handoff = do_handoff;
2557  }
2558  }
2559 
2560  if (f)
2562 
2563  if (hf)
2564  hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
2565 
2566  /* Ship frames to the worker nodes */
2567  for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++)
2568  {
2569  if (handoff_queue_elt_by_worker_index[i])
2570  {
2571  hf = handoff_queue_elt_by_worker_index[i];
2572  /*
2573  * It works better to let the handoff node
2574  * rate-adapt, always ship the handoff queue element.
2575  */
2576  if (1 || hf->n_vectors == hf->last_n_vectors)
2577  {
2579  handoff_queue_elt_by_worker_index[i] = 0;
2580  }
2581  else
2582  hf->last_n_vectors = hf->n_vectors;
2583  }
2584  congested_handoff_queue_by_worker_index[i] =
2585  (vlib_frame_queue_t *) (~0);
2586  }
2587  hf = 0;
2588  current_worker_index = ~0;
2589  return frame->n_vectors;
2590 }
2591 
2593  .function = snat_out2in_worker_handoff_fn,
2594  .name = "nat44-out2in-worker-handoff",
2595  .vector_size = sizeof (u32),
2597  .type = VLIB_NODE_TYPE_INTERNAL,
2598 
2599  .n_next_nodes = 1,
2600 
2601  .next_nodes = {
2602  [0] = "error-drop",
2603  },
2604 };
2605 
2607 
2608 static uword
2610  vlib_node_runtime_t * node,
2611  vlib_frame_t * frame)
2612 {
2613  u32 n_left_from, * from, * to_next;
2614  snat_out2in_next_t next_index;
2615  u32 pkts_processed = 0;
2616  snat_main_t * sm = &snat_main;
2617 
2618  from = vlib_frame_vector_args (frame);
2619  n_left_from = frame->n_vectors;
2620  next_index = node->cached_next_index;
2621 
2622  while (n_left_from > 0)
2623  {
2624  u32 n_left_to_next;
2625 
2626  vlib_get_next_frame (vm, node, next_index,
2627  to_next, n_left_to_next);
2628 
2629  while (n_left_from > 0 && n_left_to_next > 0)
2630  {
2631  u32 bi0;
2632  vlib_buffer_t * b0;
2633  u32 next0 = SNAT_OUT2IN_NEXT_DROP;
2634  u32 sw_if_index0;
2635  ip4_header_t * ip0;
2636  ip_csum_t sum0;
2637  u32 new_addr0, old_addr0;
2638  u16 new_port0, old_port0;
2639  udp_header_t * udp0;
2640  tcp_header_t * tcp0;
2641  icmp46_header_t * icmp0;
2642  snat_session_key_t key0, sm0;
2643  u32 proto0;
2644  u32 rx_fib_index0;
2645 
2646  /* speculatively enqueue b0 to the current next frame */
2647  bi0 = from[0];
2648  to_next[0] = bi0;
2649  from += 1;
2650  to_next += 1;
2651  n_left_from -= 1;
2652  n_left_to_next -= 1;
2653 
2654  b0 = vlib_get_buffer (vm, bi0);
2655 
2656  ip0 = vlib_buffer_get_current (b0);
2657  udp0 = ip4_next_header (ip0);
2658  tcp0 = (tcp_header_t *) udp0;
2659  icmp0 = (icmp46_header_t *) udp0;
2660 
2661  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2662  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2663 
2664  vnet_feature_next (sw_if_index0, &next0, b0);
2665 
2666  if (PREDICT_FALSE(ip0->ttl == 1))
2667  {
2668  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2669  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2670  ICMP4_time_exceeded_ttl_exceeded_in_transit,
2671  0);
2673  goto trace00;
2674  }
2675 
2676  proto0 = ip_proto_to_snat_proto (ip0->protocol);
2677 
2678  if (PREDICT_FALSE (proto0 == ~0))
2679  goto trace00;
2680 
2681  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2682  {
2683  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2684  rx_fib_index0, node, next0, ~0, 0, 0);
2685  goto trace00;
2686  }
2687 
2688  key0.addr = ip0->dst_address;
2689  key0.port = udp0->dst_port;
2690  key0.fib_index = rx_fib_index0;
2691 
2692  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
2693  {
2694  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2695  goto trace00;
2696  }
2697 
2698  new_addr0 = sm0.addr.as_u32;
2699  new_port0 = sm0.port;
2700  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
2701  old_addr0 = ip0->dst_address.as_u32;
2702  ip0->dst_address.as_u32 = new_addr0;
2703 
2704  sum0 = ip0->checksum;
2705  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2706  ip4_header_t,
2707  dst_address /* changed member */);
2708  ip0->checksum = ip_csum_fold (sum0);
2709 
2710  if (PREDICT_FALSE(new_port0 != udp0->dst_port))
2711  {
2712  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2713  {
2714  old_port0 = tcp0->dst_port;
2715  tcp0->dst_port = new_port0;
2716 
2717  sum0 = tcp0->checksum;
2718  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2719  ip4_header_t,
2720  dst_address /* changed member */);
2721 
2722  sum0 = ip_csum_update (sum0, old_port0, new_port0,
2723  ip4_header_t /* cheat */,
2724  length /* changed member */);
2725  tcp0->checksum = ip_csum_fold(sum0);
2726  }
2727  else
2728  {
2729  old_port0 = udp0->dst_port;
2730  udp0->dst_port = new_port0;
2731  udp0->checksum = 0;
2732  }
2733  }
2734  else
2735  {
2736  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2737  {
2738  sum0 = tcp0->checksum;
2739  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2740  ip4_header_t,
2741  dst_address /* changed member */);
2742 
2743  tcp0->checksum = ip_csum_fold(sum0);
2744  }
2745  }
2746 
2747  trace00:
2748 
2750  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2751  {
2752  snat_out2in_trace_t *t =
2753  vlib_add_trace (vm, node, b0, sizeof (*t));
2754  t->sw_if_index = sw_if_index0;
2755  t->next_index = next0;
2756  }
2757 
2758  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2759 
2760  /* verify speculative enqueue, maybe switch current next frame */
2761  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2762  to_next, n_left_to_next,
2763  bi0, next0);
2764  }
2765 
2766  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2767  }
2768 
2770  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
2771  pkts_processed);
2772  return frame->n_vectors;
2773 }
2774 
2776  .function = snat_out2in_fast_node_fn,
2777  .name = "nat44-out2in-fast",
2778  .vector_size = sizeof (u32),
2779  .format_trace = format_snat_out2in_fast_trace,
2780  .type = VLIB_NODE_TYPE_INTERNAL,
2781 
2782  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2783  .error_strings = snat_out2in_error_strings,
2784 
2785  .runtime_data_bytes = sizeof (snat_runtime_t),
2786 
2787  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
2788 
2789  /* edit / add dispositions here */
2790  .next_nodes = {
2791  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2792  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
2793  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2794  [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
2795  },
2796 };
vlib_node_registration_t snat_out2in_fast_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_fast_node)
Definition: out2in.c:102
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:432
VLIB_NODE_FUNCTION_MULTIARCH(snat_out2in_node, snat_out2in_node_fn)
clib_bihash_16_8_t out2in_ed
Definition: nat.h:289
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
#define CLIB_UNUSED(x)
Definition: clib.h:79
u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: out2in.c:281
u16 ext_host_port
Definition: nat.h:79
u16 out_port
Definition: nat.h:80
ip4_address_t src_address
Definition: ip4_packet.h:164
static u8 * format_snat_out2in_fast_trace(u8 *s, va_list *args)
Definition: out2in.c:57
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 thread_index, snat_session_t **p_s0)
Definition: out2in.c:581
#define PREDICT_TRUE(x)
Definition: clib.h:106
static int ip4_header_bytes(ip4_header_t *i)
Definition: ip4_packet.h:227
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:224
u32 fib_table_get_index_for_sw_if_index(fib_protocol_t proto, u32 sw_if_index)
Get the index of the FIB bound to the interface.
Definition: fib_table.c:931
int nat_ip4_reass_add_fragment(nat_reass_ip4_t *reass, u32 bi)
Cache fragment.
Definition: nat_reass.c:321
u16 port_per_thread
Definition: nat.h:301
u32 nstaticsessions
Definition: nat.h:173
static void snat_det_ses_close(snat_det_map_t *dm, snat_det_session_t *ses)
Definition: nat_det.h:179
struct _vlib_node_registration vlib_node_registration_t
u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: out2in.c:2320
uword ip_csum_t
Definition: ip_packet.h:90
u32 * fib_index_by_sw_if_index
Table index indexed by software interface.
Definition: ip4.h:111
static snat_session_t * snat_out2in_lb(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index, u32 thread_index, f64 now, vlib_main_t *vm, vlib_node_runtime_t *node)
Definition: out2in.c:731
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
clib_bihash_16_8_t in2out_ed
Definition: nat.h:290
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, u8 *twice_nat)
Match NAT44 static mapping.
Definition: nat.c:1743
u32 buffer_index[VLIB_FRAME_SIZE]
Definition: threads.h:98
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:415
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:107
dlist_elt_t * list_pool
Definition: nat.h:259
struct _tcp_header tcp_header_t
static void snat_det_reverse(snat_det_map_t *dm, ip4_address_t *out_addr, u16 out_port, ip4_address_t *in_addr)
Definition: nat_det.h:90
u32 proto
Definition: nat.h:64
static snat_session_t * snat_out2in_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index, u32 thread_index, f64 now, vlib_main_t *vm, vlib_node_runtime_t *node)
Definition: out2in.c:612
u16 l_port
Definition: nat.h:66
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
u16 identifier
Definition: nat.h:474
clib_bihash_8_8_t in2out
Definition: nat.h:247
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:226
format_function_t format_ip4_address
Definition: format.h:79
#define static_always_inline
Definition: clib.h:93
static uword ip4_header_checksum_is_valid(ip4_header_t *i)
Definition: ip4_packet.h:260
vlib_node_registration_t snat_det_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_det_out2in_node)
Definition: out2in.c:104
u16 r_port
Definition: nat.h:67
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: nat.h:78
ip4_address_t dst_address
Definition: ip4_packet.h:164
#define TCP_FLAG_ACK
Definition: fa_node.h:11
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:171
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:182
ip4_main_t * ip4_main
Definition: nat.h:383
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:233
#define foreach_snat_out2in_error
Definition: out2in.c:107
ip4_address_t local_addr
Definition: nat.h:214
static uword nat44_out2in_reass_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:1534
u64 as_u64[2]
Definition: nat.h:69
static uword snat_out2in_worker_handoff_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:2449
static int ip4_is_fragment(ip4_header_t *i)
Definition: ip4_packet.h:205
snat_out2in_next_t
Definition: out2in.c:131
u32 fib_index
Definition: nat.h:64
snat_user_t * nat_user_get_or_create(snat_main_t *sm, ip4_address_t *addr, u32 fib_index, u32 thread_index)
Definition: nat.c:239
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:459
snat_det_session_t * sessions
Definition: nat.h:203
u64 key
the key
Definition: bihash_8_8.h:35
static snat_det_map_t * snat_det_map_by_out(snat_main_t *sm, ip4_address_t *out_addr)
Definition: nat_det.h:60
vlib_main_t * vlib_main
Definition: nat.h:381
static void clib_dlist_addtail(dlist_elt_t *pool, u32 head_index, u32 new_index)
Definition: dlist.h:43
u16 protocol
Definition: nat.h:50
snat_static_mapping_t * static_mappings
Definition: nat.h:314
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:191
u32 inside_fib_index
Definition: nat.h:369
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:195
#define PREDICT_FALSE(x)
Definition: clib.h:105
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 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:502
clib_bihash_8_8_t static_mapping_by_external
Definition: nat.h:311
#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:101
#define SNAT_SESSION_FLAG_UNKNOWN_PROTO
Definition: nat.h:129
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:218
#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:364
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:1158
u32 fq_out2in_index
Definition: nat.h:343
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 thread_index, void *d, void *e)
Definition: out2in.c:458
snat_main_t snat_main
Definition: nat.c:33
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
u64 value
the value
Definition: bihash_8_8.h:36
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 thread_index)
Create session for static mapping.
Definition: out2in.c:154
u16 n_vectors
Definition: node.h:344
clib_bihash_8_8_t out2in
Definition: nat.h:246
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
u8 nat_reass_is_drop_frag(u8 is_ip6)
Get status of virtual fragmentation reassembly.
Definition: nat_reass.c:167
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
vlib_main_t * vm
Definition: buffer.c:283
ip4_address_t l_addr
Definition: nat.h:62
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.c:431
deterministic NAT definitions
#define clib_warning(format, args...)
Definition: error.h:59
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:93
#define clib_memcpy(a, b, c)
Definition: string.h:75
static int ip4_is_first_fragment(ip4_header_t *i)
Definition: ip4_packet.h:212
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: nat.h:48
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:454
static u8 * format_nat44_out2in_reass_trace(u8 *s, va_list *args)
Definition: out2in.c:88
ip4_address_t r_addr
Definition: nat.h:63
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:456
#define ASSERT(truth)
u32 num_workers
Definition: nat.h:295
unsigned int u32
Definition: types.h:88
u32 first_worker_index
Definition: nat.h:296
snat_get_worker_function_t * worker_out2in_cb
Definition: nat.h:300
static u32 ip_proto_to_snat_proto(u8 ip_proto)
Definition: nat.h:479
snat_icmp_match_function_t * icmp_match_out2in_cb
Definition: nat.h:293
#define SNAT_SESSION_FLAG_TWICE_NAT
Definition: nat.h:131
static uword snat_det_out2in_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:1822
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
static void clib_dlist_remove(dlist_elt_t *pool, u32 index)
Definition: dlist.h:99
u32 out2in_node_index
Definition: nat.h:348
vlib_node_registration_t nat44_out2in_reass_node
(constructor) VLIB_REGISTER_NODE (nat44_out2in_reass_node)
Definition: out2in.c:105
snat_address_t * twice_nat_addresses
Definition: nat.h:328
u64 uword
Definition: types.h:112
snat_session_t * nat_session_alloc_or_recycle(snat_main_t *sm, snat_user_t *u, u32 thread_index)
Definition: nat.c:283
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:103
snat_out2in_error_t
Definition: out2in.c:118
int snat_alloc_outside_address_and_port(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u32 *address_indexp, u16 port_per_thread, u32 snat_thread_index)
Definition: nat.c:1831
#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:125
unsigned char u8
Definition: types.h:56
static_always_inline u8 is_interface_addr(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, u32 ip4_addr)
Definition: nat.h:585
u32 * workers
Definition: nat.h:298
snat_main_per_thread_data_t * per_thread_data
Definition: nat.h:305
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
#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:223
static u8 * format_snat_out2in_trace(u8 *s, va_list *args)
Definition: out2in.c:46
nat_reass_ip4_t * nat_ip4_reass_find_or_create(ip4_address_t src, ip4_address_t dst, u16 frag_id, u8 proto, u8 reset_timeout, u32 **bi_to_drop)
Find or create reassembly.
Definition: nat_reass.c:219
static void vlib_put_frame_queue_elt(vlib_frame_queue_elt_t *hf)
Definition: threads.h:432
static uword snat_out2in_fast_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:2609
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: nat_det.h:112
#define vnet_buffer(b)
Definition: buffer.h:326
#define SNAT_SESSION_FLAG_STATIC_MAPPING
Definition: nat.h:128
#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:898
u8 data[0]
Packet data.
Definition: buffer.h:159
u8 forwarding_enabled
Definition: nat.h:354
static_always_inline void nat_send_all_to_node(vlib_main_t *vm, u32 *bi_vector, vlib_node_runtime_t *node, vlib_error_t *error, u32 next)
Definition: nat.h:619
u16 flags
Copy of main node flags.
Definition: node.h:450
#define is_twice_nat_session(s)
Check if NAT session is twice NAT.
Definition: nat.h:450
void nat_ip4_reass_get_frags(nat_reass_ip4_t *reass, u32 **bi)
Get cached fragments.
Definition: nat_reass.c:346
NAT plugin virtual fragmentation reassembly.
#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:481
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:75
static u8 maximum_sessions_exceeded(snat_main_t *sm, u32 thread_index)
Definition: nat.h:610
snat_session_t * sessions
Definition: nat.h:256
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_SESSION_FLAG_LOAD_BALANCING
Definition: nat.h:130
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:145
u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation.
Definition: out2in.c:399
static u8 * format_snat_out2in_worker_handoff_trace(u8 *s, va_list *args)
Definition: out2in.c:68
Definition: defs.h:46
u16 fib_index
Definition: nat.h:50
static_always_inline u8 icmp_is_error_message(icmp46_header_t *icmp)
Definition: nat.h:569