FD.io VPP  v18.07.1-19-g511ce25
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 #include <nat/nat_inlines.h>
30 
31 #include <vppinfra/hash.h>
32 #include <vppinfra/error.h>
33 #include <vppinfra/elog.h>
34 
35 typedef struct {
40 
41 typedef struct {
45 
46 /* packet trace format function */
47 static u8 * format_snat_out2in_trace (u8 * s, va_list * args)
48 {
49  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
50  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
51  snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *);
52 
53  s = format (s, "NAT44_OUT2IN: sw_if_index %d, next index %d, session index %d",
55  return s;
56 }
57 
58 static u8 * format_snat_out2in_fast_trace (u8 * s, va_list * args)
59 {
60  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
61  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
62  snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *);
63 
64  s = format (s, "NAT44_OUT2IN_FAST: sw_if_index %d, next index %d",
65  t->sw_if_index, t->next_index);
66  return s;
67 }
68 
69 static u8 * format_snat_out2in_worker_handoff_trace (u8 * s, va_list * args)
70 {
71  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
72  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
74  va_arg (*args, snat_out2in_worker_handoff_trace_t *);
75  char * m;
76 
77  m = t->do_handoff ? "next worker" : "same worker";
78  s = format (s, "NAT44_OUT2IN_WORKER_HANDOFF: %s %d", m, t->next_worker_index);
79 
80  return s;
81 }
82 
83 typedef struct {
88 
89 static u8 * format_nat44_out2in_reass_trace (u8 * s, va_list * args)
90 {
91  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
92  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
94 
95  s = format (s, "NAT44_OUT2IN_REASS: sw_if_index %d, next index %d, status %s",
96  t->sw_if_index, t->next_index,
97  t->cached ? "cached" : "translated");
98 
99  return s;
100 }
101 
109 
110 #define foreach_snat_out2in_error \
111 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
112 _(OUT2IN_PACKETS, "Good out2in packets processed") \
113 _(OUT_OF_PORTS, "Out of ports") \
114 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
115 _(NO_TRANSLATION, "No translation") \
116 _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded") \
117 _(DROP_FRAGMENT, "Drop fragment") \
118 _(MAX_REASS, "Maximum reassemblies exceeded") \
119 _(MAX_FRAG, "Maximum fragments per reassembly exceeded")\
120 _(FQ_CONGESTED, "Handoff frame queue congested")
121 
122 typedef enum {
123 #define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
125 #undef _
128 
129 static char * snat_out2in_error_strings[] = {
130 #define _(sym,string) string,
132 #undef _
133 };
134 
135 typedef enum {
142 
143 /**
144  * @brief Create session for static mapping.
145  *
146  * Create NAT session initiated by host from external network with static
147  * mapping.
148  *
149  * @param sm NAT main.
150  * @param b0 Vlib buffer.
151  * @param in2out In2out NAT44 session key.
152  * @param out2in Out2in NAT44 session key.
153  * @param node Vlib node.
154  *
155  * @returns SNAT session if successfully created otherwise 0.
156  */
157 static inline snat_session_t *
159  vlib_buffer_t *b0,
160  snat_session_key_t in2out,
161  snat_session_key_t out2in,
162  vlib_node_runtime_t * node,
163  u32 thread_index)
164 {
165  snat_user_t *u;
166  snat_session_t *s;
168  ip4_header_t *ip0;
169  udp_header_t *udp0;
170 
171  if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
172  {
173  b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
174  nat_log_notice ("maximum sessions exceeded");
175  return 0;
176  }
177 
178  ip0 = vlib_buffer_get_current (b0);
179  udp0 = ip4_next_header (ip0);
180 
181  u = nat_user_get_or_create (sm, &in2out.addr, in2out.fib_index, thread_index);
182  if (!u)
183  {
184  nat_log_warn ("create NAT user failed");
185  return 0;
186  }
187 
188  s = nat_session_alloc_or_recycle (sm, u, thread_index);
189  if (!s)
190  {
191  nat_log_warn ("create NAT session failed");
192  return 0;
193  }
194 
195  s->outside_address_index = ~0;
197  s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
198  s->ext_host_port = udp0->src_port;
199  user_session_increment (sm, u, 1 /* static */);
200  s->in2out = in2out;
201  s->out2in = out2in;
202  s->in2out.protocol = out2in.protocol;
203 
204  /* Add to translation hashes */
205  kv0.key = s->in2out.as_u64;
206  kv0.value = s - sm->per_thread_data[thread_index].sessions;
207  if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0,
208  1 /* is_add */))
209  nat_log_notice ("in2out key add failed");
210 
211  kv0.key = s->out2in.as_u64;
212 
213  if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
214  1 /* is_add */))
215  nat_log_notice ("out2in key add failed");
216 
217  /* log NAT event */
218  snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32,
219  s->out2in.addr.as_u32,
220  s->in2out.protocol,
221  s->in2out.port,
222  s->out2in.port,
223  s->in2out.fib_index);
224  return s;
225 }
226 
229  snat_session_key_t *p_key0)
230 {
231  icmp46_header_t *icmp0;
232  snat_session_key_t key0;
233  icmp_echo_header_t *echo0, *inner_echo0 = 0;
234  ip4_header_t *inner_ip0;
235  void *l4_header = 0;
236  icmp46_header_t *inner_icmp0;
237 
238  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
239  echo0 = (icmp_echo_header_t *)(icmp0+1);
240 
241  if (!icmp_is_error_message (icmp0))
242  {
243  key0.protocol = SNAT_PROTOCOL_ICMP;
244  key0.addr = ip0->dst_address;
245  key0.port = echo0->identifier;
246  }
247  else
248  {
249  inner_ip0 = (ip4_header_t *)(echo0+1);
250  l4_header = ip4_next_header (inner_ip0);
251  key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
252  key0.addr = inner_ip0->src_address;
253  switch (key0.protocol)
254  {
255  case SNAT_PROTOCOL_ICMP:
256  inner_icmp0 = (icmp46_header_t*)l4_header;
257  inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
258  key0.port = inner_echo0->identifier;
259  break;
260  case SNAT_PROTOCOL_UDP:
261  case SNAT_PROTOCOL_TCP:
262  key0.port = ((tcp_udp_header_t*)l4_header)->src_port;
263  break;
264  default:
265  return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
266  }
267  }
268  *p_key0 = key0;
269  return -1; /* success */
270 }
271 
272 /**
273  * Get address and port values to be used for ICMP packet translation
274  * and create session if needed
275  *
276  * @param[in,out] sm NAT main
277  * @param[in,out] node NAT node runtime
278  * @param[in] thread_index thread index
279  * @param[in,out] b0 buffer containing packet to be translated
280  * @param[out] p_proto protocol used for matching
281  * @param[out] p_value address and port after NAT translation
282  * @param[out] p_dont_translate if packet should not be translated
283  * @param d optional parameter
284  * @param e optional parameter
285  */
287  u32 thread_index, vlib_buffer_t *b0,
288  ip4_header_t *ip0, u8 *p_proto,
289  snat_session_key_t *p_value,
290  u8 *p_dont_translate, void *d, void *e)
291 {
292  icmp46_header_t *icmp0;
293  u32 sw_if_index0;
294  u32 rx_fib_index0;
295  snat_session_key_t key0;
296  snat_session_key_t sm0;
297  snat_session_t *s0 = 0;
298  u8 dont_translate = 0;
299  clib_bihash_kv_8_8_t kv0, value0;
300  u8 is_addr_only;
301  u32 next0 = ~0;
302  int err;
303 
304  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
305  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
306  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
307 
308  key0.protocol = 0;
309 
310  err = icmp_get_key (ip0, &key0);
311  if (err != -1)
312  {
313  b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
314  next0 = SNAT_OUT2IN_NEXT_DROP;
315  goto out;
316  }
317  key0.fib_index = rx_fib_index0;
318 
319  kv0.key = key0.as_u64;
320 
321  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
322  &value0))
323  {
324  /* Try to match static mapping by external address and port,
325  destination address and port in packet */
326  if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0, 0))
327  {
328  if (!sm->forwarding_enabled)
329  {
330  /* Don't NAT packet aimed at the intfc address */
331  if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
332  ip0->dst_address.as_u32)))
333  {
334  dont_translate = 1;
335  goto out;
336  }
337  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
338  next0 = SNAT_OUT2IN_NEXT_DROP;
339  goto out;
340  }
341  else
342  {
343  dont_translate = 1;
344  goto out;
345  }
346  }
347 
348  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
349  (icmp0->type != ICMP4_echo_request || !is_addr_only)))
350  {
351  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
352  next0 = SNAT_OUT2IN_NEXT_DROP;
353  goto out;
354  }
355 
356  /* Create session initiated by host from external network */
357  s0 = create_session_for_static_mapping(sm, b0, sm0, key0,
358  node, thread_index);
359 
360  if (!s0)
361  {
362  next0 = SNAT_OUT2IN_NEXT_DROP;
363  goto out;
364  }
365  }
366  else
367  {
368  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
369  icmp0->type != ICMP4_echo_request &&
370  !icmp_is_error_message (icmp0)))
371  {
372  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
373  next0 = SNAT_OUT2IN_NEXT_DROP;
374  goto out;
375  }
376 
377  s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
378  value0.value);
379  }
380 
381 out:
382  *p_proto = key0.protocol;
383  if (s0)
384  *p_value = s0->in2out;
385  *p_dont_translate = dont_translate;
386  if (d)
387  *(snat_session_t**)d = s0;
388  return next0;
389 }
390 
391 /**
392  * Get address and port values to be used for ICMP packet translation
393  *
394  * @param[in] sm NAT main
395  * @param[in,out] node NAT node runtime
396  * @param[in] thread_index thread index
397  * @param[in,out] b0 buffer containing packet to be translated
398  * @param[out] p_proto protocol used for matching
399  * @param[out] p_value address and port after NAT translation
400  * @param[out] p_dont_translate if packet should not be translated
401  * @param d optional parameter
402  * @param e optional parameter
403  */
405  u32 thread_index, vlib_buffer_t *b0,
406  ip4_header_t *ip0, u8 *p_proto,
407  snat_session_key_t *p_value,
408  u8 *p_dont_translate, void *d, void *e)
409 {
410  icmp46_header_t *icmp0;
411  u32 sw_if_index0;
412  u32 rx_fib_index0;
413  snat_session_key_t key0;
414  snat_session_key_t sm0;
415  u8 dont_translate = 0;
416  u8 is_addr_only;
417  u32 next0 = ~0;
418  int err;
419 
420  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
421  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
422  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
423 
424  err = icmp_get_key (ip0, &key0);
425  if (err != -1)
426  {
427  b0->error = node->errors[err];
428  next0 = SNAT_OUT2IN_NEXT_DROP;
429  goto out2;
430  }
431  key0.fib_index = rx_fib_index0;
432 
433  if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0, 0))
434  {
435  /* Don't NAT packet aimed at the intfc address */
436  if (is_interface_addr(sm, node, sw_if_index0, ip0->dst_address.as_u32))
437  {
438  dont_translate = 1;
439  goto out;
440  }
441  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
442  next0 = SNAT_OUT2IN_NEXT_DROP;
443  goto out;
444  }
445 
446  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
447  (icmp0->type != ICMP4_echo_request || !is_addr_only) &&
448  !icmp_is_error_message (icmp0)))
449  {
450  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
451  next0 = SNAT_OUT2IN_NEXT_DROP;
452  goto out;
453  }
454 
455 out:
456  *p_value = sm0;
457 out2:
458  *p_proto = key0.protocol;
459  *p_dont_translate = dont_translate;
460  return next0;
461 }
462 
463 static inline u32 icmp_out2in (snat_main_t *sm,
464  vlib_buffer_t * b0,
465  ip4_header_t * ip0,
466  icmp46_header_t * icmp0,
467  u32 sw_if_index0,
468  u32 rx_fib_index0,
469  vlib_node_runtime_t * node,
470  u32 next0,
471  u32 thread_index,
472  void *d,
473  void *e)
474 {
475  snat_session_key_t sm0;
476  u8 protocol;
477  icmp_echo_header_t *echo0, *inner_echo0 = 0;
478  ip4_header_t *inner_ip0 = 0;
479  void *l4_header = 0;
480  icmp46_header_t *inner_icmp0;
481  u8 dont_translate;
482  u32 new_addr0, old_addr0;
483  u16 old_id0, new_id0;
484  ip_csum_t sum0;
485  u16 checksum0;
486  u32 next0_tmp;
487 
488  echo0 = (icmp_echo_header_t *)(icmp0+1);
489 
490  next0_tmp = sm->icmp_match_out2in_cb(sm, node, thread_index, b0, ip0,
491  &protocol, &sm0, &dont_translate, d, e);
492  if (next0_tmp != ~0)
493  next0 = next0_tmp;
494  if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
495  goto out;
496 
497  sum0 = ip_incremental_checksum (0, icmp0,
498  ntohs(ip0->length) - ip4_header_bytes (ip0));
499  checksum0 = ~ip_csum_fold (sum0);
500  if (checksum0 != 0 && checksum0 != 0xffff)
501  {
502  next0 = SNAT_OUT2IN_NEXT_DROP;
503  goto out;
504  }
505 
506  old_addr0 = ip0->dst_address.as_u32;
507  new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32;
508  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
509 
510  sum0 = ip0->checksum;
511  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
512  dst_address /* changed member */);
513  ip0->checksum = ip_csum_fold (sum0);
514 
515  if (icmp0->checksum == 0)
516  icmp0->checksum = 0xffff;
517 
518  if (!icmp_is_error_message (icmp0))
519  {
520  new_id0 = sm0.port;
521  if (PREDICT_FALSE(new_id0 != echo0->identifier))
522  {
523  old_id0 = echo0->identifier;
524  new_id0 = sm0.port;
525  echo0->identifier = new_id0;
526 
527  sum0 = icmp0->checksum;
528  sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
529  identifier /* changed member */);
530  icmp0->checksum = ip_csum_fold (sum0);
531  }
532  }
533  else
534  {
535  inner_ip0 = (ip4_header_t *)(echo0+1);
536  l4_header = ip4_next_header (inner_ip0);
537 
538  if (!ip4_header_checksum_is_valid (inner_ip0))
539  {
540  next0 = SNAT_OUT2IN_NEXT_DROP;
541  goto out;
542  }
543 
544  old_addr0 = inner_ip0->src_address.as_u32;
545  inner_ip0->src_address = sm0.addr;
546  new_addr0 = inner_ip0->src_address.as_u32;
547 
548  sum0 = icmp0->checksum;
549  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
550  src_address /* changed member */);
551  icmp0->checksum = ip_csum_fold (sum0);
552 
553  switch (protocol)
554  {
555  case SNAT_PROTOCOL_ICMP:
556  inner_icmp0 = (icmp46_header_t*)l4_header;
557  inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
558 
559  old_id0 = inner_echo0->identifier;
560  new_id0 = sm0.port;
561  inner_echo0->identifier = new_id0;
562 
563  sum0 = icmp0->checksum;
564  sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
565  identifier);
566  icmp0->checksum = ip_csum_fold (sum0);
567  break;
568  case SNAT_PROTOCOL_UDP:
569  case SNAT_PROTOCOL_TCP:
570  old_id0 = ((tcp_udp_header_t*)l4_header)->src_port;
571  new_id0 = sm0.port;
572  ((tcp_udp_header_t*)l4_header)->src_port = new_id0;
573 
574  sum0 = icmp0->checksum;
575  sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
576  src_port);
577  icmp0->checksum = ip_csum_fold (sum0);
578  break;
579  default:
580  ASSERT(0);
581  }
582  }
583 
584 out:
585  return next0;
586 }
587 
588 
590  vlib_buffer_t * b0,
591  ip4_header_t * ip0,
592  icmp46_header_t * icmp0,
593  u32 sw_if_index0,
594  u32 rx_fib_index0,
595  vlib_node_runtime_t * node,
596  u32 next0, f64 now,
597  u32 thread_index,
598  snat_session_t ** p_s0)
599 {
600  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
601  next0, thread_index, p_s0, 0);
602  snat_session_t * s0 = *p_s0;
603  if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0))
604  {
605  /* Accounting */
608  /* Per-user LRU list maintenance */
609  nat44_session_update_lru (sm, s0, thread_index);
610  }
611  return next0;
612 }
613 
614 static int
616  vlib_buffer_t * b,
617  ip4_header_t * ip,
618  u32 rx_fib_index)
619 {
620  clib_bihash_kv_8_8_t kv, value;
622  snat_session_key_t m_key;
623  u32 old_addr, new_addr;
624  ip_csum_t sum;
625 
626  m_key.addr = ip->dst_address;
627  m_key.port = 0;
628  m_key.protocol = 0;
629  m_key.fib_index = 0;
630  kv.key = m_key.as_u64;
631  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
632  return 1;
633 
634  m = pool_elt_at_index (sm->static_mappings, value.value);
635 
636  old_addr = ip->dst_address.as_u32;
637  new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
638  sum = ip->checksum;
639  sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
640  ip->checksum = ip_csum_fold (sum);
641 
642  vnet_buffer(b)->sw_if_index[VLIB_TX] = m->fib_index;
643  return 0;
644 }
645 
646 static uword
648  vlib_node_runtime_t * node,
649  vlib_frame_t * frame)
650 {
651  u32 n_left_from, * from, * to_next;
652  snat_out2in_next_t next_index;
653  u32 pkts_processed = 0;
654  snat_main_t * sm = &snat_main;
655  f64 now = vlib_time_now (vm);
656  u32 thread_index = vm->thread_index;
657 
658  from = vlib_frame_vector_args (frame);
659  n_left_from = frame->n_vectors;
660  next_index = node->cached_next_index;
661 
662  while (n_left_from > 0)
663  {
664  u32 n_left_to_next;
665 
666  vlib_get_next_frame (vm, node, next_index,
667  to_next, n_left_to_next);
668 
669  while (n_left_from >= 4 && n_left_to_next >= 2)
670  {
671  u32 bi0, bi1;
672  vlib_buffer_t * b0, * b1;
675  u32 sw_if_index0, sw_if_index1;
676  ip4_header_t * ip0, *ip1;
677  ip_csum_t sum0, sum1;
678  u32 new_addr0, old_addr0;
679  u16 new_port0, old_port0;
680  u32 new_addr1, old_addr1;
681  u16 new_port1, old_port1;
682  udp_header_t * udp0, * udp1;
683  tcp_header_t * tcp0, * tcp1;
684  icmp46_header_t * icmp0, * icmp1;
685  snat_session_key_t key0, key1, sm0, sm1;
686  u32 rx_fib_index0, rx_fib_index1;
687  u32 proto0, proto1;
688  snat_session_t * s0 = 0, * s1 = 0;
689  clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
690 
691  /* Prefetch next iteration. */
692  {
693  vlib_buffer_t * p2, * p3;
694 
695  p2 = vlib_get_buffer (vm, from[2]);
696  p3 = vlib_get_buffer (vm, from[3]);
697 
698  vlib_prefetch_buffer_header (p2, LOAD);
699  vlib_prefetch_buffer_header (p3, LOAD);
700 
703  }
704 
705  /* speculatively enqueue b0 and b1 to the current next frame */
706  to_next[0] = bi0 = from[0];
707  to_next[1] = bi1 = from[1];
708  from += 2;
709  to_next += 2;
710  n_left_from -= 2;
711  n_left_to_next -= 2;
712 
713  b0 = vlib_get_buffer (vm, bi0);
714  b1 = vlib_get_buffer (vm, bi1);
715 
716  vnet_buffer (b0)->snat.flags = 0;
717  vnet_buffer (b1)->snat.flags = 0;
718 
719  ip0 = vlib_buffer_get_current (b0);
720  udp0 = ip4_next_header (ip0);
721  tcp0 = (tcp_header_t *) udp0;
722  icmp0 = (icmp46_header_t *) udp0;
723 
724  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
725  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
726  sw_if_index0);
727 
728  if (PREDICT_FALSE(ip0->ttl == 1))
729  {
730  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
731  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
732  ICMP4_time_exceeded_ttl_exceeded_in_transit,
733  0);
735  goto trace0;
736  }
737 
738  proto0 = ip_proto_to_snat_proto (ip0->protocol);
739 
740  if (PREDICT_FALSE (proto0 == ~0))
741  {
742  if (nat_out2in_sm_unknown_proto(sm, b0, ip0, rx_fib_index0))
743  {
744  if (!sm->forwarding_enabled)
745  {
746  b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
747  next0 = SNAT_OUT2IN_NEXT_DROP;
748  }
749  }
750  goto trace0;
751  }
752 
753  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
754  {
755  next0 = icmp_out2in_slow_path
756  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
757  next0, now, thread_index, &s0);
758  goto trace0;
759  }
760 
761  if (PREDICT_FALSE (ip4_is_fragment (ip0)))
762  {
763  next0 = SNAT_OUT2IN_NEXT_REASS;
764  goto trace0;
765  }
766 
767  key0.addr = ip0->dst_address;
768  key0.port = udp0->dst_port;
769  key0.protocol = proto0;
770  key0.fib_index = rx_fib_index0;
771 
772  kv0.key = key0.as_u64;
773 
774  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
775  &kv0, &value0))
776  {
777  /* Try to match static mapping by external address and port,
778  destination address and port in packet */
779  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
780  {
781  /*
782  * Send DHCP packets to the ipv4 stack, or we won't
783  * be able to use dhcp client on the outside interface
784  */
785  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
786  && (udp0->dst_port ==
787  clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
788  {
790  (vnet_buffer (b0)->sw_if_index[VLIB_RX], &next0, b0);
791  goto trace0;
792  }
793 
794  if (!sm->forwarding_enabled)
795  {
796  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
797  next0 = SNAT_OUT2IN_NEXT_DROP;
798  }
799  goto trace0;
800  }
801 
802  /* Create session initiated by host from external network */
803  s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
804  thread_index);
805  if (!s0)
806  {
807  next0 = SNAT_OUT2IN_NEXT_DROP;
808  goto trace0;
809  }
810  }
811  else
812  s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
813  value0.value);
814 
815  old_addr0 = ip0->dst_address.as_u32;
816  ip0->dst_address = s0->in2out.addr;
817  new_addr0 = ip0->dst_address.as_u32;
818  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
819 
820  sum0 = ip0->checksum;
821  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
822  ip4_header_t,
823  dst_address /* changed member */);
824  ip0->checksum = ip_csum_fold (sum0);
825 
826  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
827  {
828  old_port0 = tcp0->dst_port;
829  tcp0->dst_port = s0->in2out.port;
830  new_port0 = tcp0->dst_port;
831 
832  sum0 = tcp0->checksum;
833  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
834  ip4_header_t,
835  dst_address /* changed member */);
836 
837  sum0 = ip_csum_update (sum0, old_port0, new_port0,
838  ip4_header_t /* cheat */,
839  length /* changed member */);
840  tcp0->checksum = ip_csum_fold(sum0);
841  }
842  else
843  {
844  old_port0 = udp0->dst_port;
845  udp0->dst_port = s0->in2out.port;
846  udp0->checksum = 0;
847  }
848 
849  /* Accounting */
851  vlib_buffer_length_in_chain (vm, b0));
852  /* Per-user LRU list maintenance */
853  nat44_session_update_lru (sm, s0, thread_index);
854  trace0:
855 
857  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
858  {
860  vlib_add_trace (vm, node, b0, sizeof (*t));
861  t->sw_if_index = sw_if_index0;
862  t->next_index = next0;
863  t->session_index = ~0;
864  if (s0)
865  t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
866  }
867 
868  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
869 
870 
871  ip1 = vlib_buffer_get_current (b1);
872  udp1 = ip4_next_header (ip1);
873  tcp1 = (tcp_header_t *) udp1;
874  icmp1 = (icmp46_header_t *) udp1;
875 
876  sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
877  rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
878  sw_if_index1);
879 
880  if (PREDICT_FALSE(ip1->ttl == 1))
881  {
882  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
883  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
884  ICMP4_time_exceeded_ttl_exceeded_in_transit,
885  0);
887  goto trace1;
888  }
889 
890  proto1 = ip_proto_to_snat_proto (ip1->protocol);
891 
892  if (PREDICT_FALSE (proto1 == ~0))
893  {
894  if (nat_out2in_sm_unknown_proto(sm, b1, ip1, rx_fib_index1))
895  {
896  if (!sm->forwarding_enabled)
897  {
898  b1->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
899  next1 = SNAT_OUT2IN_NEXT_DROP;
900  }
901  }
902  goto trace1;
903  }
904 
905  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
906  {
907  next1 = icmp_out2in_slow_path
908  (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
909  next1, now, thread_index, &s1);
910  goto trace1;
911  }
912 
913  if (PREDICT_FALSE (ip4_is_fragment (ip1)))
914  {
915  next1 = SNAT_OUT2IN_NEXT_REASS;
916  goto trace1;
917  }
918 
919  key1.addr = ip1->dst_address;
920  key1.port = udp1->dst_port;
921  key1.protocol = proto1;
922  key1.fib_index = rx_fib_index1;
923 
924  kv1.key = key1.as_u64;
925 
926  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
927  &kv1, &value1))
928  {
929  /* Try to match static mapping by external address and port,
930  destination address and port in packet */
931  if (snat_static_mapping_match(sm, key1, &sm1, 1, 0, 0, 0))
932  {
933  /*
934  * Send DHCP packets to the ipv4 stack, or we won't
935  * be able to use dhcp client on the outside interface
936  */
937  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_UDP
938  && (udp1->dst_port ==
939  clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
940  {
942  (vnet_buffer (b1)->sw_if_index[VLIB_RX], &next1, b1);
943  goto trace1;
944  }
945 
946  if (!sm->forwarding_enabled)
947  {
948  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
949  next1 = SNAT_OUT2IN_NEXT_DROP;
950  }
951  goto trace1;
952  }
953 
954  /* Create session initiated by host from external network */
955  s1 = create_session_for_static_mapping(sm, b1, sm1, key1, node,
956  thread_index);
957  if (!s1)
958  {
959  next1 = SNAT_OUT2IN_NEXT_DROP;
960  goto trace1;
961  }
962  }
963  else
964  s1 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
965  value1.value);
966 
967  old_addr1 = ip1->dst_address.as_u32;
968  ip1->dst_address = s1->in2out.addr;
969  new_addr1 = ip1->dst_address.as_u32;
970  vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
971 
972  sum1 = ip1->checksum;
973  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
974  ip4_header_t,
975  dst_address /* changed member */);
976  ip1->checksum = ip_csum_fold (sum1);
977 
978  if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
979  {
980  old_port1 = tcp1->dst_port;
981  tcp1->dst_port = s1->in2out.port;
982  new_port1 = tcp1->dst_port;
983 
984  sum1 = tcp1->checksum;
985  sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
986  ip4_header_t,
987  dst_address /* changed member */);
988 
989  sum1 = ip_csum_update (sum1, old_port1, new_port1,
990  ip4_header_t /* cheat */,
991  length /* changed member */);
992  tcp1->checksum = ip_csum_fold(sum1);
993  }
994  else
995  {
996  old_port1 = udp1->dst_port;
997  udp1->dst_port = s1->in2out.port;
998  udp1->checksum = 0;
999  }
1000 
1001  /* Accounting */
1003  vlib_buffer_length_in_chain (vm, b1));
1004  /* Per-user LRU list maintenance */
1005  nat44_session_update_lru (sm, s1, thread_index);
1006  trace1:
1007 
1009  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1010  {
1011  snat_out2in_trace_t *t =
1012  vlib_add_trace (vm, node, b1, sizeof (*t));
1013  t->sw_if_index = sw_if_index1;
1014  t->next_index = next1;
1015  t->session_index = ~0;
1016  if (s1)
1017  t->session_index = s1 - sm->per_thread_data[thread_index].sessions;
1018  }
1019 
1020  pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
1021 
1022  /* verify speculative enqueues, maybe switch current next frame */
1023  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1024  to_next, n_left_to_next,
1025  bi0, bi1, next0, next1);
1026  }
1027 
1028  while (n_left_from > 0 && n_left_to_next > 0)
1029  {
1030  u32 bi0;
1031  vlib_buffer_t * b0;
1032  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1033  u32 sw_if_index0;
1034  ip4_header_t * ip0;
1035  ip_csum_t sum0;
1036  u32 new_addr0, old_addr0;
1037  u16 new_port0, old_port0;
1038  udp_header_t * udp0;
1039  tcp_header_t * tcp0;
1040  icmp46_header_t * icmp0;
1041  snat_session_key_t key0, sm0;
1042  u32 rx_fib_index0;
1043  u32 proto0;
1044  snat_session_t * s0 = 0;
1045  clib_bihash_kv_8_8_t kv0, value0;
1046 
1047  /* speculatively enqueue b0 to the current next frame */
1048  bi0 = from[0];
1049  to_next[0] = bi0;
1050  from += 1;
1051  to_next += 1;
1052  n_left_from -= 1;
1053  n_left_to_next -= 1;
1054 
1055  b0 = vlib_get_buffer (vm, bi0);
1056 
1057  vnet_buffer (b0)->snat.flags = 0;
1058 
1059  ip0 = vlib_buffer_get_current (b0);
1060  udp0 = ip4_next_header (ip0);
1061  tcp0 = (tcp_header_t *) udp0;
1062  icmp0 = (icmp46_header_t *) udp0;
1063 
1064  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1065  rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1066  sw_if_index0);
1067 
1068  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1069 
1070  if (PREDICT_FALSE (proto0 == ~0))
1071  {
1072  if (nat_out2in_sm_unknown_proto(sm, b0, ip0, rx_fib_index0))
1073  {
1074  if (!sm->forwarding_enabled)
1075  {
1076  b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1077  next0 = SNAT_OUT2IN_NEXT_DROP;
1078  }
1079  }
1080  goto trace00;
1081  }
1082 
1083  if (PREDICT_FALSE(ip0->ttl == 1))
1084  {
1085  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1086  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1087  ICMP4_time_exceeded_ttl_exceeded_in_transit,
1088  0);
1090  goto trace00;
1091  }
1092 
1093  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1094  {
1095  next0 = icmp_out2in_slow_path
1096  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1097  next0, now, thread_index, &s0);
1098  goto trace00;
1099  }
1100 
1101  if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1102  {
1103  next0 = SNAT_OUT2IN_NEXT_REASS;
1104  goto trace00;
1105  }
1106 
1107  key0.addr = ip0->dst_address;
1108  key0.port = udp0->dst_port;
1109  key0.protocol = proto0;
1110  key0.fib_index = rx_fib_index0;
1111 
1112  kv0.key = key0.as_u64;
1113 
1114  if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1115  &kv0, &value0))
1116  {
1117  /* Try to match static mapping by external address and port,
1118  destination address and port in packet */
1119  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
1120  {
1121  /*
1122  * Send DHCP packets to the ipv4 stack, or we won't
1123  * be able to use dhcp client on the outside interface
1124  */
1125  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1126  && (udp0->dst_port ==
1127  clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
1128  {
1130  (vnet_buffer (b0)->sw_if_index[VLIB_RX], &next0, b0);
1131  goto trace00;
1132  }
1133 
1134  if (!sm->forwarding_enabled)
1135  {
1136  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1137  next0 = SNAT_OUT2IN_NEXT_DROP;
1138  }
1139  goto trace00;
1140  }
1141 
1142  /* Create session initiated by host from external network */
1143  s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1144  thread_index);
1145  if (!s0)
1146  {
1147  next0 = SNAT_OUT2IN_NEXT_DROP;
1148  goto trace00;
1149  }
1150  }
1151  else
1152  s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1153  value0.value);
1154 
1155  old_addr0 = ip0->dst_address.as_u32;
1156  ip0->dst_address = s0->in2out.addr;
1157  new_addr0 = ip0->dst_address.as_u32;
1158  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1159 
1160  sum0 = ip0->checksum;
1161  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1162  ip4_header_t,
1163  dst_address /* changed member */);
1164  ip0->checksum = ip_csum_fold (sum0);
1165 
1166  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1167  {
1168  old_port0 = tcp0->dst_port;
1169  tcp0->dst_port = s0->in2out.port;
1170  new_port0 = tcp0->dst_port;
1171 
1172  sum0 = tcp0->checksum;
1173  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1174  ip4_header_t,
1175  dst_address /* changed member */);
1176 
1177  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1178  ip4_header_t /* cheat */,
1179  length /* changed member */);
1180  tcp0->checksum = ip_csum_fold(sum0);
1181  }
1182  else
1183  {
1184  old_port0 = udp0->dst_port;
1185  udp0->dst_port = s0->in2out.port;
1186  udp0->checksum = 0;
1187  }
1188 
1189  /* Accounting */
1191  vlib_buffer_length_in_chain (vm, b0));
1192  /* Per-user LRU list maintenance */
1193  nat44_session_update_lru (sm, s0, thread_index);
1194  trace00:
1195 
1197  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1198  {
1199  snat_out2in_trace_t *t =
1200  vlib_add_trace (vm, node, b0, sizeof (*t));
1201  t->sw_if_index = sw_if_index0;
1202  t->next_index = next0;
1203  t->session_index = ~0;
1204  if (s0)
1205  t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1206  }
1207 
1208  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1209 
1210  /* verify speculative enqueue, maybe switch current next frame */
1211  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1212  to_next, n_left_to_next,
1213  bi0, next0);
1214  }
1215 
1216  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1217  }
1218 
1220  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1221  pkts_processed);
1222  return frame->n_vectors;
1223 }
1224 
1226  .function = snat_out2in_node_fn,
1227  .name = "nat44-out2in",
1228  .vector_size = sizeof (u32),
1229  .format_trace = format_snat_out2in_trace,
1230  .type = VLIB_NODE_TYPE_INTERNAL,
1231 
1232  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1233  .error_strings = snat_out2in_error_strings,
1234 
1235  .runtime_data_bytes = sizeof (snat_runtime_t),
1236 
1237  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1238 
1239  /* edit / add dispositions here */
1240  .next_nodes = {
1241  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1242  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1243  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1244  [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1245  },
1246 };
1248 
1249 static uword
1251  vlib_node_runtime_t * node,
1252  vlib_frame_t * frame)
1253 {
1254  u32 n_left_from, *from, *to_next;
1255  snat_out2in_next_t next_index;
1256  u32 pkts_processed = 0;
1257  snat_main_t *sm = &snat_main;
1258  f64 now = vlib_time_now (vm);
1259  u32 thread_index = vm->thread_index;
1260  snat_main_per_thread_data_t *per_thread_data =
1261  &sm->per_thread_data[thread_index];
1262  u32 *fragments_to_drop = 0;
1263  u32 *fragments_to_loopback = 0;
1264 
1265  from = vlib_frame_vector_args (frame);
1266  n_left_from = frame->n_vectors;
1267  next_index = node->cached_next_index;
1268 
1269  while (n_left_from > 0)
1270  {
1271  u32 n_left_to_next;
1272 
1273  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1274 
1275  while (n_left_from > 0 && n_left_to_next > 0)
1276  {
1277  u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1278  vlib_buffer_t *b0;
1279  u32 next0;
1280  u8 cached0 = 0;
1281  ip4_header_t *ip0;
1282  nat_reass_ip4_t *reass0;
1283  udp_header_t * udp0;
1284  tcp_header_t * tcp0;
1285  snat_session_key_t key0, sm0;
1286  clib_bihash_kv_8_8_t kv0, value0;
1287  snat_session_t * s0 = 0;
1288  u16 old_port0, new_port0;
1289  ip_csum_t sum0;
1290 
1291  /* speculatively enqueue b0 to the current next frame */
1292  bi0 = from[0];
1293  to_next[0] = bi0;
1294  from += 1;
1295  to_next += 1;
1296  n_left_from -= 1;
1297  n_left_to_next -= 1;
1298 
1299  b0 = vlib_get_buffer (vm, bi0);
1300  next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1301 
1302  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1304  sw_if_index0);
1305 
1307  {
1308  next0 = SNAT_OUT2IN_NEXT_DROP;
1309  b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
1310  goto trace0;
1311  }
1312 
1313  ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1314  udp0 = ip4_next_header (ip0);
1315  tcp0 = (tcp_header_t *) udp0;
1316  proto0 = ip_proto_to_snat_proto (ip0->protocol);
1317 
1319  ip0->dst_address,
1320  ip0->fragment_id,
1321  ip0->protocol,
1322  1,
1323  &fragments_to_drop);
1324 
1325  if (PREDICT_FALSE (!reass0))
1326  {
1327  next0 = SNAT_OUT2IN_NEXT_DROP;
1328  b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
1329  nat_log_notice ("maximum reassemblies exceeded");
1330  goto trace0;
1331  }
1332 
1334  {
1335  key0.addr = ip0->dst_address;
1336  key0.port = udp0->dst_port;
1337  key0.protocol = proto0;
1338  key0.fib_index = rx_fib_index0;
1339  kv0.key = key0.as_u64;
1340 
1341  if (clib_bihash_search_8_8 (&per_thread_data->out2in, &kv0, &value0))
1342  {
1343  /* Try to match static mapping by external address and port,
1344  destination address and port in packet */
1345  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
1346  {
1347  /*
1348  * Send DHCP packets to the ipv4 stack, or we won't
1349  * be able to use dhcp client on the outside interface
1350  */
1351  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1352  && (udp0->dst_port
1353  == clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
1354  {
1356  (vnet_buffer (b0)->sw_if_index[VLIB_RX],
1357  &next0, b0);
1358  goto trace0;
1359  }
1360 
1361  if (!sm->forwarding_enabled)
1362  {
1363  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1364  next0 = SNAT_OUT2IN_NEXT_DROP;
1365  }
1366  goto trace0;
1367  }
1368 
1369  /* Create session initiated by host from external network */
1370  s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1371  thread_index);
1372  if (!s0)
1373  {
1374  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1375  next0 = SNAT_OUT2IN_NEXT_DROP;
1376  goto trace0;
1377  }
1378  reass0->sess_index = s0 - per_thread_data->sessions;
1379  reass0->thread_index = thread_index;
1380  }
1381  else
1382  {
1383  s0 = pool_elt_at_index (per_thread_data->sessions,
1384  value0.value);
1385  reass0->sess_index = value0.value;
1386  }
1387  nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1388  }
1389  else
1390  {
1391  if (PREDICT_FALSE (reass0->sess_index == (u32) ~0))
1392  {
1393  if (nat_ip4_reass_add_fragment (reass0, bi0, &fragments_to_drop))
1394  {
1395  b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
1396  nat_log_notice ("maximum fragments per reassembly exceeded");
1397  next0 = SNAT_OUT2IN_NEXT_DROP;
1398  goto trace0;
1399  }
1400  cached0 = 1;
1401  goto trace0;
1402  }
1403  s0 = pool_elt_at_index (per_thread_data->sessions,
1404  reass0->sess_index);
1405  }
1406 
1407  old_addr0 = ip0->dst_address.as_u32;
1408  ip0->dst_address = s0->in2out.addr;
1409  new_addr0 = ip0->dst_address.as_u32;
1410  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1411 
1412  sum0 = ip0->checksum;
1413  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1414  ip4_header_t,
1415  dst_address /* changed member */);
1416  ip0->checksum = ip_csum_fold (sum0);
1417 
1419  {
1420  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1421  {
1422  old_port0 = tcp0->dst_port;
1423  tcp0->dst_port = s0->in2out.port;
1424  new_port0 = tcp0->dst_port;
1425 
1426  sum0 = tcp0->checksum;
1427  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1428  ip4_header_t,
1429  dst_address /* changed member */);
1430 
1431  sum0 = ip_csum_update (sum0, old_port0, new_port0,
1432  ip4_header_t /* cheat */,
1433  length /* changed member */);
1434  tcp0->checksum = ip_csum_fold(sum0);
1435  }
1436  else
1437  {
1438  old_port0 = udp0->dst_port;
1439  udp0->dst_port = s0->in2out.port;
1440  udp0->checksum = 0;
1441  }
1442  }
1443 
1444  /* Accounting */
1446  vlib_buffer_length_in_chain (vm, b0));
1447  /* Per-user LRU list maintenance */
1448  nat44_session_update_lru (sm, s0, thread_index);
1449 
1450  trace0:
1452  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1453  {
1455  vlib_add_trace (vm, node, b0, sizeof (*t));
1456  t->cached = cached0;
1457  t->sw_if_index = sw_if_index0;
1458  t->next_index = next0;
1459  }
1460 
1461  if (cached0)
1462  {
1463  n_left_to_next++;
1464  to_next--;
1465  }
1466  else
1467  {
1468  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1469 
1470  /* verify speculative enqueue, maybe switch current next frame */
1471  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1472  to_next, n_left_to_next,
1473  bi0, next0);
1474  }
1475 
1476  if (n_left_from == 0 && vec_len (fragments_to_loopback))
1477  {
1478  from = vlib_frame_vector_args (frame);
1479  u32 len = vec_len (fragments_to_loopback);
1480  if (len <= VLIB_FRAME_SIZE)
1481  {
1482  clib_memcpy (from, fragments_to_loopback, sizeof (u32) * len);
1483  n_left_from = len;
1484  vec_reset_length (fragments_to_loopback);
1485  }
1486  else
1487  {
1488  clib_memcpy (from,
1489  fragments_to_loopback + (len - VLIB_FRAME_SIZE),
1490  sizeof (u32) * VLIB_FRAME_SIZE);
1491  n_left_from = VLIB_FRAME_SIZE;
1492  _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1493  }
1494  }
1495  }
1496 
1497  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1498  }
1499 
1501  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1502  pkts_processed);
1503 
1504  nat_send_all_to_node (vm, fragments_to_drop, node,
1505  &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
1507 
1508  vec_free (fragments_to_drop);
1509  vec_free (fragments_to_loopback);
1510  return frame->n_vectors;
1511 }
1512 
1514  .function = nat44_out2in_reass_node_fn,
1515  .name = "nat44-out2in-reass",
1516  .vector_size = sizeof (u32),
1517  .format_trace = format_nat44_out2in_reass_trace,
1518  .type = VLIB_NODE_TYPE_INTERNAL,
1519 
1520  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1521  .error_strings = snat_out2in_error_strings,
1522 
1523  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1524 
1525  /* edit / add dispositions here */
1526  .next_nodes = {
1527  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1528  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1529  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1530  [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1531  },
1532 };
1535 
1536 /*******************************/
1537 /*** endpoint-dependent mode ***/
1538 /*******************************/
1539 typedef enum {
1547 
1548 typedef struct {
1554 
1555 static u8 *
1556 format_nat44_ed_out2in_trace (u8 * s, va_list * args)
1557 {
1558  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1559  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1560  nat44_ed_out2in_trace_t *t = va_arg (*args, nat44_ed_out2in_trace_t *);
1561  char * tag;
1562 
1563  tag = t->is_slow_path ? "NAT44_OUT2IN_SLOW_PATH" : "NAT44_OUT2IN_FAST_PATH";
1564 
1565  s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
1566  t->sw_if_index, t->next_index, t->session_index);
1567 
1568  return s;
1569 }
1570 
1571 static snat_session_t *
1573  vlib_buffer_t *b,
1574  snat_session_key_t l_key,
1575  snat_session_key_t e_key,
1576  vlib_node_runtime_t * node,
1577  u32 thread_index,
1578  twice_nat_type_t twice_nat,
1579  u8 is_lb)
1580 {
1581  snat_session_t *s;
1582  snat_user_t *u;
1583  ip4_header_t *ip;
1584  udp_header_t *udp;
1585  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1587  snat_session_key_t eh_key;
1588  u32 address_index;
1589 
1590  if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
1591  {
1592  b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
1593  nat_log_notice ("maximum sessions exceeded");
1594  return 0;
1595  }
1596 
1597  u = nat_user_get_or_create (sm, &l_key.addr, l_key.fib_index, thread_index);
1598  if (!u)
1599  {
1600  nat_log_warn ("create NAT user failed");
1601  return 0;
1602  }
1603 
1604  s = nat_session_alloc_or_recycle (sm, u, thread_index);
1605  if (!s)
1606  {
1607  nat_log_warn ("create NAT session failed");
1608  return 0;
1609  }
1610 
1611  ip = vlib_buffer_get_current (b);
1612  udp = ip4_next_header (ip);
1613 
1614  s->ext_host_addr.as_u32 = ip->src_address.as_u32;
1615  s->ext_host_port = e_key.protocol == SNAT_PROTOCOL_ICMP ? 0 : udp->src_port;
1617  if (is_lb)
1620  s->outside_address_index = ~0;
1621  s->out2in = e_key;
1622  s->in2out = l_key;
1623  s->in2out.protocol = s->out2in.protocol;
1624  user_session_increment (sm, u, 1);
1625 
1626  /* Add to lookup tables */
1627  make_ed_kv (&kv, &e_key.addr, &s->ext_host_addr, ip->protocol,
1628  e_key.fib_index, e_key.port, s->ext_host_port);
1629  kv.value = s - tsm->sessions;
1630  if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1))
1631  nat_log_notice ("out2in-ed key add failed");
1632 
1633  if (twice_nat == TWICE_NAT || (twice_nat == TWICE_NAT_SELF &&
1634  ip->src_address.as_u32 == l_key.addr.as_u32))
1635  {
1636  eh_key.protocol = e_key.protocol;
1638  thread_index, &eh_key,
1639  &address_index,
1640  sm->port_per_thread,
1641  tsm->snat_thread_index))
1642  {
1643  b->error = node->errors[SNAT_OUT2IN_ERROR_OUT_OF_PORTS];
1644  nat44_delete_session (sm, s, thread_index);
1645  if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 0))
1646  nat_log_notice ("out2in-ed key del failed");
1647  return 0;
1648  }
1649  s->ext_host_nat_addr.as_u32 = eh_key.addr.as_u32;
1650  s->ext_host_nat_port = eh_key.port;
1651  s->flags |= SNAT_SESSION_FLAG_TWICE_NAT;
1652  make_ed_kv (&kv, &l_key.addr, &s->ext_host_nat_addr, ip->protocol,
1653  l_key.fib_index, l_key.port, s->ext_host_nat_port);
1654  }
1655  else
1656  {
1657  make_ed_kv (&kv, &l_key.addr, &s->ext_host_addr, ip->protocol,
1658  l_key.fib_index, l_key.port, s->ext_host_port);
1659  }
1660  kv.value = s - tsm->sessions;
1661  if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
1662  nat_log_notice ("in2out-ed key add failed");
1663 
1664  return s;
1665 }
1666 
1669 {
1670  icmp46_header_t *icmp0;
1671  nat_ed_ses_key_t key0;
1672  icmp_echo_header_t *echo0, *inner_echo0 = 0;
1673  ip4_header_t *inner_ip0;
1674  void *l4_header = 0;
1675  icmp46_header_t *inner_icmp0;
1676 
1677  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
1678  echo0 = (icmp_echo_header_t *)(icmp0+1);
1679 
1680  if (!icmp_is_error_message (icmp0))
1681  {
1682  key0.proto = IP_PROTOCOL_ICMP;
1683  key0.l_addr = ip0->dst_address;
1684  key0.r_addr = ip0->src_address;
1685  key0.l_port = echo0->identifier;
1686  key0.r_port = 0;
1687  }
1688  else
1689  {
1690  inner_ip0 = (ip4_header_t *)(echo0+1);
1691  l4_header = ip4_next_header (inner_ip0);
1692  key0.proto = inner_ip0->protocol;
1693  key0.l_addr = inner_ip0->src_address;
1694  key0.r_addr = inner_ip0->dst_address;
1695  switch (ip_proto_to_snat_proto (inner_ip0->protocol))
1696  {
1697  case SNAT_PROTOCOL_ICMP:
1698  inner_icmp0 = (icmp46_header_t*)l4_header;
1699  inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
1700  key0.l_port = inner_echo0->identifier;
1701  key0.r_port = 0;
1702  break;
1703  case SNAT_PROTOCOL_UDP:
1704  case SNAT_PROTOCOL_TCP:
1705  key0.l_port = ((tcp_udp_header_t*)l4_header)->src_port;
1706  key0.r_port = ((tcp_udp_header_t*)l4_header)->dst_port;
1707  break;
1708  default:
1709  return -1;
1710  }
1711  }
1712  *p_key0 = key0;
1713  return 0;
1714 }
1715 
1716 static int
1717 next_src_nat (snat_main_t * sm, ip4_header_t * ip, u8 proto, u16 src_port,
1718  u16 dst_port, u32 thread_index, u32 rx_fib_index)
1719 {
1720  clib_bihash_kv_16_8_t kv, value;
1721  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1722 
1723  make_ed_kv (&kv, &ip->src_address, &ip->dst_address, proto,
1724  rx_fib_index, src_port, dst_port);
1725  if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
1726  return 1;
1727 
1728  return 0;
1729 }
1730 
1731 static void
1733  u32 thread_index)
1734 {
1735  nat_ed_ses_key_t key;
1736  clib_bihash_kv_16_8_t kv, value;
1737  udp_header_t *udp;
1738  snat_user_t *u;
1739  snat_session_t *s = 0;
1740  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1741  f64 now = vlib_time_now (sm->vlib_main);
1742 
1743  if (ip->protocol == IP_PROTOCOL_ICMP)
1744  {
1745  if (icmp_get_ed_key (ip, &key))
1746  return;
1747  }
1748  else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
1749  {
1750  udp = ip4_next_header(ip);
1751  key.r_addr = ip->src_address;
1752  key.l_addr = ip->dst_address;
1753  key.proto = ip->protocol;
1754  key.l_port = udp->dst_port;
1755  key.r_port = udp->src_port;
1756  }
1757  else
1758  {
1759  key.r_addr = ip->src_address;
1760  key.l_addr = ip->dst_address;
1761  key.proto = ip->protocol;
1762  key.l_port = key.r_port = 0;
1763  }
1764  key.fib_index = 0;
1765  kv.key[0] = key.as_u64[0];
1766  kv.key[1] = key.as_u64[1];
1767 
1768  if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
1769  {
1770  s = pool_elt_at_index (tsm->sessions, value.value);
1771  }
1772  else
1773  {
1774  if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
1775  return;
1776 
1778  thread_index);
1779  if (!u)
1780  {
1781  nat_log_warn ("create NAT user failed");
1782  return;
1783  }
1784 
1785  s = nat_session_alloc_or_recycle (sm, u, thread_index);
1786  if (!s)
1787  {
1788  nat_log_warn ("create NAT session failed");
1789  return;
1790  }
1791 
1792  s->ext_host_addr = key.r_addr;
1793  s->ext_host_port = key.r_port;
1794  s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS;
1795  s->outside_address_index = ~0;
1796  s->out2in.addr = key.l_addr;
1797  s->out2in.port = key.l_port;
1798  s->out2in.protocol = ip_proto_to_snat_proto (key.proto);
1799  s->out2in.fib_index = 0;
1800  s->in2out = s->out2in;
1801  user_session_increment (sm, u, 0);
1802 
1803  kv.value = s - tsm->sessions;
1804  if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
1805  nat_log_notice ("in2out_ed key add failed");
1806  }
1807 
1808  if (ip->protocol == IP_PROTOCOL_TCP)
1809  {
1810  tcp_header_t *tcp = ip4_next_header(ip);
1811  if (nat44_set_tcp_session_state_o2i (sm, s, tcp, thread_index))
1812  return;
1813  }
1814 
1815  /* Per-user LRU list maintenance */
1816  nat44_session_update_lru (sm, s, thread_index);
1817  /* Accounting */
1818  nat44_session_update_counters (s, now, 0);
1819 }
1820 
1821 u32
1823  u32 thread_index, vlib_buffer_t * b, ip4_header_t * ip,
1824  u8 * p_proto, snat_session_key_t * p_value,
1825  u8 * p_dont_translate, void * d, void * e)
1826 {
1827  u32 next = ~0, sw_if_index, rx_fib_index;
1828  icmp46_header_t *icmp;
1829  nat_ed_ses_key_t key;
1830  clib_bihash_kv_16_8_t kv, value;
1831  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1832  snat_session_t *s = 0;
1833  u8 dont_translate = 0, is_addr_only;
1834  snat_session_key_t e_key, l_key;
1835 
1836  icmp = (icmp46_header_t *) ip4_next_header (ip);
1837  sw_if_index = vnet_buffer(b)->sw_if_index[VLIB_RX];
1838  rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
1839 
1840  if (icmp_get_ed_key (ip, &key))
1841  {
1842  b->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1843  next = SNAT_OUT2IN_NEXT_DROP;
1844  goto out;
1845  }
1846  key.fib_index = rx_fib_index;
1847  kv.key[0] = key.as_u64[0];
1848  kv.key[1] = key.as_u64[1];
1849 
1850  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
1851  {
1852  /* Try to match static mapping */
1853  e_key.addr = ip->dst_address;
1854  e_key.port = key.l_port;
1855  e_key.protocol = ip_proto_to_snat_proto (key.proto);
1856  e_key.fib_index = rx_fib_index;
1857  if (snat_static_mapping_match(sm, e_key, &l_key, 1, &is_addr_only, 0, 0))
1858  {
1859  if (!sm->forwarding_enabled)
1860  {
1861  /* Don't NAT packet aimed at the intfc address */
1862  if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index,
1863  ip->dst_address.as_u32)))
1864  {
1865  dont_translate = 1;
1866  goto out;
1867  }
1868  b->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1870  goto out;
1871  }
1872  else
1873  {
1874  dont_translate = 1;
1875  if (next_src_nat(sm, ip, key.proto, key.l_port, key.r_port,
1876  thread_index, rx_fib_index))
1877  {
1879  goto out;
1880  }
1881  create_bypass_for_fwd(sm, ip, rx_fib_index, thread_index);
1882  goto out;
1883  }
1884  }
1885 
1886  if (PREDICT_FALSE(icmp->type != ICMP4_echo_reply &&
1887  (icmp->type != ICMP4_echo_request || !is_addr_only)))
1888  {
1889  b->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
1891  goto out;
1892  }
1893 
1894  /* Create session initiated by host from external network */
1895  s = create_session_for_static_mapping_ed(sm, b, l_key, e_key, node,
1896  thread_index, 0, 0);
1897 
1898  if (!s)
1899  {
1901  goto out;
1902  }
1903  }
1904  else
1905  {
1906  if (PREDICT_FALSE(icmp->type != ICMP4_echo_reply &&
1907  icmp->type != ICMP4_echo_request &&
1908  !icmp_is_error_message (icmp)))
1909  {
1910  b->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
1911  next = SNAT_OUT2IN_NEXT_DROP;
1912  goto out;
1913  }
1914 
1915  s = pool_elt_at_index (tsm->sessions, value.value);
1916  }
1917 
1918  *p_proto = ip_proto_to_snat_proto (key.proto);
1919 out:
1920  if (s)
1921  *p_value = s->in2out;
1922  *p_dont_translate = dont_translate;
1923  if (d)
1924  *(snat_session_t**)d = s;
1925  return next;
1926 }
1927 
1928 static snat_session_t *
1930  vlib_buffer_t * b,
1931  ip4_header_t * ip,
1932  u32 rx_fib_index,
1933  u32 thread_index,
1934  f64 now,
1935  vlib_main_t * vm,
1936  vlib_node_runtime_t * node)
1937 {
1938  clib_bihash_kv_8_8_t kv, value;
1939  clib_bihash_kv_16_8_t s_kv, s_value;
1941  u32 old_addr, new_addr;
1942  ip_csum_t sum;
1943  snat_session_t * s;
1944  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1945  snat_user_t *u;
1946 
1947  old_addr = ip->dst_address.as_u32;
1948 
1949  make_ed_kv (&s_kv, &ip->dst_address, &ip->src_address, ip->protocol,
1950  rx_fib_index, 0, 0);
1951 
1952  if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
1953  {
1954  s = pool_elt_at_index (tsm->sessions, s_value.value);
1955  new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
1956  }
1957  else
1958  {
1959  if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
1960  {
1961  b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
1962  nat_log_notice ("maximum sessions exceeded");
1963  return 0;
1964  }
1965 
1966  make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
1967  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1968  {
1969  b->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1970  return 0;
1971  }
1972 
1973  m = pool_elt_at_index (sm->static_mappings, value.value);
1974 
1975  new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
1976 
1977  u = nat_user_get_or_create (sm, &ip->src_address, m->fib_index,
1978  thread_index);
1979  if (!u)
1980  {
1981  nat_log_warn ("create NAT user failed");
1982  return 0;
1983  }
1984 
1985  /* Create a new session */
1986  s = nat_session_alloc_or_recycle (sm, u, thread_index);
1987  if (!s)
1988  {
1989  nat_log_warn ("create NAT session failed");
1990  return 0;
1991  }
1992 
1993  s->ext_host_addr.as_u32 = ip->src_address.as_u32;
1994  s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
1997  s->outside_address_index = ~0;
1998  s->out2in.addr.as_u32 = old_addr;
1999  s->out2in.fib_index = rx_fib_index;
2000  s->in2out.addr.as_u32 = new_addr;
2001  s->in2out.fib_index = m->fib_index;
2002  s->in2out.port = s->out2in.port = ip->protocol;
2003  user_session_increment (sm, u, 1);
2004 
2005  /* Add to lookup tables */
2006  s_kv.value = s - tsm->sessions;
2007  if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1))
2008  nat_log_notice ("out2in key add failed");
2009 
2010  make_ed_kv (&s_kv, &ip->dst_address, &ip->src_address, ip->protocol,
2011  m->fib_index, 0, 0);
2012  s_kv.value = s - tsm->sessions;
2013  if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
2014  nat_log_notice ("in2out key add failed");
2015  }
2016 
2017  /* Update IP checksum */
2018  sum = ip->checksum;
2019  sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
2020  ip->checksum = ip_csum_fold (sum);
2021 
2022  vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
2023 
2024  /* Accounting */
2026  vlib_buffer_length_in_chain (vm, b));
2027  /* Per-user LRU list maintenance */
2028  nat44_session_update_lru (sm, s, thread_index);
2029 
2030  return s;
2031 }
2032 
2033 static inline uword
2035  vlib_node_runtime_t * node,
2036  vlib_frame_t * frame, int is_slow_path)
2037 {
2038  u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
2039  nat44_ed_out2in_next_t next_index;
2040  snat_main_t *sm = &snat_main;
2041  f64 now = vlib_time_now (vm);
2042  u32 thread_index = vm->thread_index;
2043  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
2044 
2045  stats_node_index = is_slow_path ? nat44_ed_out2in_slowpath_node.index :
2046  nat44_ed_out2in_node.index;
2047 
2048  from = vlib_frame_vector_args (frame);
2049  n_left_from = frame->n_vectors;
2050  next_index = node->cached_next_index;
2051 
2052  while (n_left_from > 0)
2053  {
2054  u32 n_left_to_next;
2055 
2056  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2057 
2058  while (n_left_from >= 4 && n_left_to_next >= 2)
2059  {
2060  u32 bi0, bi1;
2061  vlib_buffer_t *b0, *b1;
2062  u32 next0, sw_if_index0, rx_fib_index0, proto0, old_addr0, new_addr0;
2063  u32 next1, sw_if_index1, rx_fib_index1, proto1, old_addr1, new_addr1;
2064  u16 old_port0, new_port0, old_port1, new_port1;
2065  ip4_header_t *ip0, *ip1;
2066  udp_header_t *udp0, *udp1;
2067  tcp_header_t *tcp0, *tcp1;
2068  icmp46_header_t *icmp0, *icmp1;
2069  snat_session_t *s0 = 0, *s1 = 0;
2070  clib_bihash_kv_16_8_t kv0, value0, kv1, value1;
2071  ip_csum_t sum0, sum1;
2072  snat_session_key_t e_key0, l_key0, e_key1, l_key1;
2073  u8 is_lb0, is_lb1;
2074  twice_nat_type_t twice_nat0, twice_nat1;
2075 
2076  /* Prefetch next iteration. */
2077  {
2078  vlib_buffer_t * p2, * p3;
2079 
2080  p2 = vlib_get_buffer (vm, from[2]);
2081  p3 = vlib_get_buffer (vm, from[3]);
2082 
2083  vlib_prefetch_buffer_header (p2, LOAD);
2084  vlib_prefetch_buffer_header (p3, LOAD);
2085 
2088  }
2089 
2090  /* speculatively enqueue b0 and b1 to the current next frame */
2091  to_next[0] = bi0 = from[0];
2092  to_next[1] = bi1 = from[1];
2093  from += 2;
2094  to_next += 2;
2095  n_left_from -= 2;
2096  n_left_to_next -= 2;
2097 
2098  b0 = vlib_get_buffer (vm, bi0);
2099  b1 = vlib_get_buffer (vm, bi1);
2100 
2102  vnet_buffer (b0)->snat.flags = 0;
2103  ip0 = vlib_buffer_get_current (b0);
2104 
2105  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2107  sw_if_index0);
2108 
2109  if (PREDICT_FALSE(ip0->ttl == 1))
2110  {
2111  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2112  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2113  ICMP4_time_exceeded_ttl_exceeded_in_transit,
2114  0);
2116  goto trace00;
2117  }
2118 
2119  udp0 = ip4_next_header (ip0);
2120  tcp0 = (tcp_header_t *) udp0;
2121  icmp0 = (icmp46_header_t *) udp0;
2122  proto0 = ip_proto_to_snat_proto (ip0->protocol);
2123 
2124  if (is_slow_path)
2125  {
2126  if (PREDICT_FALSE (proto0 == ~0))
2127  {
2128  s0 = nat44_ed_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0,
2129  thread_index, now, vm, node);
2130  if (!sm->forwarding_enabled)
2131  {
2132  if (!s0)
2133  next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2134  goto trace00;
2135  }
2136  }
2137 
2138  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2139  {
2140  next0 = icmp_out2in_slow_path
2141  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
2142  next0, now, thread_index, &s0);
2143  goto trace00;
2144  }
2145  }
2146  else
2147  {
2148  if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP))
2149  {
2151  goto trace00;
2152  }
2153 
2154  if (ip4_is_fragment (ip0))
2155  {
2156  b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
2157  next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2158  goto trace00;
2159  }
2160  }
2161 
2162  make_ed_kv (&kv0, &ip0->dst_address, &ip0->src_address, ip0->protocol,
2163  rx_fib_index0, udp0->dst_port, udp0->src_port);
2164 
2165  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
2166  {
2167  if (is_slow_path)
2168  {
2169  /* Try to match static mapping by external address and port,
2170  destination address and port in packet */
2171  e_key0.addr = ip0->dst_address;
2172  e_key0.port = udp0->dst_port;
2173  e_key0.protocol = proto0;
2174  e_key0.fib_index = rx_fib_index0;
2175  if (snat_static_mapping_match(sm, e_key0, &l_key0, 1, 0,
2176  &twice_nat0, &is_lb0))
2177  {
2178  /*
2179  * Send DHCP packets to the ipv4 stack, or we won't
2180  * be able to use dhcp client on the outside interface
2181  */
2182  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
2183  && (udp0->dst_port ==
2184  clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
2185  {
2187  (vnet_buffer (b0)->sw_if_index[VLIB_RX], &next0, b0);
2188  goto trace00;
2189  }
2190 
2191  if (!sm->forwarding_enabled)
2192  {
2193  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2194  next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2195  }
2196  else
2197  {
2198  if (next_src_nat(sm, ip0, ip0->protocol,
2199  udp0->src_port, udp0->dst_port,
2200  thread_index, rx_fib_index0))
2201  {
2203  goto trace00;
2204  }
2205  create_bypass_for_fwd(sm, ip0, rx_fib_index0,
2206  thread_index);
2207  }
2208  goto trace00;
2209  }
2210 
2211  /* Create session initiated by host from external network */
2212  s0 = create_session_for_static_mapping_ed(sm, b0, l_key0,
2213  e_key0, node,
2214  thread_index,
2215  twice_nat0, is_lb0);
2216 
2217  if (!s0)
2218  {
2219  next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2220  goto trace00;
2221  }
2222  }
2223  else
2224  {
2226  goto trace00;
2227  }
2228  }
2229  else
2230  {
2231  s0 = pool_elt_at_index (tsm->sessions, value0.value);
2232  }
2233 
2234  old_addr0 = ip0->dst_address.as_u32;
2235  new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
2236  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
2237 
2238  sum0 = ip0->checksum;
2239  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
2240  dst_address);
2242  sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
2243  s0->ext_host_nat_addr.as_u32, ip4_header_t,
2244  src_address);
2245  ip0->checksum = ip_csum_fold (sum0);
2246 
2247  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
2248  {
2249  old_port0 = tcp0->dst_port;
2250  new_port0 = tcp0->dst_port = s0->in2out.port;
2251 
2252  sum0 = tcp0->checksum;
2253  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
2254  dst_address);
2255  sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
2256  length);
2257  if (is_twice_nat_session (s0))
2258  {
2259  sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
2260  s0->ext_host_nat_addr.as_u32,
2261  ip4_header_t, dst_address);
2262  sum0 = ip_csum_update (sum0, tcp0->src_port,
2263  s0->ext_host_nat_port, ip4_header_t,
2264  length);
2265  tcp0->src_port = s0->ext_host_nat_port;
2266  ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
2267  }
2268  tcp0->checksum = ip_csum_fold(sum0);
2269  if (nat44_set_tcp_session_state_o2i (sm, s0, tcp0, thread_index))
2270  goto trace00;
2271  }
2272  else
2273  {
2274  udp0->dst_port = s0->in2out.port;
2275  if (is_twice_nat_session (s0))
2276  {
2277  udp0->src_port = s0->ext_host_nat_port;
2278  ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
2279  }
2280  udp0->checksum = 0;
2281  }
2282 
2283  /* Accounting */
2285  vlib_buffer_length_in_chain (vm, b0));
2286  /* Per-user LRU list maintenance */
2287  nat44_session_update_lru (sm, s0, thread_index);
2288 
2289  trace00:
2291  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2292  {
2294  vlib_add_trace (vm, node, b0, sizeof (*t));
2295  t->is_slow_path = is_slow_path;
2296  t->sw_if_index = sw_if_index0;
2297  t->next_index = next0;
2298  t->session_index = ~0;
2299  if (s0)
2300  t->session_index = s0 - tsm->sessions;
2301  }
2302 
2303  pkts_processed += next0 != NAT44_ED_OUT2IN_NEXT_DROP;
2304 
2306  vnet_buffer (b1)->snat.flags = 0;
2307  ip1 = vlib_buffer_get_current (b1);
2308 
2309  sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
2311  sw_if_index1);
2312 
2313  if (PREDICT_FALSE(ip1->ttl == 1))
2314  {
2315  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2316  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
2317  ICMP4_time_exceeded_ttl_exceeded_in_transit,
2318  0);
2320  goto trace01;
2321  }
2322 
2323  udp1 = ip4_next_header (ip1);
2324  tcp1 = (tcp_header_t *) udp1;
2325  icmp1 = (icmp46_header_t *) udp1;
2326  proto1 = ip_proto_to_snat_proto (ip1->protocol);
2327 
2328  if (is_slow_path)
2329  {
2330  if (PREDICT_FALSE (proto1 == ~0))
2331  {
2332  s1 = nat44_ed_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1,
2333  thread_index, now, vm, node);
2334  if (!sm->forwarding_enabled)
2335  {
2336  if (!s1)
2337  next1 = NAT44_ED_OUT2IN_NEXT_DROP;
2338  goto trace01;
2339  }
2340  }
2341 
2342  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
2343  {
2344  next1 = icmp_out2in_slow_path
2345  (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
2346  next1, now, thread_index, &s1);
2347  goto trace01;
2348  }
2349  }
2350  else
2351  {
2352  if (PREDICT_FALSE (proto1 == ~0 || proto1 == SNAT_PROTOCOL_ICMP))
2353  {
2355  goto trace01;
2356  }
2357 
2358  if (ip4_is_fragment (ip1))
2359  {
2360  b1->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
2361  next1 = NAT44_ED_OUT2IN_NEXT_DROP;
2362  goto trace01;
2363  }
2364  }
2365 
2366  make_ed_kv (&kv1, &ip1->dst_address, &ip1->src_address, ip1->protocol,
2367  rx_fib_index1, udp1->dst_port, udp1->src_port);
2368 
2369  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv1, &value1))
2370  {
2371  if (is_slow_path)
2372  {
2373  /* Try to match static mapping by external address and port,
2374  destination address and port in packet */
2375  e_key1.addr = ip1->dst_address;
2376  e_key1.port = udp1->dst_port;
2377  e_key1.protocol = proto1;
2378  e_key1.fib_index = rx_fib_index1;
2379  if (snat_static_mapping_match(sm, e_key1, &l_key1, 1, 0,
2380  &twice_nat1, &is_lb1))
2381  {
2382  /*
2383  * Send DHCP packets to the ipv4 stack, or we won't
2384  * be able to use dhcp client on the outside interface
2385  */
2386  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_UDP
2387  && (udp1->dst_port ==
2388  clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
2389  {
2391  (vnet_buffer (b1)->sw_if_index[VLIB_RX], &next1, b1);
2392  goto trace01;
2393  }
2394 
2395  if (!sm->forwarding_enabled)
2396  {
2397  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2398  next1 = NAT44_ED_OUT2IN_NEXT_DROP;
2399  }
2400  else
2401  {
2402  if (next_src_nat(sm, ip1, ip1->protocol,
2403  udp1->src_port, udp1->dst_port,
2404  thread_index, rx_fib_index1))
2405  {
2407  goto trace01;
2408  }
2409  create_bypass_for_fwd(sm, ip1, rx_fib_index1,
2410  thread_index);
2411  }
2412  goto trace01;
2413  }
2414 
2415  /* Create session initiated by host from external network */
2416  s1 = create_session_for_static_mapping_ed(sm, b1, l_key1,
2417  e_key1, node,
2418  thread_index,
2419  twice_nat1, is_lb1);
2420 
2421  if (!s1)
2422  {
2423  next1 = NAT44_ED_OUT2IN_NEXT_DROP;
2424  goto trace01;
2425  }
2426  }
2427  else
2428  {
2430  goto trace01;
2431  }
2432  }
2433  else
2434  {
2435  s1 = pool_elt_at_index (tsm->sessions, value1.value);
2436  }
2437 
2438  old_addr1 = ip1->dst_address.as_u32;
2439  new_addr1 = ip1->dst_address.as_u32 = s1->in2out.addr.as_u32;
2440  vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
2441 
2442  sum1 = ip1->checksum;
2443  sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
2444  dst_address);
2446  sum1 = ip_csum_update (sum1, ip1->src_address.as_u32,
2447  s1->ext_host_nat_addr.as_u32, ip4_header_t,
2448  src_address);
2449  ip1->checksum = ip_csum_fold (sum1);
2450 
2451  if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
2452  {
2453  old_port1 = tcp1->dst_port;
2454  new_port1 = tcp1->dst_port = s1->in2out.port;
2455 
2456  sum1 = tcp1->checksum;
2457  sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
2458  dst_address);
2459  sum1 = ip_csum_update (sum1, old_port1, new_port1, ip4_header_t,
2460  length);
2461  if (is_twice_nat_session (s1))
2462  {
2463  sum1 = ip_csum_update (sum1, ip1->src_address.as_u32,
2464  s1->ext_host_nat_addr.as_u32,
2465  ip4_header_t, dst_address);
2466  sum1 = ip_csum_update (sum1, tcp1->src_port,
2467  s1->ext_host_nat_port, ip4_header_t,
2468  length);
2469  tcp1->src_port = s1->ext_host_nat_port;
2470  ip1->src_address.as_u32 = s1->ext_host_nat_addr.as_u32;
2471  }
2472  tcp1->checksum = ip_csum_fold(sum1);
2473  if (nat44_set_tcp_session_state_o2i (sm, s1, tcp1, thread_index))
2474  goto trace01;
2475  }
2476  else
2477  {
2478  udp1->dst_port = s1->in2out.port;
2479  if (is_twice_nat_session (s1))
2480  {
2481  udp1->src_port = s1->ext_host_nat_port;
2482  ip1->src_address.as_u32 = s1->ext_host_nat_addr.as_u32;
2483  }
2484  udp1->checksum = 0;
2485  }
2486 
2487  /* Accounting */
2489  vlib_buffer_length_in_chain (vm, b1));
2490  /* Per-user LRU list maintenance */
2491  nat44_session_update_lru (sm, s1, thread_index);
2492 
2493  trace01:
2495  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
2496  {
2498  vlib_add_trace (vm, node, b1, sizeof (*t));
2499  t->is_slow_path = is_slow_path;
2500  t->sw_if_index = sw_if_index1;
2501  t->next_index = next1;
2502  t->session_index = ~0;
2503  if (s1)
2504  t->session_index = s1 - tsm->sessions;
2505  }
2506 
2507  pkts_processed += next1 != NAT44_ED_OUT2IN_NEXT_DROP;
2508 
2509  /* verify speculative enqueues, maybe switch current next frame */
2510  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2511  to_next, n_left_to_next,
2512  bi0, bi1, next0, next1);
2513  }
2514 
2515  while (n_left_from > 0 && n_left_to_next > 0)
2516  {
2517  u32 bi0;
2518  vlib_buffer_t *b0;
2519  u32 next0, sw_if_index0, rx_fib_index0, proto0, old_addr0, new_addr0;
2520  u16 old_port0, new_port0;
2521  ip4_header_t *ip0;
2522  udp_header_t *udp0;
2523  tcp_header_t *tcp0;
2524  icmp46_header_t * icmp0;
2525  snat_session_t *s0 = 0;
2526  clib_bihash_kv_16_8_t kv0, value0;
2527  ip_csum_t sum0;
2528  snat_session_key_t e_key0, l_key0;
2529  u8 is_lb0;
2530  twice_nat_type_t twice_nat0;
2531 
2532  /* speculatively enqueue b0 to the current next frame */
2533  bi0 = from[0];
2534  to_next[0] = bi0;
2535  from += 1;
2536  to_next += 1;
2537  n_left_from -= 1;
2538  n_left_to_next -= 1;
2539 
2540  b0 = vlib_get_buffer (vm, bi0);
2542  vnet_buffer (b0)->snat.flags = 0;
2543  ip0 = vlib_buffer_get_current (b0);
2544 
2545  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2547  sw_if_index0);
2548 
2549  if (PREDICT_FALSE(ip0->ttl == 1))
2550  {
2551  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2552  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2553  ICMP4_time_exceeded_ttl_exceeded_in_transit,
2554  0);
2556  goto trace0;
2557  }
2558 
2559  udp0 = ip4_next_header (ip0);
2560  tcp0 = (tcp_header_t *) udp0;
2561  icmp0 = (icmp46_header_t *) udp0;
2562  proto0 = ip_proto_to_snat_proto (ip0->protocol);
2563 
2564  if (is_slow_path)
2565  {
2566  if (PREDICT_FALSE (proto0 == ~0))
2567  {
2568  s0 = nat44_ed_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0,
2569  thread_index, now, vm, node);
2570  if (!sm->forwarding_enabled)
2571  {
2572  if (!s0)
2573  next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2574  goto trace0;
2575  }
2576  }
2577 
2578  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2579  {
2580  next0 = icmp_out2in_slow_path
2581  (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
2582  next0, now, thread_index, &s0);
2583  goto trace0;
2584  }
2585  }
2586  else
2587  {
2588  if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP))
2589  {
2591  goto trace0;
2592  }
2593 
2594  if (ip4_is_fragment (ip0))
2595  {
2596  b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
2597  next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2598  goto trace0;
2599  }
2600  }
2601 
2602  make_ed_kv (&kv0, &ip0->dst_address, &ip0->src_address, ip0->protocol,
2603  rx_fib_index0, udp0->dst_port, udp0->src_port);
2604 
2605  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
2606  {
2607  if (is_slow_path)
2608  {
2609  /* Try to match static mapping by external address and port,
2610  destination address and port in packet */
2611  e_key0.addr = ip0->dst_address;
2612  e_key0.port = udp0->dst_port;
2613  e_key0.protocol = proto0;
2614  e_key0.fib_index = rx_fib_index0;
2615  if (snat_static_mapping_match(sm, e_key0, &l_key0, 1, 0,
2616  &twice_nat0, &is_lb0))
2617  {
2618  /*
2619  * Send DHCP packets to the ipv4 stack, or we won't
2620  * be able to use dhcp client on the outside interface
2621  */
2622  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
2623  && (udp0->dst_port ==
2624  clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
2625  {
2627  (vnet_buffer (b0)->sw_if_index[VLIB_RX], &next0, b0);
2628  goto trace0;
2629  }
2630 
2631  if (!sm->forwarding_enabled)
2632  {
2633  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2634  next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2635  }
2636  else
2637  {
2638  if (next_src_nat(sm, ip0, ip0->protocol,
2639  udp0->src_port, udp0->dst_port,
2640  thread_index, rx_fib_index0))
2641  {
2643  goto trace0;
2644  }
2645  create_bypass_for_fwd(sm, ip0, rx_fib_index0,
2646  thread_index);
2647  }
2648  goto trace0;
2649  }
2650 
2651  /* Create session initiated by host from external network */
2652  s0 = create_session_for_static_mapping_ed(sm, b0, l_key0,
2653  e_key0, node,
2654  thread_index,
2655  twice_nat0, is_lb0);
2656 
2657  if (!s0)
2658  {
2659  next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2660  goto trace0;
2661  }
2662  }
2663  else
2664  {
2666  goto trace0;
2667  }
2668  }
2669  else
2670  {
2671  s0 = pool_elt_at_index (tsm->sessions, value0.value);
2672  }
2673 
2674  old_addr0 = ip0->dst_address.as_u32;
2675  new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
2676  vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
2677 
2678  sum0 = ip0->checksum;
2679  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
2680  dst_address);
2682  sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
2683  s0->ext_host_nat_addr.as_u32, ip4_header_t,
2684  src_address);
2685  ip0->checksum = ip_csum_fold (sum0);
2686 
2687  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
2688  {
2689  old_port0 = tcp0->dst_port;
2690  new_port0 = tcp0->dst_port = s0->in2out.port;
2691 
2692  sum0 = tcp0->checksum;
2693  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
2694  dst_address);
2695  sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
2696  length);
2697  if (is_twice_nat_session (s0))
2698  {
2699  sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
2700  s0->ext_host_nat_addr.as_u32,
2701  ip4_header_t, dst_address);
2702  sum0 = ip_csum_update (sum0, tcp0->src_port,
2703  s0->ext_host_nat_port, ip4_header_t,
2704  length);
2705  tcp0->src_port = s0->ext_host_nat_port;
2706  ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
2707  }
2708  tcp0->checksum = ip_csum_fold(sum0);
2709  if (nat44_set_tcp_session_state_o2i (sm, s0, tcp0, thread_index))
2710  goto trace0;
2711  }
2712  else
2713  {
2714  udp0->dst_port = s0->in2out.port;
2715  if (is_twice_nat_session (s0))
2716  {
2717  udp0->src_port = s0->ext_host_nat_port;
2718  ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
2719  }
2720  udp0->checksum = 0;
2721  }
2722 
2723  /* Accounting */
2725  vlib_buffer_length_in_chain (vm, b0));
2726  /* Per-user LRU list maintenance */
2727  nat44_session_update_lru (sm, s0, thread_index);
2728 
2729  trace0:
2731  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2732  {
2734  vlib_add_trace (vm, node, b0, sizeof (*t));
2735  t->is_slow_path = is_slow_path;
2736  t->sw_if_index = sw_if_index0;
2737  t->next_index = next0;
2738  t->session_index = ~0;
2739  if (s0)
2740  t->session_index = s0 - tsm->sessions;
2741  }
2742 
2743  pkts_processed += next0 != NAT44_ED_OUT2IN_NEXT_DROP;
2744 
2745  /* verify speculative enqueue, maybe switch current next frame */
2746  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2747  to_next, n_left_to_next,
2748  bi0, next0);
2749  }
2750 
2751  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2752  }
2753 
2754  vlib_node_increment_counter (vm, stats_node_index,
2755  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
2756  pkts_processed);
2757  return frame->n_vectors;
2758 }
2759 
2760 static uword
2762  vlib_node_runtime_t * node,
2763  vlib_frame_t * frame)
2764 {
2765  return nat44_ed_out2in_node_fn_inline (vm, node, frame, 0);
2766 }
2767 
2769  .function = nat44_ed_out2in_fast_path_fn,
2770  .name = "nat44-ed-out2in",
2771  .vector_size = sizeof (u32),
2772  .format_trace = format_nat44_ed_out2in_trace,
2773  .type = VLIB_NODE_TYPE_INTERNAL,
2774 
2775  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2776  .error_strings = snat_out2in_error_strings,
2777 
2778  .runtime_data_bytes = sizeof (snat_runtime_t),
2779 
2780  .n_next_nodes = NAT44_ED_OUT2IN_N_NEXT,
2781 
2782  /* edit / add dispositions here */
2783  .next_nodes = {
2784  [NAT44_ED_OUT2IN_NEXT_DROP] = "error-drop",
2785  [NAT44_ED_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2786  [NAT44_ED_OUT2IN_NEXT_SLOW_PATH] = "nat44-ed-out2in-slowpath",
2787  [NAT44_ED_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2788  [NAT44_ED_OUT2IN_NEXT_IN2OUT] = "nat44-ed-in2out",
2789  },
2790 };
2791 
2793 
2794 static uword
2796  vlib_node_runtime_t * node,
2797  vlib_frame_t * frame)
2798 {
2799  return nat44_ed_out2in_node_fn_inline (vm, node, frame, 1);
2800 }
2801 
2803  .function = nat44_ed_out2in_slow_path_fn,
2804  .name = "nat44-ed-out2in-slowpath",
2805  .vector_size = sizeof (u32),
2806  .format_trace = format_nat44_ed_out2in_trace,
2807  .type = VLIB_NODE_TYPE_INTERNAL,
2808 
2809  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2810  .error_strings = snat_out2in_error_strings,
2811 
2812  .runtime_data_bytes = sizeof (snat_runtime_t),
2813 
2814  .n_next_nodes = NAT44_ED_OUT2IN_N_NEXT,
2815 
2816  /* edit / add dispositions here */
2817  .next_nodes = {
2818  [NAT44_ED_OUT2IN_NEXT_DROP] = "error-drop",
2819  [NAT44_ED_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2820  [NAT44_ED_OUT2IN_NEXT_SLOW_PATH] = "nat44-ed-out2in-slowpath",
2821  [NAT44_ED_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2822  [NAT44_ED_OUT2IN_NEXT_IN2OUT] = "nat44-ed-in2out",
2823  },
2824 };
2825 
2828 
2829 /**************************/
2830 /*** deterministic mode ***/
2831 /**************************/
2832 static uword
2834  vlib_node_runtime_t * node,
2835  vlib_frame_t * frame)
2836 {
2837  u32 n_left_from, * from, * to_next;
2838  snat_out2in_next_t next_index;
2839  u32 pkts_processed = 0;
2840  snat_main_t * sm = &snat_main;
2841  u32 thread_index = vm->thread_index;
2842 
2843  from = vlib_frame_vector_args (frame);
2844  n_left_from = frame->n_vectors;
2845  next_index = node->cached_next_index;
2846 
2847  while (n_left_from > 0)
2848  {
2849  u32 n_left_to_next;
2850 
2851  vlib_get_next_frame (vm, node, next_index,
2852  to_next, n_left_to_next);
2853 
2854  while (n_left_from >= 4 && n_left_to_next >= 2)
2855  {
2856  u32 bi0, bi1;
2857  vlib_buffer_t * b0, * b1;
2858  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
2859  u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
2860  u32 sw_if_index0, sw_if_index1;
2861  ip4_header_t * ip0, * ip1;
2862  ip_csum_t sum0, sum1;
2863  ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
2864  u16 new_port0, old_port0, old_port1, new_port1;
2865  udp_header_t * udp0, * udp1;
2866  tcp_header_t * tcp0, * tcp1;
2867  u32 proto0, proto1;
2868  snat_det_out_key_t key0, key1;
2869  snat_det_map_t * dm0, * dm1;
2870  snat_det_session_t * ses0 = 0, * ses1 = 0;
2871  u32 rx_fib_index0, rx_fib_index1;
2872  icmp46_header_t * icmp0, * icmp1;
2873 
2874  /* Prefetch next iteration. */
2875  {
2876  vlib_buffer_t * p2, * p3;
2877 
2878  p2 = vlib_get_buffer (vm, from[2]);
2879  p3 = vlib_get_buffer (vm, from[3]);
2880 
2881  vlib_prefetch_buffer_header (p2, LOAD);
2882  vlib_prefetch_buffer_header (p3, LOAD);
2883 
2886  }
2887 
2888  /* speculatively enqueue b0 and b1 to the current next frame */
2889  to_next[0] = bi0 = from[0];
2890  to_next[1] = bi1 = from[1];
2891  from += 2;
2892  to_next += 2;
2893  n_left_from -= 2;
2894  n_left_to_next -= 2;
2895 
2896  b0 = vlib_get_buffer (vm, bi0);
2897  b1 = vlib_get_buffer (vm, bi1);
2898 
2899  ip0 = vlib_buffer_get_current (b0);
2900  udp0 = ip4_next_header (ip0);
2901  tcp0 = (tcp_header_t *) udp0;
2902 
2903  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2904 
2905  if (PREDICT_FALSE(ip0->ttl == 1))
2906  {
2907  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2908  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2909  ICMP4_time_exceeded_ttl_exceeded_in_transit,
2910  0);
2912  goto trace0;
2913  }
2914 
2915  proto0 = ip_proto_to_snat_proto (ip0->protocol);
2916 
2917  if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
2918  {
2919  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2920  icmp0 = (icmp46_header_t *) udp0;
2921 
2922  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2923  rx_fib_index0, node, next0, thread_index,
2924  &ses0, &dm0);
2925  goto trace0;
2926  }
2927 
2928  key0.ext_host_addr = ip0->src_address;
2929  key0.ext_host_port = tcp0->src;
2930  key0.out_port = tcp0->dst;
2931 
2932  dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
2933  if (PREDICT_FALSE(!dm0))
2934  {
2935  nat_log_info ("unknown dst address: %U",
2937  next0 = SNAT_OUT2IN_NEXT_DROP;
2938  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2939  goto trace0;
2940  }
2941 
2942  snat_det_reverse(dm0, &ip0->dst_address,
2943  clib_net_to_host_u16(tcp0->dst), &new_addr0);
2944 
2945  ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
2946  if (PREDICT_FALSE(!ses0))
2947  {
2948  nat_log_info ("no match src %U:%d dst %U:%d for user %U",
2950  clib_net_to_host_u16 (tcp0->src),
2952  clib_net_to_host_u16 (tcp0->dst),
2953  format_ip4_address, &new_addr0);
2954  next0 = SNAT_OUT2IN_NEXT_DROP;
2955  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2956  goto trace0;
2957  }
2958  new_port0 = ses0->in_port;
2959 
2960  old_addr0 = ip0->dst_address;
2961  ip0->dst_address = new_addr0;
2962  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
2963 
2964  sum0 = ip0->checksum;
2965  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2966  ip4_header_t,
2967  dst_address /* changed member */);
2968  ip0->checksum = ip_csum_fold (sum0);
2969 
2970  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2971  {
2972  if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
2973  ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
2974  else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
2975  snat_det_ses_close(dm0, ses0);
2976 
2977  old_port0 = tcp0->dst;
2978  tcp0->dst = new_port0;
2979 
2980  sum0 = tcp0->checksum;
2981  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2982  ip4_header_t,
2983  dst_address /* changed member */);
2984 
2985  sum0 = ip_csum_update (sum0, old_port0, new_port0,
2986  ip4_header_t /* cheat */,
2987  length /* changed member */);
2988  tcp0->checksum = ip_csum_fold(sum0);
2989  }
2990  else
2991  {
2992  old_port0 = udp0->dst_port;
2993  udp0->dst_port = new_port0;
2994  udp0->checksum = 0;
2995  }
2996 
2997  trace0:
2998 
3000  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
3001  {
3002  snat_out2in_trace_t *t =
3003  vlib_add_trace (vm, node, b0, sizeof (*t));
3004  t->sw_if_index = sw_if_index0;
3005  t->next_index = next0;
3006  t->session_index = ~0;
3007  if (ses0)
3008  t->session_index = ses0 - dm0->sessions;
3009  }
3010 
3011  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
3012 
3013  b1 = vlib_get_buffer (vm, bi1);
3014 
3015  ip1 = vlib_buffer_get_current (b1);
3016  udp1 = ip4_next_header (ip1);
3017  tcp1 = (tcp_header_t *) udp1;
3018 
3019  sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
3020 
3021  if (PREDICT_FALSE(ip1->ttl == 1))
3022  {
3023  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
3024  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
3025  ICMP4_time_exceeded_ttl_exceeded_in_transit,
3026  0);
3028  goto trace1;
3029  }
3030 
3031  proto1 = ip_proto_to_snat_proto (ip1->protocol);
3032 
3033  if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP))
3034  {
3035  rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1);
3036  icmp1 = (icmp46_header_t *) udp1;
3037 
3038  next1 = icmp_out2in(sm, b1, ip1, icmp1, sw_if_index1,
3039  rx_fib_index1, node, next1, thread_index,
3040  &ses1, &dm1);
3041  goto trace1;
3042  }
3043 
3044  key1.ext_host_addr = ip1->src_address;
3045  key1.ext_host_port = tcp1->src;
3046  key1.out_port = tcp1->dst;
3047 
3048  dm1 = snat_det_map_by_out(sm, &ip1->dst_address);
3049  if (PREDICT_FALSE(!dm1))
3050  {
3051  nat_log_info ("unknown dst address: %U",
3053  next1 = SNAT_OUT2IN_NEXT_DROP;
3054  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3055  goto trace1;
3056  }
3057 
3058  snat_det_reverse(dm1, &ip1->dst_address,
3059  clib_net_to_host_u16(tcp1->dst), &new_addr1);
3060 
3061  ses1 = snat_det_get_ses_by_out (dm1, &new_addr1, key1.as_u64);
3062  if (PREDICT_FALSE(!ses1))
3063  {
3064  nat_log_info ("no match src %U:%d dst %U:%d for user %U",
3066  clib_net_to_host_u16 (tcp1->src),
3068  clib_net_to_host_u16 (tcp1->dst),
3069  format_ip4_address, &new_addr1);
3070  next1 = SNAT_OUT2IN_NEXT_DROP;
3071  b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3072  goto trace1;
3073  }
3074  new_port1 = ses1->in_port;
3075 
3076  old_addr1 = ip1->dst_address;
3077  ip1->dst_address = new_addr1;
3078  vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
3079 
3080  sum1 = ip1->checksum;
3081  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
3082  ip4_header_t,
3083  dst_address /* changed member */);
3084  ip1->checksum = ip_csum_fold (sum1);
3085 
3086  if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
3087  {
3088  if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
3089  ses1->state = SNAT_SESSION_TCP_CLOSE_WAIT;
3090  else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_LAST_ACK)
3091  snat_det_ses_close(dm1, ses1);
3092 
3093  old_port1 = tcp1->dst;
3094  tcp1->dst = new_port1;
3095 
3096  sum1 = tcp1->checksum;
3097  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
3098  ip4_header_t,
3099  dst_address /* changed member */);
3100 
3101  sum1 = ip_csum_update (sum1, old_port1, new_port1,
3102  ip4_header_t /* cheat */,
3103  length /* changed member */);
3104  tcp1->checksum = ip_csum_fold(sum1);
3105  }
3106  else
3107  {
3108  old_port1 = udp1->dst_port;
3109  udp1->dst_port = new_port1;
3110  udp1->checksum = 0;
3111  }
3112 
3113  trace1:
3114 
3116  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
3117  {
3118  snat_out2in_trace_t *t =
3119  vlib_add_trace (vm, node, b1, sizeof (*t));
3120  t->sw_if_index = sw_if_index1;
3121  t->next_index = next1;
3122  t->session_index = ~0;
3123  if (ses1)
3124  t->session_index = ses1 - dm1->sessions;
3125  }
3126 
3127  pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
3128 
3129  /* verify speculative enqueues, maybe switch current next frame */
3130  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
3131  to_next, n_left_to_next,
3132  bi0, bi1, next0, next1);
3133  }
3134 
3135  while (n_left_from > 0 && n_left_to_next > 0)
3136  {
3137  u32 bi0;
3138  vlib_buffer_t * b0;
3139  u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
3140  u32 sw_if_index0;
3141  ip4_header_t * ip0;
3142  ip_csum_t sum0;
3143  ip4_address_t new_addr0, old_addr0;
3144  u16 new_port0, old_port0;
3145  udp_header_t * udp0;
3146  tcp_header_t * tcp0;
3147  u32 proto0;
3148  snat_det_out_key_t key0;
3149  snat_det_map_t * dm0;
3150  snat_det_session_t * ses0 = 0;
3151  u32 rx_fib_index0;
3152  icmp46_header_t * icmp0;
3153 
3154  /* speculatively enqueue b0 to the current next frame */
3155  bi0 = from[0];
3156  to_next[0] = bi0;
3157  from += 1;
3158  to_next += 1;
3159  n_left_from -= 1;
3160  n_left_to_next -= 1;
3161 
3162  b0 = vlib_get_buffer (vm, bi0);
3163 
3164  ip0 = vlib_buffer_get_current (b0);
3165  udp0 = ip4_next_header (ip0);
3166  tcp0 = (tcp_header_t *) udp0;
3167 
3168  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
3169 
3170  if (PREDICT_FALSE(ip0->ttl == 1))
3171  {
3172  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
3173  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
3174  ICMP4_time_exceeded_ttl_exceeded_in_transit,
3175  0);
3177  goto trace00;
3178  }
3179 
3180  proto0 = ip_proto_to_snat_proto (ip0->protocol);
3181 
3182  if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
3183  {
3184  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
3185  icmp0 = (icmp46_header_t *) udp0;
3186 
3187  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
3188  rx_fib_index0, node, next0, thread_index,
3189  &ses0, &dm0);
3190  goto trace00;
3191  }
3192 
3193  key0.ext_host_addr = ip0->src_address;
3194  key0.ext_host_port = tcp0->src;
3195  key0.out_port = tcp0->dst;
3196 
3197  dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
3198  if (PREDICT_FALSE(!dm0))
3199  {
3200  nat_log_info ("unknown dst address: %U",
3202  next0 = SNAT_OUT2IN_NEXT_DROP;
3203  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3204  goto trace00;
3205  }
3206 
3207  snat_det_reverse(dm0, &ip0->dst_address,
3208  clib_net_to_host_u16(tcp0->dst), &new_addr0);
3209 
3210  ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
3211  if (PREDICT_FALSE(!ses0))
3212  {
3213  nat_log_info ("no match src %U:%d dst %U:%d for user %U",
3215  clib_net_to_host_u16 (tcp0->src),
3217  clib_net_to_host_u16 (tcp0->dst),
3218  format_ip4_address, &new_addr0);
3219  next0 = SNAT_OUT2IN_NEXT_DROP;
3220  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3221  goto trace00;
3222  }
3223  new_port0 = ses0->in_port;
3224 
3225  old_addr0 = ip0->dst_address;
3226  ip0->dst_address = new_addr0;
3227  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
3228 
3229  sum0 = ip0->checksum;
3230  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
3231  ip4_header_t,
3232  dst_address /* changed member */);
3233  ip0->checksum = ip_csum_fold (sum0);
3234 
3235  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
3236  {
3237  if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
3238  ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
3239  else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
3240  snat_det_ses_close(dm0, ses0);
3241 
3242  old_port0 = tcp0->dst;
3243  tcp0->dst = new_port0;
3244 
3245  sum0 = tcp0->checksum;
3246  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
3247  ip4_header_t,
3248  dst_address /* changed member */);
3249 
3250  sum0 = ip_csum_update (sum0, old_port0, new_port0,
3251  ip4_header_t /* cheat */,
3252  length /* changed member */);
3253  tcp0->checksum = ip_csum_fold(sum0);
3254  }
3255  else
3256  {
3257  old_port0 = udp0->dst_port;
3258  udp0->dst_port = new_port0;
3259  udp0->checksum = 0;
3260  }
3261 
3262  trace00:
3263 
3265  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
3266  {
3267  snat_out2in_trace_t *t =
3268  vlib_add_trace (vm, node, b0, sizeof (*t));
3269  t->sw_if_index = sw_if_index0;
3270  t->next_index = next0;
3271  t->session_index = ~0;
3272  if (ses0)
3273  t->session_index = ses0 - dm0->sessions;
3274  }
3275 
3276  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
3277 
3278  /* verify speculative enqueue, maybe switch current next frame */
3279  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3280  to_next, n_left_to_next,
3281  bi0, next0);
3282  }
3283 
3284  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3285  }
3286 
3288  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
3289  pkts_processed);
3290  return frame->n_vectors;
3291 }
3292 
3294  .function = snat_det_out2in_node_fn,
3295  .name = "nat44-det-out2in",
3296  .vector_size = sizeof (u32),
3297  .format_trace = format_snat_out2in_trace,
3298  .type = VLIB_NODE_TYPE_INTERNAL,
3299 
3300  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
3301  .error_strings = snat_out2in_error_strings,
3302 
3303  .runtime_data_bytes = sizeof (snat_runtime_t),
3304 
3305  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
3306 
3307  /* edit / add dispositions here */
3308  .next_nodes = {
3309  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
3310  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
3311  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
3312  [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
3313  },
3314 };
3316 
3317 /**
3318  * Get address and port values to be used for ICMP packet translation
3319  * and create session if needed
3320  *
3321  * @param[in,out] sm NAT main
3322  * @param[in,out] node NAT node runtime
3323  * @param[in] thread_index thread index
3324  * @param[in,out] b0 buffer containing packet to be translated
3325  * @param[out] p_proto protocol used for matching
3326  * @param[out] p_value address and port after NAT translation
3327  * @param[out] p_dont_translate if packet should not be translated
3328  * @param d optional parameter
3329  * @param e optional parameter
3330  */
3332  u32 thread_index, vlib_buffer_t *b0,
3333  ip4_header_t *ip0, u8 *p_proto,
3334  snat_session_key_t *p_value,
3335  u8 *p_dont_translate, void *d, void *e)
3336 {
3337  icmp46_header_t *icmp0;
3338  u32 sw_if_index0;
3339  u8 protocol;
3340  snat_det_out_key_t key0;
3341  u8 dont_translate = 0;
3342  u32 next0 = ~0;
3343  icmp_echo_header_t *echo0, *inner_echo0 = 0;
3344  ip4_header_t *inner_ip0;
3345  void *l4_header = 0;
3346  icmp46_header_t *inner_icmp0;
3347  snat_det_map_t * dm0 = 0;
3348  ip4_address_t new_addr0 = {{0}};
3349  snat_det_session_t * ses0 = 0;
3350  ip4_address_t out_addr;
3351 
3352  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
3353  echo0 = (icmp_echo_header_t *)(icmp0+1);
3354  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
3355 
3356  if (!icmp_is_error_message (icmp0))
3357  {
3358  protocol = SNAT_PROTOCOL_ICMP;
3359  key0.ext_host_addr = ip0->src_address;
3360  key0.ext_host_port = 0;
3361  key0.out_port = echo0->identifier;
3362  out_addr = ip0->dst_address;
3363  }
3364  else
3365  {
3366  inner_ip0 = (ip4_header_t *)(echo0+1);
3367  l4_header = ip4_next_header (inner_ip0);
3368  protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
3369  key0.ext_host_addr = inner_ip0->dst_address;
3370  out_addr = inner_ip0->src_address;
3371  switch (protocol)
3372  {
3373  case SNAT_PROTOCOL_ICMP:
3374  inner_icmp0 = (icmp46_header_t*)l4_header;
3375  inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
3376  key0.ext_host_port = 0;
3377  key0.out_port = inner_echo0->identifier;
3378  break;
3379  case SNAT_PROTOCOL_UDP:
3380  case SNAT_PROTOCOL_TCP:
3381  key0.ext_host_port = ((tcp_udp_header_t*)l4_header)->dst_port;
3382  key0.out_port = ((tcp_udp_header_t*)l4_header)->src_port;
3383  break;
3384  default:
3385  b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
3386  next0 = SNAT_OUT2IN_NEXT_DROP;
3387  goto out;
3388  }
3389  }
3390 
3391  dm0 = snat_det_map_by_out(sm, &out_addr);
3392  if (PREDICT_FALSE(!dm0))
3393  {
3394  /* Don't NAT packet aimed at the intfc address */
3395  if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
3396  ip0->dst_address.as_u32)))
3397  {
3398  dont_translate = 1;
3399  goto out;
3400  }
3401  nat_log_info ("unknown dst address: %U",
3403  goto out;
3404  }
3405 
3406  snat_det_reverse(dm0, &ip0->dst_address,
3407  clib_net_to_host_u16(key0.out_port), &new_addr0);
3408 
3409  ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
3410  if (PREDICT_FALSE(!ses0))
3411  {
3412  /* Don't NAT packet aimed at the intfc address */
3413  if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
3414  ip0->dst_address.as_u32)))
3415  {
3416  dont_translate = 1;
3417  goto out;
3418  }
3419  nat_log_info ("no match src %U:%d dst %U:%d for user %U",
3421  clib_net_to_host_u16 (key0.ext_host_port),
3422  format_ip4_address, &out_addr,
3423  clib_net_to_host_u16 (key0.out_port),
3424  format_ip4_address, &new_addr0);
3425  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3426  next0 = SNAT_OUT2IN_NEXT_DROP;
3427  goto out;
3428  }
3429 
3430  if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
3431  !icmp_is_error_message (icmp0)))
3432  {
3433  b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
3434  next0 = SNAT_OUT2IN_NEXT_DROP;
3435  goto out;
3436  }
3437 
3438  goto out;
3439 
3440 out:
3441  *p_proto = protocol;
3442  if (ses0)
3443  {
3444  p_value->addr = new_addr0;
3445  p_value->fib_index = sm->inside_fib_index;
3446  p_value->port = ses0->in_port;
3447  }
3448  *p_dont_translate = dont_translate;
3449  if (d)
3450  *(snat_det_session_t**)d = ses0;
3451  if (e)
3452  *(snat_det_map_t**)e = dm0;
3453  return next0;
3454 }
3455 
3456 /**********************/
3457 /*** worker handoff ***/
3458 /**********************/
3459 static uword
3461  vlib_node_runtime_t * node,
3462  vlib_frame_t * frame)
3463 {
3464  snat_main_t *sm = &snat_main;
3466  u32 n_left_from, *from, *to_next = 0, *to_next_drop = 0;
3467  static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
3468  static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
3469  = 0;
3470  vlib_frame_queue_elt_t *hf = 0;
3471  vlib_frame_queue_t *fq;
3472  vlib_frame_t *f = 0;
3473  int i;
3474  u32 n_left_to_next_worker = 0, *to_next_worker = 0;
3475  u32 next_worker_index = 0;
3476  u32 current_worker_index = ~0;
3477  u32 thread_index = vm->thread_index;
3478  vlib_frame_t *d = 0;
3479 
3480  ASSERT (vec_len (sm->workers));
3481 
3482  if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0))
3483  {
3484  vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
3485 
3486  vec_validate_init_empty (congested_handoff_queue_by_worker_index,
3487  tm->n_vlib_mains - 1,
3488  (vlib_frame_queue_t *) (~0));
3489  }
3490 
3491  from = vlib_frame_vector_args (frame);
3492  n_left_from = frame->n_vectors;
3493 
3494  while (n_left_from > 0)
3495  {
3496  u32 bi0;
3497  vlib_buffer_t *b0;
3498  u32 sw_if_index0;
3499  u32 rx_fib_index0;
3500  ip4_header_t * ip0;
3501  u8 do_handoff;
3502 
3503  bi0 = from[0];
3504  from += 1;
3505  n_left_from -= 1;
3506 
3507  b0 = vlib_get_buffer (vm, bi0);
3508 
3509  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
3510  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
3511 
3512  ip0 = vlib_buffer_get_current (b0);
3513 
3514  next_worker_index = sm->worker_out2in_cb(ip0, rx_fib_index0);
3515 
3516  if (PREDICT_FALSE (next_worker_index != thread_index))
3517  {
3518  do_handoff = 1;
3519 
3520  if (next_worker_index != current_worker_index)
3521  {
3523  sm->fq_out2in_index, next_worker_index, NAT_FQ_NELTS - 2,
3524  congested_handoff_queue_by_worker_index);
3525 
3526  if (fq)
3527  {
3528  /* if this is 1st frame */
3529  if (!d)
3530  {
3532  to_next_drop = vlib_frame_vector_args (d);
3533  }
3534 
3535  to_next_drop[0] = bi0;
3536  to_next_drop += 1;
3537  d->n_vectors++;
3538  b0->error = node->errors[SNAT_OUT2IN_ERROR_FQ_CONGESTED];
3539  goto trace0;
3540  }
3541 
3542  if (hf)
3543  hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
3544 
3546  next_worker_index,
3547  handoff_queue_elt_by_worker_index);
3548 
3549  n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors;
3550  to_next_worker = &hf->buffer_index[hf->n_vectors];
3551  current_worker_index = next_worker_index;
3552  }
3553 
3554  /* enqueue to correct worker thread */
3555  to_next_worker[0] = bi0;
3556  to_next_worker++;
3557  n_left_to_next_worker--;
3558 
3559  if (n_left_to_next_worker == 0)
3560  {
3561  hf->n_vectors = VLIB_FRAME_SIZE;
3563  current_worker_index = ~0;
3564  handoff_queue_elt_by_worker_index[next_worker_index] = 0;
3565  hf = 0;
3566  }
3567  }
3568  else
3569  {
3570  do_handoff = 0;
3571  /* if this is 1st frame */
3572  if (!f)
3573  {
3575  to_next = vlib_frame_vector_args (f);
3576  }
3577 
3578  to_next[0] = bi0;
3579  to_next += 1;
3580  f->n_vectors++;
3581  }
3582 
3583 trace0:
3585  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
3586  {
3588  vlib_add_trace (vm, node, b0, sizeof (*t));
3589  t->next_worker_index = next_worker_index;
3590  t->do_handoff = do_handoff;
3591  }
3592  }
3593 
3594  if (f)
3596 
3597  if (d)
3599 
3600  if (hf)
3601  hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
3602 
3603  /* Ship frames to the worker nodes */
3604  for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++)
3605  {
3606  if (handoff_queue_elt_by_worker_index[i])
3607  {
3608  hf = handoff_queue_elt_by_worker_index[i];
3609  /*
3610  * It works better to let the handoff node
3611  * rate-adapt, always ship the handoff queue element.
3612  */
3613  if (1 || hf->n_vectors == hf->last_n_vectors)
3614  {
3616  handoff_queue_elt_by_worker_index[i] = 0;
3617  }
3618  else
3619  hf->last_n_vectors = hf->n_vectors;
3620  }
3621  congested_handoff_queue_by_worker_index[i] =
3622  (vlib_frame_queue_t *) (~0);
3623  }
3624  hf = 0;
3625  current_worker_index = ~0;
3626  return frame->n_vectors;
3627 }
3628 
3630  .function = snat_out2in_worker_handoff_fn,
3631  .name = "nat44-out2in-worker-handoff",
3632  .vector_size = sizeof (u32),
3634  .type = VLIB_NODE_TYPE_INTERNAL,
3635 
3636  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
3637  .error_strings = snat_out2in_error_strings,
3638 
3639  .n_next_nodes = 1,
3640 
3641  .next_nodes = {
3642  [0] = "error-drop",
3643  },
3644 };
3645 
3647 
3648 static uword
3650  vlib_node_runtime_t * node,
3651  vlib_frame_t * frame)
3652 {
3653  u32 n_left_from, * from, * to_next;
3654  snat_out2in_next_t next_index;
3655  u32 pkts_processed = 0;
3656  snat_main_t * sm = &snat_main;
3657 
3658  from = vlib_frame_vector_args (frame);
3659  n_left_from = frame->n_vectors;
3660  next_index = node->cached_next_index;
3661 
3662  while (n_left_from > 0)
3663  {
3664  u32 n_left_to_next;
3665 
3666  vlib_get_next_frame (vm, node, next_index,
3667  to_next, n_left_to_next);
3668 
3669  while (n_left_from > 0 && n_left_to_next > 0)
3670  {
3671  u32 bi0;
3672  vlib_buffer_t * b0;
3673  u32 next0 = SNAT_OUT2IN_NEXT_DROP;
3674  u32 sw_if_index0;
3675  ip4_header_t * ip0;
3676  ip_csum_t sum0;
3677  u32 new_addr0, old_addr0;
3678  u16 new_port0, old_port0;
3679  udp_header_t * udp0;
3680  tcp_header_t * tcp0;
3681  icmp46_header_t * icmp0;
3682  snat_session_key_t key0, sm0;
3683  u32 proto0;
3684  u32 rx_fib_index0;
3685 
3686  /* speculatively enqueue b0 to the current next frame */
3687  bi0 = from[0];
3688  to_next[0] = bi0;
3689  from += 1;
3690  to_next += 1;
3691  n_left_from -= 1;
3692  n_left_to_next -= 1;
3693 
3694  b0 = vlib_get_buffer (vm, bi0);
3695 
3696  ip0 = vlib_buffer_get_current (b0);
3697  udp0 = ip4_next_header (ip0);
3698  tcp0 = (tcp_header_t *) udp0;
3699  icmp0 = (icmp46_header_t *) udp0;
3700 
3701  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
3702  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
3703 
3704  vnet_feature_next (sw_if_index0, &next0, b0);
3705 
3706  if (PREDICT_FALSE(ip0->ttl == 1))
3707  {
3708  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
3709  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
3710  ICMP4_time_exceeded_ttl_exceeded_in_transit,
3711  0);
3713  goto trace00;
3714  }
3715 
3716  proto0 = ip_proto_to_snat_proto (ip0->protocol);
3717 
3718  if (PREDICT_FALSE (proto0 == ~0))
3719  goto trace00;
3720 
3721  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
3722  {
3723  next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
3724  rx_fib_index0, node, next0, ~0, 0, 0);
3725  goto trace00;
3726  }
3727 
3728  key0.addr = ip0->dst_address;
3729  key0.port = udp0->dst_port;
3730  key0.fib_index = rx_fib_index0;
3731 
3732  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
3733  {
3734  b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3735  goto trace00;
3736  }
3737 
3738  new_addr0 = sm0.addr.as_u32;
3739  new_port0 = sm0.port;
3740  vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
3741  old_addr0 = ip0->dst_address.as_u32;
3742  ip0->dst_address.as_u32 = new_addr0;
3743 
3744  sum0 = ip0->checksum;
3745  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
3746  ip4_header_t,
3747  dst_address /* changed member */);
3748  ip0->checksum = ip_csum_fold (sum0);
3749 
3750  if (PREDICT_FALSE(new_port0 != udp0->dst_port))
3751  {
3752  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
3753  {
3754  old_port0 = tcp0->dst_port;
3755  tcp0->dst_port = new_port0;
3756 
3757  sum0 = tcp0->checksum;
3758  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
3759  ip4_header_t,
3760  dst_address /* changed member */);
3761 
3762  sum0 = ip_csum_update (sum0, old_port0, new_port0,
3763  ip4_header_t /* cheat */,
3764  length /* changed member */);
3765  tcp0->checksum = ip_csum_fold(sum0);
3766  }
3767  else
3768  {
3769  old_port0 = udp0->dst_port;
3770  udp0->dst_port = new_port0;
3771  udp0->checksum = 0;
3772  }
3773  }
3774  else
3775  {
3776  if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
3777  {
3778  sum0 = tcp0->checksum;
3779  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
3780  ip4_header_t,
3781  dst_address /* changed member */);
3782 
3783  tcp0->checksum = ip_csum_fold(sum0);
3784  }
3785  }
3786 
3787  trace00:
3788 
3790  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
3791  {
3792  snat_out2in_trace_t *t =
3793  vlib_add_trace (vm, node, b0, sizeof (*t));
3794  t->sw_if_index = sw_if_index0;
3795  t->next_index = next0;
3796  }
3797 
3798  pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
3799 
3800  /* verify speculative enqueue, maybe switch current next frame */
3801  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3802  to_next, n_left_to_next,
3803  bi0, next0);
3804  }
3805 
3806  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3807  }
3808 
3810  SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
3811  pkts_processed);
3812  return frame->n_vectors;
3813 }
3814 
3816  .function = snat_out2in_fast_node_fn,
3817  .name = "nat44-out2in-fast",
3818  .vector_size = sizeof (u32),
3819  .format_trace = format_snat_out2in_fast_trace,
3820  .type = VLIB_NODE_TYPE_INTERNAL,
3821 
3822  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
3823  .error_strings = snat_out2in_error_strings,
3824 
3825  .runtime_data_bytes = sizeof (snat_runtime_t),
3826 
3827  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
3828 
3829  /* edit / add dispositions here */
3830  .next_nodes = {
3831  [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
3832  [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
3833  [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
3834  [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
3835  },
3836 };
vlib_node_registration_t snat_out2in_fast_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_fast_node)
Definition: out2in.c:103
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:437
VLIB_NODE_FUNCTION_MULTIARCH(snat_out2in_node, snat_out2in_node_fn)
#define nat_log_info(...)
Definition: nat.h:531
#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:286
u16 ext_host_port
Definition: nat.h:82
u16 out_port
Definition: nat.h:83
ip4_address_t src_address
Definition: ip4_packet.h:169
static u8 * format_snat_out2in_fast_trace(u8 *s, va_list *args)
Definition: out2in.c:58
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:589
#define PREDICT_TRUE(x)
Definition: clib.h:106
static_always_inline u8 icmp_is_error_message(icmp46_header_t *icmp)
Definition: nat_inlines.h:52
static int ip4_header_bytes(ip4_header_t *i)
Definition: ip4_packet.h:234
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:228
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:948
static snat_session_t * create_session_for_static_mapping_ed(snat_main_t *sm, vlib_buffer_t *b, snat_session_key_t l_key, snat_session_key_t e_key, vlib_node_runtime_t *node, u32 thread_index, twice_nat_type_t twice_nat, u8 is_lb)
Definition: out2in.c:1572
static void make_sm_kv(clib_bihash_kv_8_8_t *kv, ip4_address_t *addr, u8 proto, u32 fib_index, u16 port)
Definition: nat_inlines.h:260
u16 port_per_thread
Definition: nat.h:332
u32 thread_index
Definition: main.h:179
#define nat_log_warn(...)
Definition: nat.h:527
static void snat_det_ses_close(snat_det_map_t *dm, snat_det_session_t *ses)
Definition: nat_det.h:180
int i
u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: out2in.c:3331
uword ip_csum_t
Definition: ip_packet.h:181
u32 * fib_index_by_sw_if_index
Table index indexed by software interface.
Definition: ip4.h:111
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u32 buffer_index[VLIB_FRAME_SIZE]
Definition: threads.h:98
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:451
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:250
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:67
static vlib_frame_queue_t * is_vlib_frame_queue_congested(u32 frame_queue_index, u32 index, u32 queue_hi_thresh, vlib_frame_queue_t **handoff_queue_by_worker_index)
Definition: threads.h:492
unsigned char u8
Definition: types.h:56
static u8 * format_nat44_ed_out2in_trace(u8 *s, va_list *args)
Definition: out2in.c:1556
static int nat44_set_tcp_session_state_o2i(snat_main_t *sm, snat_session_t *ses, tcp_header_t *tcp, u32 thread_index)
Definition: nat_inlines.h:199
u16 l_port
Definition: nat.h:69
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
u16 identifier
Definition: nat.h:543
static uword nat44_ed_out2in_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_slow_path)
Definition: out2in.c:2034
clib_bihash_8_8_t in2out
Definition: nat.h:279
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:224
format_function_t format_ip4_address
Definition: format.h:81
static snat_session_t * nat44_ed_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:1929
#define static_always_inline
Definition: clib.h:93
static uword ip4_header_checksum_is_valid(ip4_header_t *i)
Definition: ip4_packet.h:267
vlib_node_registration_t snat_det_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_det_out2in_node)
Definition: out2in.c:105
u16 r_port
Definition: nat.h:70
ip4_address_t ext_host_addr
Definition: nat.h:81
ip4_address_t dst_address
Definition: ip4_packet.h:169
#define TCP_FLAG_ACK
Definition: fa_node.h:16
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:184
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, twice_nat_type_t *twice_nat, u8 *lb)
Match NAT44 static mapping.
Definition: nat.c:2137
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:423
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:240
unsigned int u32
Definition: types.h:88
#define foreach_snat_out2in_error
Definition: out2in.c:110
ip4_address_t local_addr
Definition: nat.h:243
#define VLIB_FRAME_SIZE
Definition: node.h:364
static uword nat44_out2in_reass_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:1250
u64 as_u64[2]
Definition: nat.h:72
static u8 maximum_sessions_exceeded(snat_main_t *sm, u32 thread_index)
Definition: nat_inlines.h:93
static uword snat_out2in_worker_handoff_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:3460
static void nat44_delete_session(snat_main_t *sm, snat_session_t *ses, u32 thread_index)
Definition: nat_inlines.h:144
static uword nat44_ed_out2in_slow_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:2795
static int ip4_is_fragment(ip4_header_t *i)
Definition: ip4_packet.h:212
snat_out2in_next_t
Definition: out2in.c:135
u32 fib_index
Definition: nat.h:67
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:288
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:464
static int next_src_nat(snat_main_t *sm, ip4_header_t *ip, u8 proto, u16 src_port, u16 dst_port, u32 thread_index, u32 rx_fib_index)
Definition: out2in.c:1717
clib_bihash_16_8_t out2in_ed
Definition: nat.h:282
snat_det_session_t * sessions
Definition: nat.h:226
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:421
unsigned short u16
Definition: types.h:57
u16 protocol
Definition: nat.h:53
snat_static_mapping_t * static_mappings
Definition: nat.h:345
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:406
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:202
nat44_ed_out2in_next_t
Definition: out2in.c:1539
#define NAT_FQ_NELTS
Definition: nat.h:41
#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:524
clib_bihash_8_8_t static_mapping_by_external
Definition: nat.h:342
#define TCP_FLAG_FIN
Definition: fa_node.h:12
#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:102
#define SNAT_SESSION_FLAG_UNKNOWN_PROTO
Definition: nat.h:140
static_always_inline void vnet_feature_next(u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:237
#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
#define nat_log_notice(...)
Definition: nat.h:529
vlib_node_registration_t nat44_ed_out2in_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_out2in_node)
Definition: out2in.c:107
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:135
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1168
u32 fq_out2in_index
Definition: nat.h:377
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:463
snat_main_t snat_main
Definition: nat.c:36
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:158
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:153
u16 n_vectors
Definition: node.h:380
clib_bihash_8_8_t out2in
Definition: nat.h:278
u8 nat_reass_is_drop_frag(u8 is_ip6)
Get status of virtual fragmentation reassembly.
Definition: nat_reass.c:168
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:77
vlib_main_t * vm
Definition: buffer.c:294
ip4_address_t l_addr
Definition: nat.h:65
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.c:431
deterministic NAT definitions
static ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_packet.h:254
u32 error_node_index
Definition: nat.h:383
#define clib_memcpy(a, b, c)
Definition: string.h:75
static int ip4_is_first_fragment(ip4_header_t *i)
Definition: ip4_packet.h:219
static void nat44_session_update_counters(snat_session_t *s, f64 now, uword bytes)
Definition: nat_inlines.h:224
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:51
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:89
static void make_ed_kv(clib_bihash_kv_16_8_t *kv, ip4_address_t *l_addr, ip4_address_t *r_addr, u8 proto, u32 fib_index, u16 l_port, u16 r_port)
Definition: nat_inlines.h:243
ip4_address_t r_addr
Definition: nat.h:66
u32 icmp_match_out2in_ed(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b, ip4_header_t *ip, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Definition: out2in.c:1822
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:492
#define ASSERT(truth)
Definition: nat.h:238
snat_get_worker_function_t * worker_out2in_cb
Definition: nat.h:331
snat_icmp_match_function_t * icmp_match_out2in_cb
Definition: nat.h:325
#define SNAT_SESSION_FLAG_TWICE_NAT
Definition: nat.h:142
static uword snat_det_out2in_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:2833
static void nat44_session_update_lru(snat_main_t *sm, snat_session_t *s, u32 thread_index)
Per-user LRU list maintenance.
Definition: nat_inlines.h:233
#define SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT
Definition: nat.h:143
u32 out2in_node_index
Definition: nat.h:382
vlib_node_registration_t nat44_out2in_reass_node
(constructor) VLIB_REGISTER_NODE (nat44_out2in_reass_node)
Definition: out2in.c:106
snat_address_t * twice_nat_addresses
Definition: nat.h:362
snat_session_t * nat_session_alloc_or_recycle(snat_main_t *sm, snat_user_t *u, u32 thread_index)
Definition: nat.c:332
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
#define vec_elt(v, i)
Get vector value at index i.
struct _vlib_node_registration vlib_node_registration_t
Definition: defs.h:47
vlib_node_registration_t snat_out2in_worker_handoff_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node)
Definition: out2in.c:104
snat_out2in_error_t
Definition: out2in.c:122
#define SNAT_SESSION_FLAG_FWD_BYPASS
Definition: nat.h:144
static u32 ip_proto_to_snat_proto(u8 ip_proto)
The NAT inline functions.
Definition: nat_inlines.h:25
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:2241
static void user_session_increment(snat_main_t *sm, snat_user_t *u, u8 is_static)
Definition: nat_inlines.h:132
twice_nat_type_t
Definition: nat.h:236
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
static char * snat_out2in_error_strings[]
Definition: out2in.c:129
static int nat_out2in_sm_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index)
Definition: out2in.c:615
u32 * workers
Definition: nat.h:329
u64 uword
Definition: types.h:112
snat_main_per_thread_data_t * per_thread_data
Definition: nat.h:336
vlib_node_registration_t nat44_ed_out2in_slowpath_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_out2in_slowpath_node)
Definition: out2in.c:108
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:231
static u8 is_interface_addr(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, u32 ip4_addr)
Definition: nat_inlines.h:68
static_always_inline snat_out2in_error_t icmp_get_key(ip4_header_t *ip0, snat_session_key_t *p_key0)
Definition: out2in.c:228
static u8 * format_snat_out2in_trace(u8 *s, va_list *args)
Definition: out2in.c:47
nat_reass_ip4_t * nat_ip4_reass_find_or_create(ip4_address_t src, ip4_address_t dst, u16 frag_id, u8 proto, u8 reset_timeout, u32 **bi_to_drop)
Find or create reassembly.
Definition: nat_reass.c:220
static void vlib_put_frame_queue_elt(vlib_frame_queue_elt_t *hf)
Definition: threads.h:454
static uword nat44_ed_out2in_fast_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:2761
static uword snat_out2in_fast_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: out2in.c:3649
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:360
#define SNAT_SESSION_FLAG_STATIC_MAPPING
Definition: nat.h:139
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:647
int nat_ip4_reass_add_fragment(nat_reass_ip4_t *reass, u32 bi, u32 **bi_to_drop)
Cache fragment.
Definition: nat_reass.c:336
u8 data[0]
Packet data.
Definition: buffer.h:172
u8 forwarding_enabled
Definition: nat.h:389
u16 flags
Copy of main node flags.
Definition: node.h:486
static 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_inlines.h:103
#define is_twice_nat_session(s)
Check if NAT session is twice NAT.
Definition: nat.h:502
clib_bihash_16_8_t in2out_ed
Definition: nat.h:283
void nat_ip4_reass_get_frags(nat_reass_ip4_t *reass, u32 **bi)
Get cached fragments.
Definition: nat_reass.c:368
NAT plugin virtual fragmentation reassembly.
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:295
#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:486
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:62
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:111
snat_session_t * sessions
Definition: nat.h:292
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:141
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:237
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:404
static u8 * format_snat_out2in_worker_handoff_trace(u8 *s, va_list *args)
Definition: out2in.c:69
static_always_inline int icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0)
Definition: out2in.c:1668
Definition: defs.h:46
u16 fib_index
Definition: nat.h:53
static void create_bypass_for_fwd(snat_main_t *sm, ip4_header_t *ip, u32 rx_fib_index, u32 thread_index)
Definition: out2in.c:1732