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