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