FD.io VPP  v18.01.1-37-g7ea3975
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 (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  goto trace0;
1181  }
1182  else
1183  {
1184  if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
1185  {
1186  next0 = SNAT_OUT2IN_NEXT_IN2OUT;
1187  goto trace0;
1188  }
1189  create_bypass_for_fwd(sm, ip0);
1190  goto trace0;
1191  }
1192  }
1193 
1194  /* Create session initiated by host from external network */
1195  s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1196  thread_index);
1197  if (!s0)
1198  {
1199  next0 = SNAT_OUT2IN_NEXT_DROP;
1200  goto trace0;
1201  }
1202  }
1203  else
1204  {
1205  if (PREDICT_FALSE (value0.value == ~0ULL))
1206  {
1207  s0 = snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index,
1208  now, vm, node);
1209  if (!s0)
1210  next0 = SNAT_OUT2IN_NEXT_DROP;
1211  goto trace0;
1212  }
1213  else
1214  {
1215  s0 = pool_elt_at_index (
1216  sm->per_thread_data[thread_index].sessions,
1217  value0.value);
1218  }
1219  }
1220 
1221  old_addr0 = ip0->dst_address.as_u32;
1222  ip0->dst_address = s0->in2out.addr;
1223  new_addr0 = ip0->dst_address.as_u32;
1224  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1225 
1226  sum0 = ip0->checksum;
1227  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1228  ip4_header_t,
1229  dst_address /* changed member */);
1230  ip0->checksum = ip_csum_fold (sum0);
1231 
1232  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1233  {
1234  old_port0 = tcp0->dst_port;
1235  tcp0->dst_port = s0->in2out.port;
1236  new_port0 = tcp0->dst_port;
1237 
1238  sum0 = tcp0->checksum;
1239  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1240  ip4_header_t,
1241  dst_address /* changed member */);
1242 
1243  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1244  ip4_header_t /* cheat */,
1245  length /* changed member */);
1246  tcp0->checksum = ip_csum_fold(sum0);
1247  }
1248  else
1249  {
1250  old_port0 = udp0->dst_port;
1251  udp0->dst_port = s0->in2out.port;
1252  udp0->checksum = 0;
1253  }
1254 
1255  /* Accounting */
1256  s0->last_heard = now;
1257  s0->total_pkts++;
1258  s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1259  /* Per-user LRU list maintenance */
1260  clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1261  s0->per_user_index);
1262  clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1263  s0->per_user_list_head_index,
1264  s0->per_user_index);
1265  trace0:
1266 
1268  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1269  {
1270  snat_out2in_trace_t *t =
1271  vlib_add_trace (vm, node, b0, sizeof (*t));
1272  t->sw_if_index = sw_if_index0;
1273  t->next_index = next0;
1274  t->session_index = ~0;
1275  if (s0)
1276  t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1277  }
1278 
1279  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1280 
1281 
1282  ip1 = vlib_buffer_get_current (b1);
1283  udp1 = ip4_next_header (ip1);
1284  tcp1 = (tcp_header_t *) udp1;
1285  icmp1 = (icmp46_header_t *) udp1;
1286 
1287  sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1288  rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1289  sw_if_index1);
1290 
1291  if (PREDICT_FALSE(ip1->ttl == 1))
1292  {
1293  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1294  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1295  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1296  0);
1298  goto trace1;
1299  }
1300 
1301  proto1 = ip_proto_to_snat_proto (ip1->protocol);
1302 
1303  if (PREDICT_FALSE (proto1 == ~0))
1304  {
1305  s1 = snat_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1,
1306  thread_index, now, vm, node);
1307  if (!sm->forwarding_enabled)
1308  if (!s1)
1309  next1 = SNAT_OUT2IN_NEXT_DROP;
1310  goto trace1;
1311  }
1312 
1313  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1314  {
1315  next1 = icmp_out2in_slow_path
1316  (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1317  next1, now, thread_index, &s1);
1318  goto trace1;
1319  }
1320 
1321  if (PREDICT_FALSE (ip4_is_fragment (ip1)))
1322  {
1323  next1 = SNAT_OUT2IN_NEXT_REASS;
1324  goto trace1;
1325  }
1326 
1327  key1.addr = ip1->dst_address;
1328  key1.port = udp1->dst_port;
1329  key1.protocol = proto1;
1330  key1.fib_index = rx_fib_index1;
1331 
1332  kv1.key = key1.as_u64;
1333 
1334  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1335  &kv1, &value1))
1336  {
1337  /* Try to match static mapping by external address and port,
1338  destination address and port in packet */
1339  if (snat_static_mapping_match(sm, key1, &sm1, 1, 0, 0))
1340  {
1341  if (!sm->forwarding_enabled)
1342  {
1343  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1344  /*
1345  * Send DHCP packets to the ipv4 stack, or we won't
1346  * be able to use dhcp client on the outside interface
1347  */
1348  if (proto1 != SNAT_PROTOCOL_UDP
1349  || (udp1->dst_port
1350  != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
1351  next1 = SNAT_OUT2IN_NEXT_DROP;
1352  goto trace1;
1353  }
1354  else
1355  {
1356  if (next_src_nat(sm, ip1, proto1, udp1->src_port, thread_index))
1357  {
1358  next1 = SNAT_OUT2IN_NEXT_IN2OUT;
1359  goto trace1;
1360  }
1361  create_bypass_for_fwd(sm, ip1);
1362  goto trace1;
1363  }
1364  }
1365 
1366  /* Create session initiated by host from external network */
1367  s1 = create_session_for_static_mapping(sm, b1, sm1, key1, node,
1368  thread_index);
1369  if (!s1)
1370  {
1371  next1 = SNAT_OUT2IN_NEXT_DROP;
1372  goto trace1;
1373  }
1374  }
1375  else
1376  {
1377  if (PREDICT_FALSE (value1.value == ~0ULL))
1378  {
1379  s1 = snat_out2in_lb(sm, b1, ip1, rx_fib_index1, thread_index,
1380  now, vm, node);
1381  if (!s1)
1382  next1 = SNAT_OUT2IN_NEXT_DROP;
1383  goto trace1;
1384  }
1385  else
1386  {
1387  s1 = pool_elt_at_index (
1388  sm->per_thread_data[thread_index].sessions,
1389  value1.value);
1390  }
1391  }
1392 
1393  old_addr1 = ip1->dst_address.as_u32;
1394  ip1->dst_address = s1->in2out.addr;
1395  new_addr1 = ip1->dst_address.as_u32;
1396  vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1397 
1398  sum1 = ip1->checksum;
1399  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1400  ip4_header_t,
1401  dst_address /* changed member */);
1402  ip1->checksum = ip_csum_fold (sum1);
1403 
1404  if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1405  {
1406  old_port1 = tcp1->dst_port;
1407  tcp1->dst_port = s1->in2out.port;
1408  new_port1 = tcp1->dst_port;
1409 
1410  sum1 = tcp1->checksum;
1411  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1412  ip4_header_t,
1413  dst_address /* changed member */);
1414 
1415  sum1 = ip_csum_update (sum1, old_port1, new_port1,
1416  ip4_header_t /* cheat */,
1417  length /* changed member */);
1418  tcp1->checksum = ip_csum_fold(sum1);
1419  }
1420  else
1421  {
1422  old_port1 = udp1->dst_port;
1423  udp1->dst_port = s1->in2out.port;
1424  udp1->checksum = 0;
1425  }
1426 
1427  /* Accounting */
1428  s1->last_heard = now;
1429  s1->total_pkts++;
1430  s1->total_bytes += vlib_buffer_length_in_chain (vm, b1);
1431  /* Per-user LRU list maintenance */
1432  clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1433  s1->per_user_index);
1434  clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1435  s1->per_user_list_head_index,
1436  s1->per_user_index);
1437  trace1:
1438 
1440  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1441  {
1442  snat_out2in_trace_t *t =
1443  vlib_add_trace (vm, node, b1, sizeof (*t));
1444  t->sw_if_index = sw_if_index1;
1445  t->next_index = next1;
1446  t->session_index = ~0;
1447  if (s1)
1448  t->session_index = s1 - sm->per_thread_data[thread_index].sessions;
1449  }
1450 
1451  pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
1452 
1453  /* verify speculative enqueues, maybe switch current next frame */
1454  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1455  to_next, n_left_to_next,
1456  bi0, bi1, next0, next1);
1457  }
1458 
1459  while (n_left_from > 0 && n_left_to_next > 0)
1460  {
1461  u32 bi0;
1462  vlib_buffer_t * b0;
1463  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1464  u32 sw_if_index0;
1465  ip4_header_t * ip0;
1466  ip_csum_t sum0;
1467  u32 new_addr0, old_addr0;
1468  u16 new_port0, old_port0;
1469  udp_header_t * udp0;
1470  tcp_header_t * tcp0;
1471  icmp46_header_t * icmp0;
1472  snat_session_key_t key0, sm0;
1473  u32 rx_fib_index0;
1474  u32 proto0;
1475  snat_session_t * s0 = 0;
1476  clib_bihash_kv_8_8_t kv0, value0;
1477 
1478  /* speculatively enqueue b0 to the current next frame */
1479  bi0 = from[0];
1480  to_next[0] = bi0;
1481  from += 1;
1482  to_next += 1;
1483  n_left_from -= 1;
1484  n_left_to_next -= 1;
1485 
1486  b0 = vlib_get_buffer (vm, bi0);
1487 
1488  vnet_buffer (b0)->snat.flags = 0;
1489 
1490  ip0 = vlib_buffer_get_current (b0);
1491  udp0 = ip4_next_header (ip0);
1492  tcp0 = (tcp_header_t *) udp0;
1493  icmp0 = (icmp46_header_t *) udp0;
1494 
1495  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1496  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1497  sw_if_index0);
1498 
1499  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1500 
1501  if (PREDICT_FALSE (proto0 == ~0))
1502  {
1503  s0 = snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0,
1504  thread_index, now, vm, node);
1505  if (!sm->forwarding_enabled)
1506  if (!s0)
1507  next0 = SNAT_OUT2IN_NEXT_DROP;
1508  goto trace00;
1509  }
1510 
1511  if (PREDICT_FALSE(ip0->ttl == 1))
1512  {
1513  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1514  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1515  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1516  0);
1518  goto trace00;
1519  }
1520 
1521  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1522  {
1523  next0 = icmp_out2in_slow_path
1524  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1525  next0, now, thread_index, &s0);
1526  goto trace00;
1527  }
1528 
1529  if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1530  {
1531  next0 = SNAT_OUT2IN_NEXT_REASS;
1532  goto trace00;
1533  }
1534 
1535  key0.addr = ip0->dst_address;
1536  key0.port = udp0->dst_port;
1537  key0.protocol = proto0;
1538  key0.fib_index = rx_fib_index0;
1539 
1540  kv0.key = key0.as_u64;
1541 
1542  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1543  &kv0, &value0))
1544  {
1545  /* Try to match static mapping by external address and port,
1546  destination address and port in packet */
1547  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
1548  {
1549  if (!sm->forwarding_enabled)
1550  {
1551  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1552  /*
1553  * Send DHCP packets to the ipv4 stack, or we won't
1554  * be able to use dhcp client on the outside interface
1555  */
1556  if (proto0 != SNAT_PROTOCOL_UDP
1557  || (udp0->dst_port
1558  != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
1559  next0 = SNAT_OUT2IN_NEXT_DROP;
1560  goto trace00;
1561  }
1562  else
1563  {
1564  if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
1565  {
1566  next0 = SNAT_OUT2IN_NEXT_IN2OUT;
1567  goto trace00;
1568  }
1569  create_bypass_for_fwd(sm, ip0);
1570  goto trace00;
1571  }
1572  }
1573 
1574  /* Create session initiated by host from external network */
1575  s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1576  thread_index);
1577  if (!s0)
1578  {
1579  next0 = SNAT_OUT2IN_NEXT_DROP;
1580  goto trace00;
1581  }
1582  }
1583  else
1584  {
1585  if (PREDICT_FALSE (value0.value == ~0ULL))
1586  {
1587  s0 = snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index,
1588  now, vm, node);
1589  if (!s0)
1590  next0 = SNAT_OUT2IN_NEXT_DROP;
1591  goto trace00;
1592  }
1593  else
1594  {
1595  s0 = pool_elt_at_index (
1596  sm->per_thread_data[thread_index].sessions,
1597  value0.value);
1598  }
1599  }
1600 
1601  old_addr0 = ip0->dst_address.as_u32;
1602  ip0->dst_address = s0->in2out.addr;
1603  new_addr0 = ip0->dst_address.as_u32;
1604  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1605 
1606  sum0 = ip0->checksum;
1607  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1608  ip4_header_t,
1609  dst_address /* changed member */);
1610  ip0->checksum = ip_csum_fold (sum0);
1611 
1612  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1613  {
1614  old_port0 = tcp0->dst_port;
1615  tcp0->dst_port = s0->in2out.port;
1616  new_port0 = tcp0->dst_port;
1617 
1618  sum0 = tcp0->checksum;
1619  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1620  ip4_header_t,
1621  dst_address /* changed member */);
1622 
1623  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1624  ip4_header_t /* cheat */,
1625  length /* changed member */);
1626  tcp0->checksum = ip_csum_fold(sum0);
1627  }
1628  else
1629  {
1630  old_port0 = udp0->dst_port;
1631  udp0->dst_port = s0->in2out.port;
1632  udp0->checksum = 0;
1633  }
1634 
1635  /* Accounting */
1636  s0->last_heard = now;
1637  s0->total_pkts++;
1638  s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1639  /* Per-user LRU list maintenance */
1640  clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1641  s0->per_user_index);
1642  clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1643  s0->per_user_list_head_index,
1644  s0->per_user_index);
1645  trace00:
1646 
1648  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1649  {
1650  snat_out2in_trace_t *t =
1651  vlib_add_trace (vm, node, b0, sizeof (*t));
1652  t->sw_if_index = sw_if_index0;
1653  t->next_index = next0;
1654  t->session_index = ~0;
1655  if (s0)
1656  t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1657  }
1658 
1659  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1660 
1661  /* verify speculative enqueue, maybe switch current next frame */
1662  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1663  to_next, n_left_to_next,
1664  bi0, next0);
1665  }
1666 
1667  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1668  }
1669 
1671  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1672  pkts_processed);
1673  return frame->n_vectors;
1674 }
1675 
1677  .function = snat_out2in_node_fn,
1678  .name = "nat44-out2in",
1679  .vector_size = sizeof (u32),
1680  .format_trace = format_snat_out2in_trace,
1681  .type = VLIB_NODE_TYPE_INTERNAL,
1682 
1683  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1684  .error_strings = snat_out2in_error_strings,
1685 
1686  .runtime_data_bytes = sizeof (snat_runtime_t),
1687 
1688  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1689 
1690  /* edit / add dispositions here */
1691  .next_nodes = {
1692  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1693  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1694  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1695  [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1696  [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
1697  },
1698 };
1700 
1701 static uword
1703  vlib_node_runtime_t * node,
1704  vlib_frame_t * frame)
1705 {
1706  u32 n_left_from, *from, *to_next;
1707  snat_out2in_next_t next_index;
1708  u32 pkts_processed = 0;
1709  snat_main_t *sm = &snat_main;
1710  f64 now = vlib_time_now (vm);
1711  u32 thread_index = vlib_get_thread_index ();
1712  snat_main_per_thread_data_t *per_thread_data =
1713  &sm->per_thread_data[thread_index];
1714  u32 *fragments_to_drop = 0;
1715  u32 *fragments_to_loopback = 0;
1716 
1717  from = vlib_frame_vector_args (frame);
1718  n_left_from = frame->n_vectors;
1719  next_index = node->cached_next_index;
1720 
1721  while (n_left_from > 0)
1722  {
1723  u32 n_left_to_next;
1724 
1725  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1726 
1727  while (n_left_from > 0 && n_left_to_next > 0)
1728  {
1729  u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1730  vlib_buffer_t *b0;
1731  u32 next0;
1732  u8 cached0 = 0;
1733  ip4_header_t *ip0;
1734  nat_reass_ip4_t *reass0;
1735  udp_header_t * udp0;
1736  tcp_header_t * tcp0;
1737  snat_session_key_t key0, sm0;
1738  clib_bihash_kv_8_8_t kv0, value0;
1739  snat_session_t * s0 = 0;
1740  u16 old_port0, new_port0;
1741  ip_csum_t sum0;
1742 
1743  /* speculatively enqueue b0 to the current next frame */
1744  bi0 = from[0];
1745  to_next[0] = bi0;
1746  from += 1;
1747  to_next += 1;
1748  n_left_from -= 1;
1749  n_left_to_next -= 1;
1750 
1751  b0 = vlib_get_buffer (vm, bi0);
1752  next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1753 
1754  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1756  sw_if_index0);
1757 
1759  {
1760  next0 = SNAT_OUT2IN_NEXT_DROP;
1761  b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
1762  goto trace0;
1763  }
1764 
1765  ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1766  udp0 = ip4_next_header (ip0);
1767  tcp0 = (tcp_header_t *) udp0;
1768  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1769 
1771  ip0->dst_address,
1772  ip0->fragment_id,
1773  ip0->protocol,
1774  1,
1775  &fragments_to_drop);
1776 
1777  if (PREDICT_FALSE (!reass0))
1778  {
1779  next0 = SNAT_OUT2IN_NEXT_DROP;
1780  b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
1781  goto trace0;
1782  }
1783 
1785  {
1786  key0.addr = ip0->dst_address;
1787  key0.port = udp0->dst_port;
1788  key0.protocol = proto0;
1789  key0.fib_index = rx_fib_index0;
1790  kv0.key = key0.as_u64;
1791 
1792  if (clib_bihash_search_8_8 (&per_thread_data->out2in, &kv0, &value0))
1793  {
1794  /* Try to match static mapping by external address and port,
1795  destination address and port in packet */
1796  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
1797  {
1798  if (!sm->forwarding_enabled)
1799  {
1800  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1801  /*
1802  * Send DHCP packets to the ipv4 stack, or we won't
1803  * be able to use dhcp client on the outside interface
1804  */
1805  if (proto0 != SNAT_PROTOCOL_UDP
1806  || (udp0->dst_port
1807  != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
1808  next0 = SNAT_OUT2IN_NEXT_DROP;
1809  goto trace0;
1810  }
1811  else
1812  {
1813  if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
1814  {
1815  next0 = SNAT_OUT2IN_NEXT_IN2OUT;
1816  goto trace0;
1817  }
1818  create_bypass_for_fwd(sm, ip0);
1819  goto trace0;
1820  }
1821  }
1822 
1823  /* Create session initiated by host from external network */
1824  s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1825  thread_index);
1826  if (!s0)
1827  {
1828  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1829  next0 = SNAT_OUT2IN_NEXT_DROP;
1830  goto trace0;
1831  }
1832  reass0->sess_index = s0 - per_thread_data->sessions;
1833  reass0->thread_index = thread_index;
1834  }
1835  else
1836  {
1837  s0 = pool_elt_at_index (per_thread_data->sessions,
1838  value0.value);
1839  reass0->sess_index = value0.value;
1840  }
1841  nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1842  }
1843  else
1844  {
1845  if (PREDICT_FALSE (reass0->sess_index == (u32) ~0))
1846  {
1847  if (nat_ip4_reass_add_fragment (reass0, bi0))
1848  {
1849  b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
1850  next0 = SNAT_OUT2IN_NEXT_DROP;
1851  goto trace0;
1852  }
1853  cached0 = 1;
1854  goto trace0;
1855  }
1856  s0 = pool_elt_at_index (per_thread_data->sessions,
1857  reass0->sess_index);
1858  }
1859 
1860  old_addr0 = ip0->dst_address.as_u32;
1861  ip0->dst_address = s0->in2out.addr;
1862  new_addr0 = ip0->dst_address.as_u32;
1863  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1864 
1865  sum0 = ip0->checksum;
1866  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1867  ip4_header_t,
1868  dst_address /* changed member */);
1869  ip0->checksum = ip_csum_fold (sum0);
1870 
1872  {
1873  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1874  {
1875  old_port0 = tcp0->dst_port;
1876  tcp0->dst_port = s0->in2out.port;
1877  new_port0 = tcp0->dst_port;
1878 
1879  sum0 = tcp0->checksum;
1880  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1881  ip4_header_t,
1882  dst_address /* changed member */);
1883 
1884  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1885  ip4_header_t /* cheat */,
1886  length /* changed member */);
1887  tcp0->checksum = ip_csum_fold(sum0);
1888  }
1889  else
1890  {
1891  old_port0 = udp0->dst_port;
1892  udp0->dst_port = s0->in2out.port;
1893  udp0->checksum = 0;
1894  }
1895  }
1896 
1897  /* Accounting */
1898  s0->last_heard = now;
1899  s0->total_pkts++;
1900  s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1901  /* Per-user LRU list maintenance */
1902  clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1903  s0->per_user_index);
1904  clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1905  s0->per_user_list_head_index,
1906  s0->per_user_index);
1907 
1908  trace0:
1910  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1911  {
1913  vlib_add_trace (vm, node, b0, sizeof (*t));
1914  t->cached = cached0;
1915  t->sw_if_index = sw_if_index0;
1916  t->next_index = next0;
1917  }
1918 
1919  if (cached0)
1920  {
1921  n_left_to_next++;
1922  to_next--;
1923  }
1924  else
1925  {
1926  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1927 
1928  /* verify speculative enqueue, maybe switch current next frame */
1929  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1930  to_next, n_left_to_next,
1931  bi0, next0);
1932  }
1933 
1934  if (n_left_from == 0 && vec_len (fragments_to_loopback))
1935  {
1936  from = vlib_frame_vector_args (frame);
1937  u32 len = vec_len (fragments_to_loopback);
1938  if (len <= VLIB_FRAME_SIZE)
1939  {
1940  clib_memcpy (from, fragments_to_loopback, sizeof (u32) * len);
1941  n_left_from = len;
1942  vec_reset_length (fragments_to_loopback);
1943  }
1944  else
1945  {
1946  clib_memcpy (from,
1947  fragments_to_loopback + (len - VLIB_FRAME_SIZE),
1948  sizeof (u32) * VLIB_FRAME_SIZE);
1949  n_left_from = VLIB_FRAME_SIZE;
1950  _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1951  }
1952  }
1953  }
1954 
1955  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1956  }
1957 
1959  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1960  pkts_processed);
1961 
1962  nat_send_all_to_node (vm, fragments_to_drop, node,
1963  &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
1965 
1966  vec_free (fragments_to_drop);
1967  vec_free (fragments_to_loopback);
1968  return frame->n_vectors;
1969 }
1970 
1972  .function = nat44_out2in_reass_node_fn,
1973  .name = "nat44-out2in-reass",
1974  .vector_size = sizeof (u32),
1975  .format_trace = format_nat44_out2in_reass_trace,
1976  .type = VLIB_NODE_TYPE_INTERNAL,
1977 
1978  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1979  .error_strings = snat_out2in_error_strings,
1980 
1981  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1982 
1983  /* edit / add dispositions here */
1984  .next_nodes = {
1985  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1986  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1987  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1988  [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1989  [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
1990  },
1991 };
1994 
1995 /**************************/
1996 /*** deterministic mode ***/
1997 /**************************/
1998 static uword
2000  vlib_node_runtime_t * node,
2001  vlib_frame_t * frame)
2002 {
2003  u32 n_left_from, * from, * to_next;
2004  snat_out2in_next_t next_index;
2005  u32 pkts_processed = 0;
2006  snat_main_t * sm = &snat_main;
2007  u32 thread_index = vlib_get_thread_index ();
2008 
2009  from = vlib_frame_vector_args (frame);
2010  n_left_from = frame->n_vectors;
2011  next_index = node->cached_next_index;
2012 
2013  while (n_left_from > 0)
2014  {
2015  u32 n_left_to_next;
2016 
2017  vlib_get_next_frame (vm, node, next_index,
2018  to_next, n_left_to_next);
2019 
2020  while (n_left_from >= 4 && n_left_to_next >= 2)
2021  {
2022  u32 bi0, bi1;
2023  vlib_buffer_t * b0, * b1;
2024  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
2025  u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
2026  u32 sw_if_index0, sw_if_index1;
2027  ip4_header_t * ip0, * ip1;
2028  ip_csum_t sum0, sum1;
2029  ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
2030  u16 new_port0, old_port0, old_port1, new_port1;
2031  udp_header_t * udp0, * udp1;
2032  tcp_header_t * tcp0, * tcp1;
2033  u32 proto0, proto1;
2034  snat_det_out_key_t key0, key1;
2035  snat_det_map_t * dm0, * dm1;
2036  snat_det_session_t * ses0 = 0, * ses1 = 0;
2037  u32 rx_fib_index0, rx_fib_index1;
2038  icmp46_header_t * icmp0, * icmp1;
2039 
2040  /* Prefetch next iteration. */
2041  {
2042  vlib_buffer_t * p2, * p3;
2043 
2044  p2 = vlib_get_buffer (vm, from[2]);
2045  p3 = vlib_get_buffer (vm, from[3]);
2046 
2047  vlib_prefetch_buffer_header (p2, LOAD);
2048  vlib_prefetch_buffer_header (p3, LOAD);
2049 
2052  }
2053 
2054  /* speculatively enqueue b0 and b1 to the current next frame */
2055  to_next[0] = bi0 = from[0];
2056  to_next[1] = bi1 = from[1];
2057  from += 2;
2058  to_next += 2;
2059  n_left_from -= 2;
2060  n_left_to_next -= 2;
2061 
2062  b0 = vlib_get_buffer (vm, bi0);
2063  b1 = vlib_get_buffer (vm, bi1);
2064 
2065  ip0 = vlib_buffer_get_current (b0);
2066  udp0 = ip4_next_header (ip0);
2067  tcp0 = (tcp_header_t *) udp0;
2068 
2069  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2070 
2071  if (PREDICT_FALSE(ip0->ttl == 1))
2072  {
2073  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2074  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2075  ICMP4_time_exceeded_ttl_exceeded_in_transit,
2076  0);
2078  goto trace0;
2079  }
2080 
2081  proto0 = ip_proto_to_snat_proto (ip0->protocol);
2082 
2083  if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
2084  {
2085  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2086  icmp0 = (icmp46_header_t *) udp0;
2087 
2088  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2089  rx_fib_index0, node, next0, thread_index,
2090  &ses0, &dm0);
2091  goto trace0;
2092  }
2093 
2094  key0.ext_host_addr = ip0->src_address;
2095  key0.ext_host_port = tcp0->src;
2096  key0.out_port = tcp0->dst;
2097 
2098  dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
2099  if (PREDICT_FALSE(!dm0))
2100  {
2101  clib_warning("unknown dst address: %U",
2103  next0 = SNAT_OUT2IN_NEXT_DROP;
2104  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2105  goto trace0;
2106  }
2107 
2108  snat_det_reverse(dm0, &ip0->dst_address,
2109  clib_net_to_host_u16(tcp0->dst), &new_addr0);
2110 
2111  ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
2112  if (PREDICT_FALSE(!ses0))
2113  {
2114  clib_warning("no match src %U:%d dst %U:%d for user %U",
2116  clib_net_to_host_u16 (tcp0->src),
2118  clib_net_to_host_u16 (tcp0->dst),
2119  format_ip4_address, &new_addr0);
2120  next0 = SNAT_OUT2IN_NEXT_DROP;
2121  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2122  goto trace0;
2123  }
2124  new_port0 = ses0->in_port;
2125 
2126  old_addr0 = ip0->dst_address;
2127  ip0->dst_address = new_addr0;
2128  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
2129 
2130  sum0 = ip0->checksum;
2131  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2132  ip4_header_t,
2133  dst_address /* changed member */);
2134  ip0->checksum = ip_csum_fold (sum0);
2135 
2136  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2137  {
2138  if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
2139  ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
2140  else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
2141  snat_det_ses_close(dm0, ses0);
2142 
2143  old_port0 = tcp0->dst;
2144  tcp0->dst = new_port0;
2145 
2146  sum0 = tcp0->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 
2151  sum0 = ip_csum_update (sum0, old_port0, new_port0,
2152  ip4_header_t /* cheat */,
2153  length /* changed member */);
2154  tcp0->checksum = ip_csum_fold(sum0);
2155  }
2156  else
2157  {
2158  old_port0 = udp0->dst_port;
2159  udp0->dst_port = new_port0;
2160  udp0->checksum = 0;
2161  }
2162 
2163  trace0:
2164 
2166  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2167  {
2168  snat_out2in_trace_t *t =
2169  vlib_add_trace (vm, node, b0, sizeof (*t));
2170  t->sw_if_index = sw_if_index0;
2171  t->next_index = next0;
2172  t->session_index = ~0;
2173  if (ses0)
2174  t->session_index = ses0 - dm0->sessions;
2175  }
2176 
2177  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2178 
2179  b1 = vlib_get_buffer (vm, bi1);
2180 
2181  ip1 = vlib_buffer_get_current (b1);
2182  udp1 = ip4_next_header (ip1);
2183  tcp1 = (tcp_header_t *) udp1;
2184 
2185  sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
2186 
2187  if (PREDICT_FALSE(ip1->ttl == 1))
2188  {
2189  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2190  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
2191  ICMP4_time_exceeded_ttl_exceeded_in_transit,
2192  0);
2194  goto trace1;
2195  }
2196 
2197  proto1 = ip_proto_to_snat_proto (ip1->protocol);
2198 
2199  if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP))
2200  {
2201  rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1);
2202  icmp1 = (icmp46_header_t *) udp1;
2203 
2204  next1 = icmp_out2in(sm, b1, ip1, icmp1, sw_if_index1,
2205  rx_fib_index1, node, next1, thread_index,
2206  &ses1, &dm1);
2207  goto trace1;
2208  }
2209 
2210  key1.ext_host_addr = ip1->src_address;
2211  key1.ext_host_port = tcp1->src;
2212  key1.out_port = tcp1->dst;
2213 
2214  dm1 = snat_det_map_by_out(sm, &ip1->dst_address);
2215  if (PREDICT_FALSE(!dm1))
2216  {
2217  clib_warning("unknown dst address: %U",
2219  next1 = SNAT_OUT2IN_NEXT_DROP;
2220  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2221  goto trace1;
2222  }
2223 
2224  snat_det_reverse(dm1, &ip1->dst_address,
2225  clib_net_to_host_u16(tcp1->dst), &new_addr1);
2226 
2227  ses1 = snat_det_get_ses_by_out (dm1, &new_addr1, key1.as_u64);
2228  if (PREDICT_FALSE(!ses1))
2229  {
2230  clib_warning("no match src %U:%d dst %U:%d for user %U",
2232  clib_net_to_host_u16 (tcp1->src),
2234  clib_net_to_host_u16 (tcp1->dst),
2235  format_ip4_address, &new_addr1);
2236  next1 = SNAT_OUT2IN_NEXT_DROP;
2237  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2238  goto trace1;
2239  }
2240  new_port1 = ses1->in_port;
2241 
2242  old_addr1 = ip1->dst_address;
2243  ip1->dst_address = new_addr1;
2244  vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
2245 
2246  sum1 = ip1->checksum;
2247  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
2248  ip4_header_t,
2249  dst_address /* changed member */);
2250  ip1->checksum = ip_csum_fold (sum1);
2251 
2252  if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
2253  {
2254  if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
2255  ses1->state = SNAT_SESSION_TCP_CLOSE_WAIT;
2256  else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_LAST_ACK)
2257  snat_det_ses_close(dm1, ses1);
2258 
2259  old_port1 = tcp1->dst;
2260  tcp1->dst = new_port1;
2261 
2262  sum1 = tcp1->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 
2267  sum1 = ip_csum_update (sum1, old_port1, new_port1,
2268  ip4_header_t /* cheat */,
2269  length /* changed member */);
2270  tcp1->checksum = ip_csum_fold(sum1);
2271  }
2272  else
2273  {
2274  old_port1 = udp1->dst_port;
2275  udp1->dst_port = new_port1;
2276  udp1->checksum = 0;
2277  }
2278 
2279  trace1:
2280 
2282  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
2283  {
2284  snat_out2in_trace_t *t =
2285  vlib_add_trace (vm, node, b1, sizeof (*t));
2286  t->sw_if_index = sw_if_index1;
2287  t->next_index = next1;
2288  t->session_index = ~0;
2289  if (ses1)
2290  t->session_index = ses1 - dm1->sessions;
2291  }
2292 
2293  pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
2294 
2295  /* verify speculative enqueues, maybe switch current next frame */
2296  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2297  to_next, n_left_to_next,
2298  bi0, bi1, next0, next1);
2299  }
2300 
2301  while (n_left_from > 0 && n_left_to_next > 0)
2302  {
2303  u32 bi0;
2304  vlib_buffer_t * b0;
2305  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
2306  u32 sw_if_index0;
2307  ip4_header_t * ip0;
2308  ip_csum_t sum0;
2309  ip4_address_t new_addr0, old_addr0;
2310  u16 new_port0, old_port0;
2311  udp_header_t * udp0;
2312  tcp_header_t * tcp0;
2313  u32 proto0;
2314  snat_det_out_key_t key0;
2315  snat_det_map_t * dm0;
2316  snat_det_session_t * ses0 = 0;
2317  u32 rx_fib_index0;
2318  icmp46_header_t * icmp0;
2319 
2320  /* speculatively enqueue b0 to the current next frame */
2321  bi0 = from[0];
2322  to_next[0] = bi0;
2323  from += 1;
2324  to_next += 1;
2325  n_left_from -= 1;
2326  n_left_to_next -= 1;
2327 
2328  b0 = vlib_get_buffer (vm, bi0);
2329 
2330  ip0 = vlib_buffer_get_current (b0);
2331  udp0 = ip4_next_header (ip0);
2332  tcp0 = (tcp_header_t *) udp0;
2333 
2334  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2335 
2336  if (PREDICT_FALSE(ip0->ttl == 1))
2337  {
2338  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2339  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2340  ICMP4_time_exceeded_ttl_exceeded_in_transit,
2341  0);
2343  goto trace00;
2344  }
2345 
2346  proto0 = ip_proto_to_snat_proto (ip0->protocol);
2347 
2348  if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
2349  {
2350  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2351  icmp0 = (icmp46_header_t *) udp0;
2352 
2353  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2354  rx_fib_index0, node, next0, thread_index,
2355  &ses0, &dm0);
2356  goto trace00;
2357  }
2358 
2359  key0.ext_host_addr = ip0->src_address;
2360  key0.ext_host_port = tcp0->src;
2361  key0.out_port = tcp0->dst;
2362 
2363  dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
2364  if (PREDICT_FALSE(!dm0))
2365  {
2366  clib_warning("unknown dst address: %U",
2368  next0 = SNAT_OUT2IN_NEXT_DROP;
2369  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2370  goto trace00;
2371  }
2372 
2373  snat_det_reverse(dm0, &ip0->dst_address,
2374  clib_net_to_host_u16(tcp0->dst), &new_addr0);
2375 
2376  ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
2377  if (PREDICT_FALSE(!ses0))
2378  {
2379  clib_warning("no match src %U:%d dst %U:%d for user %U",
2381  clib_net_to_host_u16 (tcp0->src),
2383  clib_net_to_host_u16 (tcp0->dst),
2384  format_ip4_address, &new_addr0);
2385  next0 = SNAT_OUT2IN_NEXT_DROP;
2386  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2387  goto trace00;
2388  }
2389  new_port0 = ses0->in_port;
2390 
2391  old_addr0 = ip0->dst_address;
2392  ip0->dst_address = new_addr0;
2393  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
2394 
2395  sum0 = ip0->checksum;
2396  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2397  ip4_header_t,
2398  dst_address /* changed member */);
2399  ip0->checksum = ip_csum_fold (sum0);
2400 
2401  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2402  {
2403  if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
2404  ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
2405  else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
2406  snat_det_ses_close(dm0, ses0);
2407 
2408  old_port0 = tcp0->dst;
2409  tcp0->dst = new_port0;
2410 
2411  sum0 = tcp0->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 
2416  sum0 = ip_csum_update (sum0, old_port0, new_port0,
2417  ip4_header_t /* cheat */,
2418  length /* changed member */);
2419  tcp0->checksum = ip_csum_fold(sum0);
2420  }
2421  else
2422  {
2423  old_port0 = udp0->dst_port;
2424  udp0->dst_port = new_port0;
2425  udp0->checksum = 0;
2426  }
2427 
2428  trace00:
2429 
2431  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2432  {
2433  snat_out2in_trace_t *t =
2434  vlib_add_trace (vm, node, b0, sizeof (*t));
2435  t->sw_if_index = sw_if_index0;
2436  t->next_index = next0;
2437  t->session_index = ~0;
2438  if (ses0)
2439  t->session_index = ses0 - dm0->sessions;
2440  }
2441 
2442  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2443 
2444  /* verify speculative enqueue, maybe switch current next frame */
2445  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2446  to_next, n_left_to_next,
2447  bi0, next0);
2448  }
2449 
2450  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2451  }
2452 
2454  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
2455  pkts_processed);
2456  return frame->n_vectors;
2457 }
2458 
2460  .function = snat_det_out2in_node_fn,
2461  .name = "nat44-det-out2in",
2462  .vector_size = sizeof (u32),
2463  .format_trace = format_snat_out2in_trace,
2464  .type = VLIB_NODE_TYPE_INTERNAL,
2465 
2466  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2467  .error_strings = snat_out2in_error_strings,
2468 
2469  .runtime_data_bytes = sizeof (snat_runtime_t),
2470 
2471  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
2472 
2473  /* edit / add dispositions here */
2474  .next_nodes = {
2475  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
2476  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2477  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2478  [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
2479  [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
2480  },
2481 };
2483 
2484 /**
2485  * Get address and port values to be used for ICMP packet translation
2486  * and create session if needed
2487  *
2488  * @param[in,out] sm NAT main
2489  * @param[in,out] node NAT node runtime
2490  * @param[in] thread_index thread index
2491  * @param[in,out] b0 buffer containing packet to be translated
2492  * @param[out] p_proto protocol used for matching
2493  * @param[out] p_value address and port after NAT translation
2494  * @param[out] p_dont_translate if packet should not be translated
2495  * @param d optional parameter
2496  * @param e optional parameter
2497  */
2499  u32 thread_index, vlib_buffer_t *b0,
2500  ip4_header_t *ip0, u8 *p_proto,
2501  snat_session_key_t *p_value,
2502  u8 *p_dont_translate, void *d, void *e)
2503 {
2504  icmp46_header_t *icmp0;
2505  u32 sw_if_index0;
2506  u8 protocol;
2507  snat_det_out_key_t key0;
2508  u8 dont_translate = 0;
2509  u32 next0 = ~0;
2510  icmp_echo_header_t *echo0, *inner_echo0 = 0;
2511  ip4_header_t *inner_ip0;
2512  void *l4_header = 0;
2513  icmp46_header_t *inner_icmp0;
2514  snat_det_map_t * dm0 = 0;
2515  ip4_address_t new_addr0 = {{0}};
2516  snat_det_session_t * ses0 = 0;
2517  ip4_address_t out_addr;
2518 
2519  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
2520  echo0 = (icmp_echo_header_t *)(icmp0+1);
2521  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2522 
2523  if (!icmp_is_error_message (icmp0))
2524  {
2525  protocol = SNAT_PROTOCOL_ICMP;
2526  key0.ext_host_addr = ip0->src_address;
2527  key0.ext_host_port = 0;
2528  key0.out_port = echo0->identifier;
2529  out_addr = ip0->dst_address;
2530  }
2531  else
2532  {
2533  inner_ip0 = (ip4_header_t *)(echo0+1);
2534  l4_header = ip4_next_header (inner_ip0);
2535  protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
2536  key0.ext_host_addr = inner_ip0->dst_address;
2537  out_addr = inner_ip0->src_address;
2538  switch (protocol)
2539  {
2540  case SNAT_PROTOCOL_ICMP:
2541  inner_icmp0 = (icmp46_header_t*)l4_header;
2542  inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
2543  key0.ext_host_port = 0;
2544  key0.out_port = inner_echo0->identifier;
2545  break;
2546  case SNAT_PROTOCOL_UDP:
2547  case SNAT_PROTOCOL_TCP:
2548  key0.ext_host_port = ((tcp_udp_header_t*)l4_header)->dst_port;
2549  key0.out_port = ((tcp_udp_header_t*)l4_header)->src_port;
2550  break;
2551  default:
2552  b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
2553  next0 = SNAT_OUT2IN_NEXT_DROP;
2554  goto out;
2555  }
2556  }
2557 
2558  dm0 = snat_det_map_by_out(sm, &out_addr);
2559  if (PREDICT_FALSE(!dm0))
2560  {
2561  /* Don't NAT packet aimed at the intfc address */
2562  if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
2563  ip0->dst_address.as_u32)))
2564  {
2565  dont_translate = 1;
2566  goto out;
2567  }
2568  clib_warning("unknown dst address: %U",
2570  goto out;
2571  }
2572 
2573  snat_det_reverse(dm0, &ip0->dst_address,
2574  clib_net_to_host_u16(key0.out_port), &new_addr0);
2575 
2576  ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
2577  if (PREDICT_FALSE(!ses0))
2578  {
2579  /* Don't NAT packet aimed at the intfc address */
2580  if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
2581  ip0->dst_address.as_u32)))
2582  {
2583  dont_translate = 1;
2584  goto out;
2585  }
2586  clib_warning("no match src %U:%d dst %U:%d for user %U",
2588  clib_net_to_host_u16 (key0.ext_host_port),
2589  format_ip4_address, &out_addr,
2590  clib_net_to_host_u16 (key0.out_port),
2591  format_ip4_address, &new_addr0);
2592  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2593  next0 = SNAT_OUT2IN_NEXT_DROP;
2594  goto out;
2595  }
2596 
2597  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
2598  !icmp_is_error_message (icmp0)))
2599  {
2600  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
2601  next0 = SNAT_OUT2IN_NEXT_DROP;
2602  goto out;
2603  }
2604 
2605  goto out;
2606 
2607 out:
2608  *p_proto = protocol;
2609  if (ses0)
2610  {
2611  p_value->addr = new_addr0;
2612  p_value->fib_index = sm->inside_fib_index;
2613  p_value->port = ses0->in_port;
2614  }
2615  *p_dont_translate = dont_translate;
2616  if (d)
2617  *(snat_det_session_t**)d = ses0;
2618  if (e)
2619  *(snat_det_map_t**)e = dm0;
2620  return next0;
2621 }
2622 
2623 /**********************/
2624 /*** worker handoff ***/
2625 /**********************/
2626 static uword
2628  vlib_node_runtime_t * node,
2629  vlib_frame_t * frame)
2630 {
2631  snat_main_t *sm = &snat_main;
2633  u32 n_left_from, *from, *to_next = 0;
2634  static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
2635  static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
2636  = 0;
2637  vlib_frame_queue_elt_t *hf = 0;
2638  vlib_frame_t *f = 0;
2639  int i;
2640  u32 n_left_to_next_worker = 0, *to_next_worker = 0;
2641  u32 next_worker_index = 0;
2642  u32 current_worker_index = ~0;
2643  u32 thread_index = vlib_get_thread_index ();
2644 
2645  ASSERT (vec_len (sm->workers));
2646 
2647  if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0))
2648  {
2649  vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
2650 
2651  vec_validate_init_empty (congested_handoff_queue_by_worker_index,
2652  sm->first_worker_index + sm->num_workers - 1,
2653  (vlib_frame_queue_t *) (~0));
2654  }
2655 
2656  from = vlib_frame_vector_args (frame);
2657  n_left_from = frame->n_vectors;
2658 
2659  while (n_left_from > 0)
2660  {
2661  u32 bi0;
2662  vlib_buffer_t *b0;
2663  u32 sw_if_index0;
2664  u32 rx_fib_index0;
2665  ip4_header_t * ip0;
2666  u8 do_handoff;
2667 
2668  bi0 = from[0];
2669  from += 1;
2670  n_left_from -= 1;
2671 
2672  b0 = vlib_get_buffer (vm, bi0);
2673 
2674  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
2675  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2676 
2677  ip0 = vlib_buffer_get_current (b0);
2678 
2679  next_worker_index = sm->worker_out2in_cb(ip0, rx_fib_index0);
2680 
2681  if (PREDICT_FALSE (next_worker_index != thread_index))
2682  {
2683  do_handoff = 1;
2684 
2685  if (next_worker_index != current_worker_index)
2686  {
2687  if (hf)
2688  hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
2689 
2691  next_worker_index,
2692  handoff_queue_elt_by_worker_index);
2693 
2694  n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors;
2695  to_next_worker = &hf->buffer_index[hf->n_vectors];
2696  current_worker_index = next_worker_index;
2697  }
2698 
2699  /* enqueue to correct worker thread */
2700  to_next_worker[0] = bi0;
2701  to_next_worker++;
2702  n_left_to_next_worker--;
2703 
2704  if (n_left_to_next_worker == 0)
2705  {
2706  hf->n_vectors = VLIB_FRAME_SIZE;
2708  current_worker_index = ~0;
2709  handoff_queue_elt_by_worker_index[next_worker_index] = 0;
2710  hf = 0;
2711  }
2712  }
2713  else
2714  {
2715  do_handoff = 0;
2716  /* if this is 1st frame */
2717  if (!f)
2718  {
2720  to_next = vlib_frame_vector_args (f);
2721  }
2722 
2723  to_next[0] = bi0;
2724  to_next += 1;
2725  f->n_vectors++;
2726  }
2727 
2729  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2730  {
2732  vlib_add_trace (vm, node, b0, sizeof (*t));
2733  t->next_worker_index = next_worker_index;
2734  t->do_handoff = do_handoff;
2735  }
2736  }
2737 
2738  if (f)
2740 
2741  if (hf)
2742  hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
2743 
2744  /* Ship frames to the worker nodes */
2745  for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++)
2746  {
2747  if (handoff_queue_elt_by_worker_index[i])
2748  {
2749  hf = handoff_queue_elt_by_worker_index[i];
2750  /*
2751  * It works better to let the handoff node
2752  * rate-adapt, always ship the handoff queue element.
2753  */
2754  if (1 || hf->n_vectors == hf->last_n_vectors)
2755  {
2757  handoff_queue_elt_by_worker_index[i] = 0;
2758  }
2759  else
2760  hf->last_n_vectors = hf->n_vectors;
2761  }
2762  congested_handoff_queue_by_worker_index[i] =
2763  (vlib_frame_queue_t *) (~0);
2764  }
2765  hf = 0;
2766  current_worker_index = ~0;
2767  return frame->n_vectors;
2768 }
2769 
2771  .function = snat_out2in_worker_handoff_fn,
2772  .name = "nat44-out2in-worker-handoff",
2773  .vector_size = sizeof (u32),
2775  .type = VLIB_NODE_TYPE_INTERNAL,
2776 
2777  .n_next_nodes = 1,
2778 
2779  .next_nodes = {
2780  [0] = "error-drop",
2781  },
2782 };
2783 
2785 
2786 static uword
2788  vlib_node_runtime_t * node,
2789  vlib_frame_t * frame)
2790 {
2791  u32 n_left_from, * from, * to_next;
2792  snat_out2in_next_t next_index;
2793  u32 pkts_processed = 0;
2794  snat_main_t * sm = &snat_main;
2795 
2796  from = vlib_frame_vector_args (frame);
2797  n_left_from = frame->n_vectors;
2798  next_index = node->cached_next_index;
2799 
2800  while (n_left_from > 0)
2801  {
2802  u32 n_left_to_next;
2803 
2804  vlib_get_next_frame (vm, node, next_index,
2805  to_next, n_left_to_next);
2806 
2807  while (n_left_from > 0 && n_left_to_next > 0)
2808  {
2809  u32 bi0;
2810  vlib_buffer_t * b0;
2811  u32 next0 = SNAT_OUT2IN_NEXT_DROP;
2812  u32 sw_if_index0;
2813  ip4_header_t * ip0;
2814  ip_csum_t sum0;
2815  u32 new_addr0, old_addr0;
2816  u16 new_port0, old_port0;
2817  udp_header_t * udp0;
2818  tcp_header_t * tcp0;
2819  icmp46_header_t * icmp0;
2820  snat_session_key_t key0, sm0;
2821  u32 proto0;
2822  u32 rx_fib_index0;
2823 
2824  /* speculatively enqueue b0 to the current next frame */
2825  bi0 = from[0];
2826  to_next[0] = bi0;
2827  from += 1;
2828  to_next += 1;
2829  n_left_from -= 1;
2830  n_left_to_next -= 1;
2831 
2832  b0 = vlib_get_buffer (vm, bi0);
2833 
2834  ip0 = vlib_buffer_get_current (b0);
2835  udp0 = ip4_next_header (ip0);
2836  tcp0 = (tcp_header_t *) udp0;
2837  icmp0 = (icmp46_header_t *) udp0;
2838 
2839  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2840  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2841 
2842  vnet_feature_next (sw_if_index0, &next0, b0);
2843 
2844  if (PREDICT_FALSE(ip0->ttl == 1))
2845  {
2846  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2847  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2848  ICMP4_time_exceeded_ttl_exceeded_in_transit,
2849  0);
2851  goto trace00;
2852  }
2853 
2854  proto0 = ip_proto_to_snat_proto (ip0->protocol);
2855 
2856  if (PREDICT_FALSE (proto0 == ~0))
2857  goto trace00;
2858 
2859  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2860  {
2861  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2862  rx_fib_index0, node, next0, ~0, 0, 0);
2863  goto trace00;
2864  }
2865 
2866  key0.addr = ip0->dst_address;
2867  key0.port = udp0->dst_port;
2868  key0.fib_index = rx_fib_index0;
2869 
2870  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
2871  {
2872  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2873  goto trace00;
2874  }
2875 
2876  new_addr0 = sm0.addr.as_u32;
2877  new_port0 = sm0.port;
2878  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
2879  old_addr0 = ip0->dst_address.as_u32;
2880  ip0->dst_address.as_u32 = new_addr0;
2881 
2882  sum0 = ip0->checksum;
2883  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2884  ip4_header_t,
2885  dst_address /* changed member */);
2886  ip0->checksum = ip_csum_fold (sum0);
2887 
2888  if (PREDICT_FALSE(new_port0 != udp0->dst_port))
2889  {
2890  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2891  {
2892  old_port0 = tcp0->dst_port;
2893  tcp0->dst_port = new_port0;
2894 
2895  sum0 = tcp0->checksum;
2896  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2897  ip4_header_t,
2898  dst_address /* changed member */);
2899 
2900  sum0 = ip_csum_update (sum0, old_port0, new_port0,
2901  ip4_header_t /* cheat */,
2902  length /* changed member */);
2903  tcp0->checksum = ip_csum_fold(sum0);
2904  }
2905  else
2906  {
2907  old_port0 = udp0->dst_port;
2908  udp0->dst_port = new_port0;
2909  udp0->checksum = 0;
2910  }
2911  }
2912  else
2913  {
2914  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2915  {
2916  sum0 = tcp0->checksum;
2917  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2918  ip4_header_t,
2919  dst_address /* changed member */);
2920 
2921  tcp0->checksum = ip_csum_fold(sum0);
2922  }
2923  }
2924 
2925  trace00:
2926 
2928  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2929  {
2930  snat_out2in_trace_t *t =
2931  vlib_add_trace (vm, node, b0, sizeof (*t));
2932  t->sw_if_index = sw_if_index0;
2933  t->next_index = next0;
2934  }
2935 
2936  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2937 
2938  /* verify speculative enqueue, maybe switch current next frame */
2939  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2940  to_next, n_left_to_next,
2941  bi0, next0);
2942  }
2943 
2944  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2945  }
2946 
2948  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
2949  pkts_processed);
2950  return frame->n_vectors;
2951 }
2952 
2954  .function = snat_out2in_fast_node_fn,
2955  .name = "nat44-out2in-fast",
2956  .vector_size = sizeof (u32),
2957  .format_trace = format_snat_out2in_fast_trace,
2958  .type = VLIB_NODE_TYPE_INTERNAL,
2959 
2960  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2961  .error_strings = snat_out2in_error_strings,
2962 
2963  .runtime_data_bytes = sizeof (snat_runtime_t),
2964 
2965  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
2966 
2967  /* edit / add dispositions here */
2968  .next_nodes = {
2969  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2970  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
2971  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2972  [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
2973  [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
2974  },
2975 };
vlib_node_registration_t snat_out2in_fast_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_fast_node)
Definition: out2in.c:102
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:432
VLIB_NODE_FUNCTION_MULTIARCH(snat_out2in_node, snat_out2in_node_fn)
clib_bihash_16_8_t out2in_ed
Definition: nat.h:289
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
#define CLIB_UNUSED(x)
Definition: clib.h:79
u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: out2in.c: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:224
u32 fib_table_get_index_for_sw_if_index(fib_protocol_t proto, u32 sw_if_index)
Get the index of the FIB bound to the interface.
Definition: fib_table.c:931
int nat_ip4_reass_add_fragment(nat_reass_ip4_t *reass, u32 bi)
Cache fragment.
Definition: nat_reass.c:328
u16 port_per_thread
Definition: nat.h:301
static void snat_det_ses_close(snat_det_map_t *dm, snat_det_session_t *ses)
Definition: nat_det.h:179
struct _vlib_node_registration vlib_node_registration_t
u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: out2in.c:2498
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:290
int snat_static_mapping_match(snat_main_t *sm, snat_session_key_t match, snat_session_key_t *mapping, u8 by_external, u8 *is_addr_only, u8 *twice_nat)
Match NAT44 static mapping.
Definition: nat.c:1785
u32 buffer_index[VLIB_FRAME_SIZE]
Definition: threads.h:98
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:415
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:107
dlist_elt_t * list_pool
Definition: nat.h:259
struct _tcp_header tcp_header_t
static void snat_det_reverse(snat_det_map_t *dm, ip4_address_t *out_addr, u16 out_port, ip4_address_t *in_addr)
Definition: nat_det.h:90
u32 proto
Definition: nat.h:64
static snat_session_t * snat_out2in_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index, u32 thread_index, f64 now, vlib_main_t *vm, vlib_node_runtime_t *node)
Definition: out2in.c: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:474
clib_bihash_8_8_t in2out
Definition: nat.h:247
static void user_session_increment(snat_main_t *sm, snat_user_t *u, u8 is_static)
Definition: nat.h:645
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:226
format_function_t format_ip4_address
Definition: format.h:79
#define static_always_inline
Definition: clib.h:93
static uword ip4_header_checksum_is_valid(ip4_header_t *i)
Definition: ip4_packet.h:260
vlib_node_registration_t snat_det_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_det_out2in_node)
Definition: out2in.c:104
u16 r_port
Definition: nat.h:67
ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_checksum.c:43
ip4_address_t ext_host_addr
Definition: nat.h:78
ip4_address_t dst_address
Definition: ip4_packet.h:164
#define TCP_FLAG_ACK
Definition: fa_node.h:11
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:171
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:182
ip4_main_t * ip4_main
Definition: nat.h:383
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:233
#define foreach_snat_out2in_error
Definition: out2in.c:107
ip4_address_t local_addr
Definition: nat.h:214
static uword nat44_out2in_reass_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:1702
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:2627
static int ip4_is_fragment(ip4_header_t *i)
Definition: ip4_packet.h:205
snat_out2in_next_t
Definition: out2in.c:131
u32 fib_index
Definition: nat.h:64
snat_user_t * nat_user_get_or_create(snat_main_t *sm, ip4_address_t *addr, u32 fib_index, u32 thread_index)
Definition: nat.c:239
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:459
snat_det_session_t * sessions
Definition: nat.h:203
u64 key
the key
Definition: bihash_8_8.h:35
static snat_det_map_t * snat_det_map_by_out(snat_main_t *sm, ip4_address_t *out_addr)
Definition: nat_det.h:60
vlib_main_t * vlib_main
Definition: nat.h:381
static void clib_dlist_addtail(dlist_elt_t *pool, u32 head_index, u32 new_index)
Definition: dlist.h:43
u16 protocol
Definition: nat.h:50
snat_static_mapping_t * static_mappings
Definition: nat.h:314
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:191
u32 inside_fib_index
Definition: nat.h:369
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:195
#define PREDICT_FALSE(x)
Definition: clib.h:105
void snat_ipfix_logging_nat44_ses_create(u32 src_ip, u32 nat_src_ip, snat_protocol_t snat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session create event.
static vlib_frame_queue_elt_t * vlib_get_worker_handoff_queue_elt(u32 frame_queue_index, u32 vlib_worker_index, vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index)
Definition: threads.h:502
clib_bihash_8_8_t static_mapping_by_external
Definition: nat.h:311
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:7
#define VLIB_FRAME_SIZE
Definition: node.h:328
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
vlib_node_registration_t snat_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_node)
Definition: out2in.c:101
#define SNAT_SESSION_FLAG_UNKNOWN_PROTO
Definition: nat.h:129
static_always_inline void vnet_feature_next(u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:221
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:364
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:113
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1158
u32 fq_out2in_index
Definition: nat.h:343
static u32 icmp_out2in(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0, u32 thread_index, void *d, void *e)
Definition: out2in.c:595
snat_main_t snat_main
Definition: nat.c:33
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
u64 value
the value
Definition: bihash_8_8.h:36
static snat_session_t * create_session_for_static_mapping(snat_main_t *sm, vlib_buffer_t *b0, snat_session_key_t in2out, snat_session_key_t out2in, vlib_node_runtime_t *node, u32 thread_index)
Create session for static mapping.
Definition: out2in.c:155
u16 n_vectors
Definition: node.h:344
clib_bihash_8_8_t out2in
Definition: nat.h:246
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
u8 nat_reass_is_drop_frag(u8 is_ip6)
Get status of virtual fragmentation reassembly.
Definition: nat_reass.c:167
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
vlib_main_t * vm
Definition: buffer.c:283
ip4_address_t l_addr
Definition: nat.h:62
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.c:431
deterministic NAT definitions
#define clib_warning(format, args...)
Definition: error.h:59
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:93
#define clib_memcpy(a, b, c)
Definition: string.h:75
static int ip4_is_first_fragment(ip4_header_t *i)
Definition: ip4_packet.h:212
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:33
#define ARRAY_LEN(x)
Definition: clib.h:59
ip4_address_t addr
Definition: nat.h:48
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:454
static u8 * format_nat44_out2in_reass_trace(u8 *s, va_list *args)
Definition: out2in.c:88
ip4_address_t r_addr
Definition: nat.h:63
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:295
unsigned int u32
Definition: types.h:88
u32 first_worker_index
Definition: nat.h:296
snat_get_worker_function_t * worker_out2in_cb
Definition: nat.h:300
static u32 ip_proto_to_snat_proto(u8 ip_proto)
Definition: nat.h:479
snat_icmp_match_function_t * icmp_match_out2in_cb
Definition: nat.h:293
#define SNAT_SESSION_FLAG_TWICE_NAT
Definition: nat.h:131
static uword snat_det_out2in_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:1999
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
static void clib_dlist_remove(dlist_elt_t *pool, u32 index)
Definition: dlist.h:99
u32 out2in_node_index
Definition: nat.h:348
vlib_node_registration_t nat44_out2in_reass_node
(constructor) VLIB_REGISTER_NODE (nat44_out2in_reass_node)
Definition: out2in.c:105
snat_address_t * twice_nat_addresses
Definition: nat.h:328
u64 uword
Definition: types.h:112
snat_session_t * nat_session_alloc_or_recycle(snat_main_t *sm, snat_user_t *u, u32 thread_index)
Definition: nat.c:283
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
#define vec_elt(v, i)
Get vector value at index i.
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
vlib_node_registration_t snat_out2in_worker_handoff_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node)
Definition: out2in.c:103
snat_out2in_error_t
Definition: out2in.c:118
int snat_alloc_outside_address_and_port(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u32 *address_indexp, u16 port_per_thread, u32 snat_thread_index)
Definition: nat.c:1873
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
static char * snat_out2in_error_strings[]
Definition: out2in.c:125
unsigned char u8
Definition: types.h:56
static_always_inline u8 is_interface_addr(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, u32 ip4_addr)
Definition: nat.h:585
u32 * workers
Definition: nat.h:298
snat_main_per_thread_data_t * per_thread_data
Definition: nat.h:305
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:139
static_always_inline snat_out2in_error_t icmp_get_key(ip4_header_t *ip0, snat_session_key_t *p_key0)
Definition: out2in.c: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:219
static void vlib_put_frame_queue_elt(vlib_frame_queue_elt_t *hf)
Definition: threads.h:432
static uword snat_out2in_fast_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:2787
static snat_det_session_t * snat_det_get_ses_by_out(snat_det_map_t *dm, ip4_address_t *in_addr, u64 out_key)
Definition: nat_det.h:112
#define vnet_buffer(b)
Definition: buffer.h:326
#define SNAT_SESSION_FLAG_STATIC_MAPPING
Definition: nat.h:128
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
static uword snat_out2in_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:1038
u8 data[0]
Packet data.
Definition: buffer.h:159
u8 forwarding_enabled
Definition: nat.h:354
static_always_inline void nat_send_all_to_node(vlib_main_t *vm, u32 *bi_vector, vlib_node_runtime_t *node, vlib_error_t *error, u32 next)
Definition: nat.h:619
u16 flags
Copy of main node flags.
Definition: node.h:450
#define is_twice_nat_session(s)
Check if NAT session is twice NAT.
Definition: nat.h:450
void nat_ip4_reass_get_frags(nat_reass_ip4_t *reass, u32 **bi)
Get cached fragments.
Definition: nat_reass.c:353
NAT plugin virtual fragmentation reassembly.
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:481
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:75
static u8 maximum_sessions_exceeded(snat_main_t *sm, u32 thread_index)
Definition: nat.h:610
snat_session_t * sessions
Definition: nat.h:256
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
#define SNAT_SESSION_FLAG_LOAD_BALANCING
Definition: nat.h:130
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:145
u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation.
Definition: out2in.c: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:569