FD.io VPP  v20.01-48-g3e0dafb74
Vector Packet Processing
nat_det_in2out.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 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  * @file
17  * @brief Deterministic/CGN NAT44 inside to outside network translation
18  */
19 
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22 #include <vnet/ip/ip.h>
23 #include <vnet/fib/ip4_fib.h>
24 #include <vppinfra/error.h>
25 #include <vppinfra/elog.h>
26 #include <nat/nat.h>
27 #include <nat/nat_det.h>
28 #include <nat/nat_inlines.h>
29 
30 typedef struct
31 {
36 
37 typedef enum
38 {
44 
45 #define foreach_nat_det_in2out_error \
46 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
47 _(NO_TRANSLATION, "No translation") \
48 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
49 _(OUT_OF_PORTS, "Out of ports") \
50 _(IN2OUT_PACKETS, "Good in2out packets processed")
51 
52 typedef enum
53 {
54 #define _(sym,str) NAT_DET_IN2OUT_ERROR_##sym,
56 #undef _
59 
60 static char *nat_det_in2out_error_strings[] = {
61 #define _(sym,string) string,
63 #undef _
64 };
65 
66 static u8 *
67 format_nat_det_in2out_trace (u8 * s, va_list * args)
68 {
69  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
70  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
71  nat_det_in2out_trace_t *t = va_arg (*args, nat_det_in2out_trace_t *);
72 
73  s = format (s, "NAT_DET_IN2OUT: sw_if_index %d, next index %d, session %d",
75 
76  return s;
77 }
78 
79 #ifndef CLIB_MARCH_VARIANT
80 /**
81  * Get address and port values to be used for ICMP packet translation
82  * and create session if needed
83  *
84  * @param[in,out] sm NAT main
85  * @param[in,out] node NAT node runtime
86  * @param[in] thread_index thread index
87  * @param[in,out] b0 buffer containing packet to be translated
88  * @param[out] p_proto protocol used for matching
89  * @param[out] p_value address and port after NAT translation
90  * @param[out] p_dont_translate if packet should not be translated
91  * @param d optional parameter
92  * @param e optional parameter
93  */
94 u32
96  u32 thread_index, vlib_buffer_t * b0,
97  ip4_header_t * ip0, u8 * p_proto,
98  snat_session_key_t * p_value,
99  u8 * p_dont_translate, void *d, void *e)
100 {
101  icmp46_header_t *icmp0;
102  u32 sw_if_index0;
103  u32 rx_fib_index0;
104  u8 protocol;
105  snat_det_out_key_t key0;
106  u8 dont_translate = 0;
107  u32 next0 = ~0;
108  icmp_echo_header_t *echo0, *inner_echo0 = 0;
109  ip4_header_t *inner_ip0;
110  void *l4_header = 0;
111  icmp46_header_t *inner_icmp0;
112  snat_det_map_t *dm0 = 0;
113  ip4_address_t new_addr0;
114  u16 lo_port0, i0;
115  snat_det_session_t *ses0 = 0;
116  ip4_address_t in_addr;
117  u16 in_port;
118 
119  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
120  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
121  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
122  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
123 
125  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
126  {
127  protocol = SNAT_PROTOCOL_ICMP;
128  in_addr = ip0->src_address;
129  in_port = vnet_buffer (b0)->ip.reass.l4_src_port;
130  }
131  else
132  {
133  /* if error message, then it's not fragmented and we can access it */
134  inner_ip0 = (ip4_header_t *) (echo0 + 1);
135  l4_header = ip4_next_header (inner_ip0);
136  protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
137  in_addr = inner_ip0->dst_address;
138  switch (protocol)
139  {
140  case SNAT_PROTOCOL_ICMP:
141  inner_icmp0 = (icmp46_header_t *) l4_header;
142  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
143  in_port = inner_echo0->identifier;
144  break;
145  case SNAT_PROTOCOL_UDP:
146  case SNAT_PROTOCOL_TCP:
147  in_port = ((tcp_udp_header_t *) l4_header)->dst_port;
148  break;
149  default:
150  b0->error = node->errors[NAT_DET_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
151  next0 = NAT_DET_IN2OUT_NEXT_DROP;
152  goto out;
153  }
154  }
155 
156  dm0 = snat_det_map_by_user (sm, &in_addr);
157  if (PREDICT_FALSE (!dm0))
158  {
159  nat_log_info ("no match for internal host %U",
160  format_ip4_address, &in_addr);
161  if (PREDICT_FALSE (snat_not_translate_fast (sm, node, sw_if_index0, ip0,
162  IP_PROTOCOL_ICMP,
163  rx_fib_index0)))
164  {
165  dont_translate = 1;
166  goto out;
167  }
168  next0 = NAT_DET_IN2OUT_NEXT_DROP;
169  b0->error = node->errors[NAT_DET_IN2OUT_ERROR_NO_TRANSLATION];
170  goto out;
171  }
172 
173  snat_det_forward (dm0, &in_addr, &new_addr0, &lo_port0);
174 
175  key0.ext_host_addr = ip0->dst_address;
176  key0.ext_host_port = 0;
177 
178  ses0 = snat_det_find_ses_by_in (dm0, &in_addr, in_port, key0);
179  if (PREDICT_FALSE (!ses0))
180  {
181  if (PREDICT_FALSE (snat_not_translate_fast (sm, node, sw_if_index0, ip0,
182  IP_PROTOCOL_ICMP,
183  rx_fib_index0)))
184  {
185  dont_translate = 1;
186  goto out;
187  }
188  if (icmp0->type != ICMP4_echo_request)
189  {
190  b0->error = node->errors[NAT_DET_IN2OUT_ERROR_BAD_ICMP_TYPE];
191  next0 = NAT_DET_IN2OUT_NEXT_DROP;
192  goto out;
193  }
194  for (i0 = 0; i0 < dm0->ports_per_host; i0++)
195  {
196  key0.out_port = clib_host_to_net_u16 (lo_port0 +
197  ((i0 +
198  clib_net_to_host_u16
199  (echo0->identifier)) %
200  dm0->ports_per_host));
201 
202  if (snat_det_get_ses_by_out (dm0, &in_addr, key0.as_u64))
203  continue;
204 
205  ses0 =
206  snat_det_ses_create (thread_index, dm0,
207  &in_addr, echo0->identifier, &key0);
208  break;
209  }
210  if (PREDICT_FALSE (!ses0))
211  {
212  next0 = NAT_DET_IN2OUT_NEXT_DROP;
213  b0->error = node->errors[NAT_DET_IN2OUT_ERROR_OUT_OF_PORTS];
214  goto out;
215  }
216  }
217 
218  if (PREDICT_FALSE
219  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_request
221  reass.icmp_type_or_tcp_flags)))
222  {
223  b0->error = node->errors[NAT_DET_IN2OUT_ERROR_BAD_ICMP_TYPE];
224  next0 = NAT_DET_IN2OUT_NEXT_DROP;
225  goto out;
226  }
227 
228  u32 now = (u32) vlib_time_now (sm->vlib_main);
229 
230  ses0->state = SNAT_SESSION_ICMP_ACTIVE;
231  ses0->expire = now + sm->icmp_timeout;
232 
233 out:
234  *p_proto = protocol;
235  if (ses0)
236  {
237  p_value->addr = new_addr0;
238  p_value->fib_index = sm->outside_fib_index;
239  p_value->port = ses0->out.out_port;
240  }
241  *p_dont_translate = dont_translate;
242  if (d)
243  *(snat_det_session_t **) d = ses0;
244  if (e)
245  *(snat_det_map_t **) e = dm0;
246  return next0;
247 }
248 #endif
249 
253 {
254  u32 n_left_from, *from, *to_next;
255  nat_det_in2out_next_t next_index;
256  u32 pkts_processed = 0;
257  snat_main_t *sm = &snat_main;
258  u32 now = (u32) vlib_time_now (vm);
259  u32 thread_index = vm->thread_index;
260 
261  from = vlib_frame_vector_args (frame);
262  n_left_from = frame->n_vectors;
263  next_index = node->cached_next_index;
264 
265  while (n_left_from > 0)
266  {
267  u32 n_left_to_next;
268 
269  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
270 
271  while (n_left_from >= 4 && n_left_to_next >= 2)
272  {
273  u32 bi0, bi1;
274  vlib_buffer_t *b0, *b1;
275  u32 next0, next1;
276  u32 sw_if_index0, sw_if_index1;
277  ip4_header_t *ip0, *ip1;
278  ip_csum_t sum0, sum1;
279  ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
280  u16 old_port0, new_port0, lo_port0, i0;
281  u16 old_port1, new_port1, lo_port1, i1;
282  udp_header_t *udp0, *udp1;
283  tcp_header_t *tcp0, *tcp1;
284  u32 proto0, proto1;
285  snat_det_out_key_t key0, key1;
286  snat_det_map_t *dm0, *dm1;
287  snat_det_session_t *ses0 = 0, *ses1 = 0;
288  u32 rx_fib_index0, rx_fib_index1;
289  icmp46_header_t *icmp0, *icmp1;
290 
291  /* Prefetch next iteration. */
292  {
293  vlib_buffer_t *p2, *p3;
294 
295  p2 = vlib_get_buffer (vm, from[2]);
296  p3 = vlib_get_buffer (vm, from[3]);
297 
298  vlib_prefetch_buffer_header (p2, LOAD);
299  vlib_prefetch_buffer_header (p3, LOAD);
300 
303  }
304 
305  /* speculatively enqueue b0 and b1 to the current next frame */
306  to_next[0] = bi0 = from[0];
307  to_next[1] = bi1 = from[1];
308  from += 2;
309  to_next += 2;
310  n_left_from -= 2;
311  n_left_to_next -= 2;
312 
313  b0 = vlib_get_buffer (vm, bi0);
314  b1 = vlib_get_buffer (vm, bi1);
315 
318 
319  ip0 = vlib_buffer_get_current (b0);
320  udp0 = ip4_next_header (ip0);
321  tcp0 = (tcp_header_t *) udp0;
322 
323  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
324 
325  if (PREDICT_FALSE (ip0->ttl == 1))
326  {
327  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
328  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
329  ICMP4_time_exceeded_ttl_exceeded_in_transit,
330  0);
332  goto trace0;
333  }
334 
335  proto0 = ip_proto_to_snat_proto (ip0->protocol);
336 
337  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
338  {
339  rx_fib_index0 =
341  icmp0 = (icmp46_header_t *) udp0;
342 
343  next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0,
344  rx_fib_index0, node, next0, thread_index,
345  &ses0, &dm0);
346  goto trace0;
347  }
348 
349  dm0 = snat_det_map_by_user (sm, &ip0->src_address);
350  if (PREDICT_FALSE (!dm0))
351  {
352  nat_log_info ("no match for internal host %U",
354  next0 = NAT_DET_IN2OUT_NEXT_DROP;
355  b0->error = node->errors[NAT_DET_IN2OUT_ERROR_NO_TRANSLATION];
356  goto trace0;
357  }
358 
359  snat_det_forward (dm0, &ip0->src_address, &new_addr0, &lo_port0);
360 
361  key0.ext_host_addr = ip0->dst_address;
362  key0.ext_host_port = tcp0->dst;
363 
364  ses0 =
365  snat_det_find_ses_by_in (dm0, &ip0->src_address, tcp0->src, key0);
366  if (PREDICT_FALSE (!ses0))
367  {
368  for (i0 = 0; i0 < dm0->ports_per_host; i0++)
369  {
370  key0.out_port = clib_host_to_net_u16 (lo_port0 +
371  ((i0 +
372  clib_net_to_host_u16
373  (tcp0->src)) %
374  dm0->
375  ports_per_host));
376 
378  (dm0, &ip0->src_address, key0.as_u64))
379  continue;
380 
381  ses0 =
382  snat_det_ses_create (thread_index, dm0, &ip0->src_address,
383  tcp0->src, &key0);
384  break;
385  }
386  if (PREDICT_FALSE (!ses0))
387  {
388  /* too many sessions for user, send ICMP error packet */
389  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
391  ICMP4_destination_unreachable,
392  ICMP4_destination_unreachable_destination_unreachable_host,
393  0);
395  goto trace0;
396  }
397  }
398 
399  old_port0 = udp0->src_port;
400  udp0->src_port = new_port0 = ses0->out.out_port;
401 
402  old_addr0.as_u32 = ip0->src_address.as_u32;
403  ip0->src_address.as_u32 = new_addr0.as_u32;
404  vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
405 
406  sum0 = ip0->checksum;
407  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
408  ip4_header_t,
409  src_address /* changed member */ );
410  ip0->checksum = ip_csum_fold (sum0);
411 
412  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
413  {
414  if (tcp0->flags & TCP_FLAG_SYN)
415  ses0->state = SNAT_SESSION_TCP_SYN_SENT;
416  else if (tcp0->flags & TCP_FLAG_ACK
417  && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
418  ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
419  else if (tcp0->flags & TCP_FLAG_FIN
420  && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
421  ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
422  else if (tcp0->flags & TCP_FLAG_ACK
423  && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
424  snat_det_ses_close (dm0, ses0);
425  else if (tcp0->flags & TCP_FLAG_FIN
426  && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
427  ses0->state = SNAT_SESSION_TCP_LAST_ACK;
428  else if (tcp0->flags == 0
429  && ses0->state == SNAT_SESSION_UNKNOWN)
430  ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
431 
432  sum0 = tcp0->checksum;
433  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
434  ip4_header_t,
435  dst_address /* changed member */ );
436  sum0 = ip_csum_update (sum0, old_port0, new_port0,
437  ip4_header_t /* cheat */ ,
438  length /* changed member */ );
439  mss_clamping (sm, tcp0, &sum0);
440  tcp0->checksum = ip_csum_fold (sum0);
441  }
442  else
443  {
444  ses0->state = SNAT_SESSION_UDP_ACTIVE;
445 
446  if (PREDICT_FALSE (udp0->checksum))
447  {
448  sum0 = udp0->checksum;
449  sum0 =
450  ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
451  ip4_header_t,
452  dst_address /* changed member */ );
453  sum0 =
454  ip_csum_update (sum0, old_port0, new_port0,
455  ip4_header_t /* cheat */ ,
456  length /* changed member */ );
457  udp0->checksum = ip_csum_fold (sum0);
458  }
459  }
460 
461  switch (ses0->state)
462  {
463  case SNAT_SESSION_UDP_ACTIVE:
464  ses0->expire = now + sm->udp_timeout;
465  break;
466  case SNAT_SESSION_TCP_SYN_SENT:
467  case SNAT_SESSION_TCP_FIN_WAIT:
468  case SNAT_SESSION_TCP_CLOSE_WAIT:
469  case SNAT_SESSION_TCP_LAST_ACK:
470  ses0->expire = now + sm->tcp_transitory_timeout;
471  break;
472  case SNAT_SESSION_TCP_ESTABLISHED:
473  ses0->expire = now + sm->tcp_established_timeout;
474  break;
475  }
476 
477  trace0:
478  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
479  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
480  {
482  vlib_add_trace (vm, node, b0, sizeof (*t));
483  t->sw_if_index = sw_if_index0;
484  t->next_index = next0;
485  t->session_index = ~0;
486  if (ses0)
487  t->session_index = ses0 - dm0->sessions;
488  }
489 
490  pkts_processed += next0 != NAT_DET_IN2OUT_NEXT_DROP;
491 
492  ip1 = vlib_buffer_get_current (b1);
493  udp1 = ip4_next_header (ip1);
494  tcp1 = (tcp_header_t *) udp1;
495 
496  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
497 
498  if (PREDICT_FALSE (ip1->ttl == 1))
499  {
500  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
501  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
502  ICMP4_time_exceeded_ttl_exceeded_in_transit,
503  0);
505  goto trace1;
506  }
507 
508  proto1 = ip_proto_to_snat_proto (ip1->protocol);
509 
510  if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
511  {
512  rx_fib_index1 =
514  icmp1 = (icmp46_header_t *) udp1;
515 
516  next1 = icmp_in2out (sm, b1, ip1, icmp1, sw_if_index1,
517  rx_fib_index1, node, next1, thread_index,
518  &ses1, &dm1);
519  goto trace1;
520  }
521 
522  dm1 = snat_det_map_by_user (sm, &ip1->src_address);
523  if (PREDICT_FALSE (!dm1))
524  {
525  nat_log_info ("no match for internal host %U",
527  next1 = NAT_DET_IN2OUT_NEXT_DROP;
528  b1->error = node->errors[NAT_DET_IN2OUT_ERROR_NO_TRANSLATION];
529  goto trace1;
530  }
531 
532  snat_det_forward (dm1, &ip1->src_address, &new_addr1, &lo_port1);
533 
534  key1.ext_host_addr = ip1->dst_address;
535  key1.ext_host_port = tcp1->dst;
536 
537  ses1 =
538  snat_det_find_ses_by_in (dm1, &ip1->src_address, tcp1->src, key1);
539  if (PREDICT_FALSE (!ses1))
540  {
541  for (i1 = 0; i1 < dm1->ports_per_host; i1++)
542  {
543  key1.out_port = clib_host_to_net_u16 (lo_port1 +
544  ((i1 +
545  clib_net_to_host_u16
546  (tcp1->src)) %
547  dm1->
548  ports_per_host));
549 
551  (dm1, &ip1->src_address, key1.as_u64))
552  continue;
553 
554  ses1 =
555  snat_det_ses_create (thread_index, dm1, &ip1->src_address,
556  tcp1->src, &key1);
557  break;
558  }
559  if (PREDICT_FALSE (!ses1))
560  {
561  /* too many sessions for user, send ICMP error packet */
562  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
564  ICMP4_destination_unreachable,
565  ICMP4_destination_unreachable_destination_unreachable_host,
566  0);
568  goto trace1;
569  }
570  }
571 
572  old_port1 = udp1->src_port;
573  udp1->src_port = new_port1 = ses1->out.out_port;
574 
575  old_addr1.as_u32 = ip1->src_address.as_u32;
576  ip1->src_address.as_u32 = new_addr1.as_u32;
577  vnet_buffer (b1)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
578 
579  sum1 = ip1->checksum;
580  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
581  ip4_header_t,
582  src_address /* changed member */ );
583  ip1->checksum = ip_csum_fold (sum1);
584 
585  if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
586  {
587  if (tcp1->flags & TCP_FLAG_SYN)
588  ses1->state = SNAT_SESSION_TCP_SYN_SENT;
589  else if (tcp1->flags & TCP_FLAG_ACK
590  && ses1->state == SNAT_SESSION_TCP_SYN_SENT)
591  ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
592  else if (tcp1->flags & TCP_FLAG_FIN
593  && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
594  ses1->state = SNAT_SESSION_TCP_FIN_WAIT;
595  else if (tcp1->flags & TCP_FLAG_ACK
596  && ses1->state == SNAT_SESSION_TCP_FIN_WAIT)
597  snat_det_ses_close (dm1, ses1);
598  else if (tcp1->flags & TCP_FLAG_FIN
599  && ses1->state == SNAT_SESSION_TCP_CLOSE_WAIT)
600  ses1->state = SNAT_SESSION_TCP_LAST_ACK;
601  else if (tcp1->flags == 0
602  && ses1->state == SNAT_SESSION_UNKNOWN)
603  ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
604 
605  sum1 = tcp1->checksum;
606  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
607  ip4_header_t,
608  dst_address /* changed member */ );
609  sum1 = ip_csum_update (sum1, old_port1, new_port1,
610  ip4_header_t /* cheat */ ,
611  length /* changed member */ );
612  mss_clamping (sm, tcp1, &sum1);
613  tcp1->checksum = ip_csum_fold (sum1);
614  }
615  else
616  {
617  ses1->state = SNAT_SESSION_UDP_ACTIVE;
618 
619  if (PREDICT_FALSE (udp1->checksum))
620  {
621  sum1 = udp1->checksum;
622  sum1 =
623  ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
624  ip4_header_t,
625  dst_address /* changed member */ );
626  sum1 =
627  ip_csum_update (sum1, old_port1, new_port1,
628  ip4_header_t /* cheat */ ,
629  length /* changed member */ );
630  udp1->checksum = ip_csum_fold (sum1);
631  }
632  }
633 
634  switch (ses1->state)
635  {
636  case SNAT_SESSION_UDP_ACTIVE:
637  ses1->expire = now + sm->udp_timeout;
638  break;
639  case SNAT_SESSION_TCP_SYN_SENT:
640  case SNAT_SESSION_TCP_FIN_WAIT:
641  case SNAT_SESSION_TCP_CLOSE_WAIT:
642  case SNAT_SESSION_TCP_LAST_ACK:
643  ses1->expire = now + sm->tcp_transitory_timeout;
644  break;
645  case SNAT_SESSION_TCP_ESTABLISHED:
646  ses1->expire = now + sm->tcp_established_timeout;
647  break;
648  }
649 
650  trace1:
651  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
652  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
653  {
655  vlib_add_trace (vm, node, b1, sizeof (*t));
656  t->sw_if_index = sw_if_index1;
657  t->next_index = next1;
658  t->session_index = ~0;
659  if (ses1)
660  t->session_index = ses1 - dm1->sessions;
661  }
662 
663  pkts_processed += next1 != NAT_DET_IN2OUT_NEXT_DROP;
664 
665  /* verify speculative enqueues, maybe switch current next frame */
666  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
667  to_next, n_left_to_next,
668  bi0, bi1, next0, next1);
669  }
670 
671  while (n_left_from > 0 && n_left_to_next > 0)
672  {
673  u32 bi0;
674  vlib_buffer_t *b0;
675  u32 next0;
676  u32 sw_if_index0;
677  ip4_header_t *ip0;
678  ip_csum_t sum0;
679  ip4_address_t new_addr0, old_addr0;
680  u16 old_port0, new_port0, lo_port0, i0;
681  udp_header_t *udp0;
682  tcp_header_t *tcp0;
683  u32 proto0;
684  snat_det_out_key_t key0;
685  snat_det_map_t *dm0;
686  snat_det_session_t *ses0 = 0;
687  u32 rx_fib_index0;
688  icmp46_header_t *icmp0;
689 
690  /* speculatively enqueue b0 to the current next frame */
691  bi0 = from[0];
692  to_next[0] = bi0;
693  from += 1;
694  to_next += 1;
695  n_left_from -= 1;
696  n_left_to_next -= 1;
697 
698  b0 = vlib_get_buffer (vm, bi0);
700 
701  ip0 = vlib_buffer_get_current (b0);
702  udp0 = ip4_next_header (ip0);
703  tcp0 = (tcp_header_t *) udp0;
704 
705  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
706 
707  if (PREDICT_FALSE (ip0->ttl == 1))
708  {
709  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
710  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
711  ICMP4_time_exceeded_ttl_exceeded_in_transit,
712  0);
714  goto trace00;
715  }
716 
717  proto0 = ip_proto_to_snat_proto (ip0->protocol);
718 
719  if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
720  {
721  rx_fib_index0 =
723  icmp0 = (icmp46_header_t *) udp0;
724 
725  next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0,
726  rx_fib_index0, node, next0, thread_index,
727  &ses0, &dm0);
728  goto trace00;
729  }
730 
731  dm0 = snat_det_map_by_user (sm, &ip0->src_address);
732  if (PREDICT_FALSE (!dm0))
733  {
734  nat_log_info ("no match for internal host %U",
736  next0 = NAT_DET_IN2OUT_NEXT_DROP;
737  b0->error = node->errors[NAT_DET_IN2OUT_ERROR_NO_TRANSLATION];
738  goto trace00;
739  }
740 
741  snat_det_forward (dm0, &ip0->src_address, &new_addr0, &lo_port0);
742 
743  key0.ext_host_addr = ip0->dst_address;
744  key0.ext_host_port = tcp0->dst;
745 
746  ses0 =
747  snat_det_find_ses_by_in (dm0, &ip0->src_address, tcp0->src, key0);
748  if (PREDICT_FALSE (!ses0))
749  {
750  for (i0 = 0; i0 < dm0->ports_per_host; i0++)
751  {
752  key0.out_port = clib_host_to_net_u16 (lo_port0 +
753  ((i0 +
754  clib_net_to_host_u16
755  (tcp0->src)) %
756  dm0->
757  ports_per_host));
758 
760  (dm0, &ip0->src_address, key0.as_u64))
761  continue;
762 
763  ses0 =
764  snat_det_ses_create (thread_index, dm0, &ip0->src_address,
765  tcp0->src, &key0);
766  break;
767  }
768  if (PREDICT_FALSE (!ses0))
769  {
770  /* too many sessions for user, send ICMP error packet */
771  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
773  ICMP4_destination_unreachable,
774  ICMP4_destination_unreachable_destination_unreachable_host,
775  0);
777  goto trace00;
778  }
779  }
780 
781  old_port0 = udp0->src_port;
782  udp0->src_port = new_port0 = ses0->out.out_port;
783 
784  old_addr0.as_u32 = ip0->src_address.as_u32;
785  ip0->src_address.as_u32 = new_addr0.as_u32;
786  vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
787 
788  sum0 = ip0->checksum;
789  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
790  ip4_header_t,
791  src_address /* changed member */ );
792  ip0->checksum = ip_csum_fold (sum0);
793 
794  if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
795  {
796  if (tcp0->flags & TCP_FLAG_SYN)
797  ses0->state = SNAT_SESSION_TCP_SYN_SENT;
798  else if (tcp0->flags & TCP_FLAG_ACK
799  && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
800  ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
801  else if (tcp0->flags & TCP_FLAG_FIN
802  && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
803  ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
804  else if (tcp0->flags & TCP_FLAG_ACK
805  && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
806  snat_det_ses_close (dm0, ses0);
807  else if (tcp0->flags & TCP_FLAG_FIN
808  && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
809  ses0->state = SNAT_SESSION_TCP_LAST_ACK;
810  else if (tcp0->flags == 0
811  && ses0->state == SNAT_SESSION_UNKNOWN)
812  ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
813 
814  sum0 = tcp0->checksum;
815  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
816  ip4_header_t,
817  dst_address /* changed member */ );
818  sum0 = ip_csum_update (sum0, old_port0, new_port0,
819  ip4_header_t /* cheat */ ,
820  length /* changed member */ );
821  mss_clamping (sm, tcp0, &sum0);
822  tcp0->checksum = ip_csum_fold (sum0);
823  }
824  else
825  {
826  ses0->state = SNAT_SESSION_UDP_ACTIVE;
827 
828  if (PREDICT_FALSE (udp0->checksum))
829  {
830  sum0 = udp0->checksum;
831  sum0 =
832  ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
833  ip4_header_t,
834  dst_address /* changed member */ );
835  sum0 =
836  ip_csum_update (sum0, old_port0, new_port0,
837  ip4_header_t /* cheat */ ,
838  length /* changed member */ );
839  udp0->checksum = ip_csum_fold (sum0);
840  }
841  }
842 
843  switch (ses0->state)
844  {
845  case SNAT_SESSION_UDP_ACTIVE:
846  ses0->expire = now + sm->udp_timeout;
847  break;
848  case SNAT_SESSION_TCP_SYN_SENT:
849  case SNAT_SESSION_TCP_FIN_WAIT:
850  case SNAT_SESSION_TCP_CLOSE_WAIT:
851  case SNAT_SESSION_TCP_LAST_ACK:
852  ses0->expire = now + sm->tcp_transitory_timeout;
853  break;
854  case SNAT_SESSION_TCP_ESTABLISHED:
855  ses0->expire = now + sm->tcp_established_timeout;
856  break;
857  }
858 
859  trace00:
860  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
861  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
862  {
864  vlib_add_trace (vm, node, b0, sizeof (*t));
865  t->sw_if_index = sw_if_index0;
866  t->next_index = next0;
867  t->session_index = ~0;
868  if (ses0)
869  t->session_index = ses0 - dm0->sessions;
870  }
871 
872  pkts_processed += next0 != NAT_DET_IN2OUT_NEXT_DROP;
873 
874  /* verify speculative enqueue, maybe switch current next frame */
875  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
876  to_next, n_left_to_next,
877  bi0, next0);
878  }
879 
880  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
881  }
882 
884  NAT_DET_IN2OUT_ERROR_IN2OUT_PACKETS,
885  pkts_processed);
886  return frame->n_vectors;
887 }
888 
889 /* *INDENT-OFF* */
891  .name = "nat44-det-in2out",
892  .vector_size = sizeof (u32),
893  .format_trace = format_nat_det_in2out_trace,
896  .error_strings = nat_det_in2out_error_strings,
897  .n_next_nodes = NAT_DET_IN2OUT_N_NEXT,
898  /* edit / add dispositions here */
899  .next_nodes = {
900  [NAT_DET_IN2OUT_NEXT_DROP] = "error-drop",
901  [NAT_DET_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
902  [NAT_DET_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
903  },
904 };
905 /* *INDENT-ON* */
906 
907 /*
908  * fd.io coding-style-patch-verification: ON
909  *
910  * Local Variables:
911  * eval: (c-set-style "gnu")
912  * End:
913  */
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:124
#define nat_log_info(...)
Definition: nat.h:862
vlib_node_registration_t snat_det_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_det_in2out_node)
#define CLIB_UNUSED(x)
Definition: clib.h:82
u16 ext_host_port
Definition: nat.h:123
u32 icmp_timeout
Definition: nat.h:677
ip4_address_t src_address
Definition: ip4_packet.h:170
#define TCP_FLAG_SYN
Definition: fa_node.h:13
#define PREDICT_TRUE(x)
Definition: clib.h:112
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:279
u32 thread_index
Definition: main.h:218
u8 data[0]
Packet data.
Definition: buffer.h:181
static void snat_det_ses_close(snat_det_map_t *dm, snat_det_session_t *ses)
Definition: nat_det.h:182
static snat_det_session_t * snat_det_find_ses_by_in(snat_det_map_t *dm, ip4_address_t *in_addr, u16 in_port, snat_det_out_key_t out_key)
Definition: nat_det.h:129
static void snat_det_forward(snat_det_map_t *dm, ip4_address_t *in_addr, ip4_address_t *out_addr, u16 *lo_port)
Definition: nat_det.h:75
uword ip_csum_t
Definition: ip_packet.h:244
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define VLIB_NODE_FN(node)
Definition: node.h:202
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
u32 icmp_match_in2out_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...
struct _tcp_header tcp_header_t
unsigned char u8
Definition: types.h:56
static char * nat_det_in2out_error_strings[]
static int snat_not_translate_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0)
Check if packet should be translated.
Definition: nat_inlines.h:639
vl_api_ip_proto_t protocol
Definition: lb_types.api:71
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:230
format_function_t format_ip4_address
Definition: format.h:73
ip4_address_t ext_host_addr
Definition: nat.h:122
ip4_address_t dst_address
Definition: ip4_packet.h:170
u32 det_in2out_node_index
Definition: nat.h:641
#define TCP_FLAG_ACK
Definition: fa_node.h:16
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:203
u32 icmp_in2out(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: in2out.c:655
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:241
unsigned int u32
Definition: types.h:88
nat_det_in2out_error_t
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
static void mss_clamping(snat_main_t *sm, tcp_header_t *tcp, ip_csum_t *sum)
Definition: nat_inlines.h:576
static_always_inline u8 icmp_type_is_error_message(u8 icmp_type)
Definition: nat_inlines.h:174
snat_det_session_t * sessions
Definition: nat.h:401
vlib_main_t * vlib_main
Definition: nat.h:698
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
u32 udp_timeout
Definition: nat.h:676
#define PREDICT_FALSE(x)
Definition: clib.h:111
#define TCP_FLAG_FIN
Definition: fa_node.h:12
vl_api_address_union_t src_address
Definition: ip_types.api:98
#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
#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:338
vlib_main_t * vm
Definition: in2out_ed.c:1810
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
snat_main_t snat_main
Definition: nat.c:39
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
static snat_det_session_t * snat_det_ses_create(u32 thread_index, snat_det_map_t *dm, ip4_address_t *in_addr, u16 in_port, snat_det_out_key_t *out)
Definition: nat_det.h:150
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
deterministic NAT definitions
#define foreach_nat_det_in2out_error
u32 outside_fib_index
Definition: nat.h:671
#define ARRAY_LEN(x)
Definition: clib.h:62
ip4_address_t addr
Definition: nat.h:90
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:456
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1810
u32 tcp_transitory_timeout
Definition: nat.h:678
static snat_det_map_t * snat_det_map_by_user(snat_main_t *sm, ip4_address_t *user_addr)
Definition: nat_det.h:45
nat_det_in2out_next_t
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
Definition: defs.h:47
vl_api_address_t ip
Definition: l2.api:490
static u32 ip_proto_to_snat_proto(u8 ip_proto)
Definition: nat_inlines.h:147
u16 ports_per_host
Definition: nat.h:397
VLIB buffer representation.
Definition: buffer.h:102
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:294
snat_det_out_key_t out
Definition: nat.h:379
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:408
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1811
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
static_always_inline void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.h:51
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:300
Definition: defs.h:46
u16 fib_index
Definition: nat.h:92
static u8 * format_nat_det_in2out_trace(u8 *s, va_list *args)
u32 tcp_established_timeout
Definition: nat.h:679