FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
det44_in2out.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 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 /**
17  * @file
18  * @brief Deterministic NAT (CGN) inside to outside translation
19  */
20 
21 #include <vlib/vlib.h>
22 #include <vnet/vnet.h>
23 #include <vnet/ip/ip.h>
24 #include <vnet/fib/ip4_fib.h>
25 #include <vppinfra/error.h>
26 #include <vppinfra/elog.h>
27 
28 #include <nat/det44/det44.h>
30 
31 #include <nat/lib/lib.h>
32 #include <nat/lib/inlines.h>
33 #include <nat/lib/nat_inlines.h>
34 
35 typedef enum
36 {
42 
43 typedef struct
44 {
49 
50 #define foreach_det44_in2out_error \
51 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
52 _(NO_TRANSLATION, "No translation") \
53 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
54 _(OUT_OF_PORTS, "Out of ports") \
55 _(IN2OUT_PACKETS, "Good in2out packets processed")
56 
57 typedef enum
58 {
59 #define _(sym,str) DET44_IN2OUT_ERROR_##sym,
61 #undef _
64 
65 static char *det44_in2out_error_strings[] = {
66 #define _(sym,string) string,
68 #undef _
69 };
70 
71 static u8 *
72 format_det44_in2out_trace (u8 * s, va_list * args)
73 {
74  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
75  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
76  det44_in2out_trace_t *t = va_arg (*args, det44_in2out_trace_t *);
77 
78  s = format (s, "DET44_IN2OUT: sw_if_index %d, next index %d, session %d",
80 
81  return s;
82 }
83 
84 #ifndef CLIB_MARCH_VARIANT
85 /**
86  * Get address and port values to be used for ICMP packet translation
87  * and create session if needed
88  *
89  * @param[in,out] node NAT node runtime
90  * @param[in] thread_index thread index
91  * @param[in,out] b0 buffer containing packet to be translated
92  * @param[in,out] ip0 ip header
93  * @param[out] p_proto protocol used for matching
94  * @param[out] p_value address and port after NAT translation
95  * @param[out] p_dont_translate if packet should not be translated
96  * @param d optional parameter
97  * @param e optional parameter
98  */
99 u32
101  u32 thread_index, vlib_buffer_t * b0,
103  u16 * port, u32 * fib_index,
104  nat_protocol_t * proto, void *d, void *e,
105  u8 * dont_translate)
106 {
107  det44_main_t *dm = &det44_main;
108  vlib_main_t *vm = vlib_get_main ();
109  icmp46_header_t *icmp0;
110  u32 sw_if_index0;
111  u32 rx_fib_index0;
113  snat_det_out_key_t key0;
114  u32 next0 = ~0;
115  icmp_echo_header_t *echo0, *inner_echo0 = 0;
116  ip4_header_t *inner_ip0;
117  void *l4_header = 0;
118  icmp46_header_t *inner_icmp0;
119  snat_det_map_t *mp0 = 0;
120  ip4_address_t new_addr0;
121  u16 lo_port0, i0;
122  snat_det_session_t *ses0 = 0;
123  ip4_address_t in_addr;
124  u16 in_port;
125  *dont_translate = 0;
126 
127  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
128  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
129  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
130  rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
131 
133  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
134  {
135  protocol = NAT_PROTOCOL_ICMP;
136  in_addr = ip0->src_address;
137  in_port = vnet_buffer (b0)->ip.reass.l4_src_port;
138  }
139  else
140  {
141  /* if error message, then it's not fragmented and we can access it */
142  inner_ip0 = (ip4_header_t *) (echo0 + 1);
143  l4_header = ip4_next_header (inner_ip0);
144  protocol = ip_proto_to_nat_proto (inner_ip0->protocol);
145  in_addr = inner_ip0->dst_address;
146  switch (protocol)
147  {
148  case NAT_PROTOCOL_ICMP:
149  inner_icmp0 = (icmp46_header_t *) l4_header;
150  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
151  in_port = inner_echo0->identifier;
152  break;
153  case NAT_PROTOCOL_UDP:
154  case NAT_PROTOCOL_TCP:
155  in_port = ((tcp_udp_header_t *) l4_header)->dst_port;
156  break;
157  default:
158  b0->error = node->errors[DET44_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
159  next0 = DET44_IN2OUT_NEXT_DROP;
160  goto out;
161  }
162  }
163 
164  mp0 = snat_det_map_by_user (&in_addr);
165  if (PREDICT_FALSE (!mp0))
166  {
167  if (PREDICT_FALSE (det44_translate (node, sw_if_index0, ip0,
168  IP_PROTOCOL_ICMP, rx_fib_index0)))
169  {
170  *dont_translate = 1;
171  goto out;
172  }
173  next0 = DET44_IN2OUT_NEXT_DROP;
174  b0->error = node->errors[DET44_IN2OUT_ERROR_NO_TRANSLATION];
175  goto out;
176  }
177 
178  snat_det_forward (mp0, &in_addr, &new_addr0, &lo_port0);
179 
180  key0.ext_host_addr = ip0->dst_address;
181  key0.ext_host_port = 0;
182 
183  ses0 = snat_det_find_ses_by_in (mp0, &in_addr, in_port, key0);
184  if (PREDICT_FALSE (!ses0))
185  {
186  if (PREDICT_FALSE (det44_translate (node, sw_if_index0, ip0,
187  IP_PROTOCOL_ICMP, rx_fib_index0)))
188  {
189  *dont_translate = 1;
190  goto out;
191  }
192  if (icmp0->type != ICMP4_echo_request)
193  {
194  b0->error = node->errors[DET44_IN2OUT_ERROR_BAD_ICMP_TYPE];
195  next0 = DET44_IN2OUT_NEXT_DROP;
196  goto out;
197  }
198  for (i0 = 0; i0 < mp0->ports_per_host; i0++)
199  {
200  key0.out_port = clib_host_to_net_u16 (lo_port0 +
201  ((i0 +
202  clib_net_to_host_u16
203  (echo0->identifier)) %
204  mp0->ports_per_host));
205 
206  if (snat_det_get_ses_by_out (mp0, &in_addr, key0.as_u64))
207  continue;
208 
209  ses0 =
210  snat_det_ses_create (thread_index, mp0,
211  &in_addr, echo0->identifier, &key0);
212  break;
213  }
214  if (PREDICT_FALSE (!ses0))
215  {
216  next0 = DET44_IN2OUT_NEXT_DROP;
217  b0->error = node->errors[DET44_IN2OUT_ERROR_OUT_OF_PORTS];
218  goto out;
219  }
220  }
221 
222  if (PREDICT_FALSE
223  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_request
225  reass.icmp_type_or_tcp_flags)))
226  {
227  b0->error = node->errors[DET44_IN2OUT_ERROR_BAD_ICMP_TYPE];
228  next0 = DET44_IN2OUT_NEXT_DROP;
229  goto out;
230  }
231 
232  u32 now = (u32) vlib_time_now (vm);
233 
234  ses0->state = DET44_SESSION_ICMP_ACTIVE;
235  ses0->expire = now + dm->timeouts.icmp;
236 
237 out:
238  *proto = protocol;
239  if (ses0)
240  {
241  *addr = new_addr0;
242  *fib_index = dm->outside_fib_index;
243  *port = ses0->out.out_port;
244  }
245  if (d)
246  *(snat_det_session_t **) d = ses0;
247  if (e)
248  *(snat_det_map_t **) e = mp0;
249  return next0;
250 }
251 #endif
252 
253 #ifndef CLIB_MARCH_VARIANT
254 u32
256  ip4_header_t * ip0,
257  icmp46_header_t * icmp0,
258  u32 sw_if_index0,
259  u32 rx_fib_index0,
261  u32 next0, u32 thread_index, void *d, void *e)
262 {
263  vlib_main_t *vm = vlib_get_main ();
264  u16 old_id0, new_id0, port, checksum0, old_checksum0, new_checksum0;
265  u32 new_addr0, old_addr0, next0_tmp, fib_index;
266  icmp_echo_header_t *echo0, *inner_echo0;
267  icmp46_header_t *inner_icmp0;
268  ip4_header_t *inner_ip0;
270  void *l4_header;
271  u8 dont_translate;
272  ip_csum_t sum0;
274 
275  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
276  next0_tmp = icmp_match_in2out_det (node, thread_index, b0, ip0,
277  &addr, &port, &fib_index, &protocol,
278  d, e, &dont_translate);
279  if (next0_tmp != ~0)
280  next0 = next0_tmp;
281  if (next0 == DET44_IN2OUT_NEXT_DROP || dont_translate)
282  goto out;
283 
284  if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
285  {
286  sum0 =
288  (u8 *) icmp0 -
289  (u8 *) vlib_buffer_get_current (b0),
290  ntohs (ip0->length) -
291  ip4_header_bytes (ip0), 0);
292  checksum0 = ~ip_csum_fold (sum0);
293  if (PREDICT_FALSE (checksum0 != 0 && checksum0 != 0xffff))
294  {
295  next0 = DET44_IN2OUT_NEXT_DROP;
296  goto out;
297  }
298  }
299 
300  old_addr0 = ip0->src_address.as_u32;
301  new_addr0 = ip0->src_address.as_u32 = addr.as_u32;
302 
303  sum0 = ip0->checksum;
304  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
305  src_address /* changed member */ );
306  ip0->checksum = ip_csum_fold (sum0);
307 
308  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
309  {
310  if (icmp0->checksum == 0)
311  icmp0->checksum = 0xffff;
312 
313  if (!icmp_type_is_error_message (icmp0->type))
314  {
315  new_id0 = port;
316  if (PREDICT_FALSE (new_id0 != echo0->identifier))
317  {
318  old_id0 = echo0->identifier;
319  new_id0 = port;
320  echo0->identifier = new_id0;
321 
322  sum0 = icmp0->checksum;
323  sum0 =
324  ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
325  identifier);
326  icmp0->checksum = ip_csum_fold (sum0);
327  }
328  }
329  else
330  {
331  inner_ip0 = (ip4_header_t *) (echo0 + 1);
332  l4_header = ip4_next_header (inner_ip0);
333 
334  if (!ip4_header_checksum_is_valid (inner_ip0))
335  {
336  next0 = DET44_IN2OUT_NEXT_DROP;
337  goto out;
338  }
339 
340  /* update inner destination IP address */
341  old_addr0 = inner_ip0->dst_address.as_u32;
342  inner_ip0->dst_address = addr;
343  new_addr0 = inner_ip0->dst_address.as_u32;
344  sum0 = icmp0->checksum;
345  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
346  dst_address /* changed member */ );
347  icmp0->checksum = ip_csum_fold (sum0);
348 
349  /* update inner IP header checksum */
350  old_checksum0 = inner_ip0->checksum;
351  sum0 = inner_ip0->checksum;
352  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
353  dst_address /* changed member */ );
354  inner_ip0->checksum = ip_csum_fold (sum0);
355  new_checksum0 = inner_ip0->checksum;
356  sum0 = icmp0->checksum;
357  sum0 =
358  ip_csum_update (sum0, old_checksum0, new_checksum0, ip4_header_t,
359  checksum);
360  icmp0->checksum = ip_csum_fold (sum0);
361 
362  switch (protocol)
363  {
364  case NAT_PROTOCOL_ICMP:
365  inner_icmp0 = (icmp46_header_t *) l4_header;
366  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
367 
368  old_id0 = inner_echo0->identifier;
369  new_id0 = port;
370  inner_echo0->identifier = new_id0;
371 
372  sum0 = icmp0->checksum;
373  sum0 =
374  ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
375  identifier);
376  icmp0->checksum = ip_csum_fold (sum0);
377  break;
378  case NAT_PROTOCOL_UDP:
379  case NAT_PROTOCOL_TCP:
380  old_id0 = ((tcp_udp_header_t *) l4_header)->dst_port;
381  new_id0 = port;
382  ((tcp_udp_header_t *) l4_header)->dst_port = new_id0;
383 
384  sum0 = icmp0->checksum;
385  sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
386  dst_port);
387  icmp0->checksum = ip_csum_fold (sum0);
388  break;
389  default:
390  ASSERT (0);
391  }
392  }
393  }
394 
395  if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0)
396  vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
397 out:
398  return next0;
399 }
400 #endif
401 
405 {
406  u32 n_left_from, *from;
407  u32 pkts_processed = 0;
408  det44_main_t *dm = &det44_main;
409  u32 now = (u32) vlib_time_now (vm);
410  u32 thread_index = vm->thread_index;
411 
412  from = vlib_frame_vector_args (frame);
413  n_left_from = frame->n_vectors;
414 
415  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
416  u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
417  vlib_get_buffers (vm, from, b, n_left_from);
418 
419  while (n_left_from >= 2)
420  {
421  vlib_buffer_t *b0, *b1;
422  u32 next0, next1;
423  u32 sw_if_index0, sw_if_index1;
424  ip4_header_t *ip0, *ip1;
425  ip_csum_t sum0, sum1;
426  ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
427  u16 old_port0, new_port0, lo_port0, i0;
428  u16 old_port1, new_port1, lo_port1, i1;
429  udp_header_t *udp0, *udp1;
430  tcp_header_t *tcp0, *tcp1;
431  u32 proto0, proto1;
432  snat_det_out_key_t key0, key1;
433  snat_det_map_t *mp0, *mp1;
434  snat_det_session_t *ses0 = 0, *ses1 = 0;
435  u32 rx_fib_index0, rx_fib_index1;
436  icmp46_header_t *icmp0, *icmp1;
437 
438  b0 = *b;
439  b++;
440  b1 = *b;
441  b++;
442 
443  /* Prefetch next iteration. */
444  if (PREDICT_TRUE (n_left_from >= 4))
445  {
446  vlib_buffer_t *p2, *p3;
447 
448  p2 = *b;
449  p3 = *(b + 1);
450 
451  vlib_prefetch_buffer_header (p2, LOAD);
452  vlib_prefetch_buffer_header (p3, LOAD);
453 
456  }
457 
458  next0 = DET44_IN2OUT_NEXT_LOOKUP;
459  next1 = DET44_IN2OUT_NEXT_LOOKUP;
460 
461  ip0 = vlib_buffer_get_current (b0);
462  udp0 = ip4_next_header (ip0);
463  tcp0 = (tcp_header_t *) udp0;
464 
465  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
466 
467  if (PREDICT_FALSE (ip0->ttl == 1))
468  {
469  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
470  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
471  ICMP4_time_exceeded_ttl_exceeded_in_transit,
472  0);
474  goto trace0;
475  }
476 
477  proto0 = ip_proto_to_nat_proto (ip0->protocol);
478 
479  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
480  {
481  rx_fib_index0 =
483  icmp0 = (icmp46_header_t *) udp0;
484 
485  // TODO:
486  next0 = det44_icmp_in2out (b0, ip0, icmp0, sw_if_index0,
487  rx_fib_index0, node, next0,
488  thread_index, &ses0, &mp0);
489  goto trace0;
490  }
491 
492  mp0 = snat_det_map_by_user (&ip0->src_address);
493  if (PREDICT_FALSE (!mp0))
494  {
495  det44_log_info ("no match for internal host %U",
497  next0 = DET44_IN2OUT_NEXT_DROP;
498  b0->error = node->errors[DET44_IN2OUT_ERROR_NO_TRANSLATION];
499  goto trace0;
500  }
501 
502  snat_det_forward (mp0, &ip0->src_address, &new_addr0, &lo_port0);
503 
504  key0.ext_host_addr = ip0->dst_address;
505  key0.ext_host_port = tcp0->dst;
506 
507  ses0 =
508  snat_det_find_ses_by_in (mp0, &ip0->src_address, tcp0->src, key0);
509  if (PREDICT_FALSE (!ses0))
510  {
511  for (i0 = 0; i0 < mp0->ports_per_host; i0++)
512  {
513  key0.out_port = clib_host_to_net_u16 (lo_port0 +
514  ((i0 +
515  clib_net_to_host_u16
516  (tcp0->src)) %
517  mp0->ports_per_host));
518 
520  (mp0, &ip0->src_address, key0.as_u64))
521  continue;
522 
523  ses0 =
524  snat_det_ses_create (thread_index, mp0, &ip0->src_address,
525  tcp0->src, &key0);
526  break;
527  }
528  if (PREDICT_FALSE (!ses0))
529  {
530  /* too many sessions for user, send ICMP error packet */
531  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
533  ICMP4_destination_unreachable,
534  ICMP4_destination_unreachable_destination_unreachable_host,
535  0);
537  goto trace0;
538  }
539  }
540 
541  old_port0 = udp0->src_port;
542  udp0->src_port = new_port0 = ses0->out.out_port;
543 
544  old_addr0.as_u32 = ip0->src_address.as_u32;
545  ip0->src_address.as_u32 = new_addr0.as_u32;
546  vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->outside_fib_index;
547 
548  sum0 = ip0->checksum;
549  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
550  ip4_header_t, src_address /* changed member */ );
551  ip0->checksum = ip_csum_fold (sum0);
552 
553  if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
554  {
555  if (tcp0->flags & TCP_FLAG_SYN)
556  ses0->state = DET44_SESSION_TCP_SYN_SENT;
557  else if (tcp0->flags & TCP_FLAG_ACK
558  && ses0->state == DET44_SESSION_TCP_SYN_SENT)
559  ses0->state = DET44_SESSION_TCP_ESTABLISHED;
560  else if (tcp0->flags & TCP_FLAG_FIN
561  && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
562  ses0->state = DET44_SESSION_TCP_FIN_WAIT;
563  else if (tcp0->flags & TCP_FLAG_ACK
564  && ses0->state == DET44_SESSION_TCP_FIN_WAIT)
565  snat_det_ses_close (mp0, ses0);
566  else if (tcp0->flags & TCP_FLAG_FIN
567  && ses0->state == DET44_SESSION_TCP_CLOSE_WAIT)
568  ses0->state = DET44_SESSION_TCP_LAST_ACK;
569  else if (tcp0->flags == 0 && ses0->state == DET44_SESSION_UNKNOWN)
570  ses0->state = DET44_SESSION_TCP_ESTABLISHED;
571 
572  sum0 = tcp0->checksum;
573  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
574  ip4_header_t,
575  dst_address /* changed member */ );
576  sum0 = ip_csum_update (sum0, old_port0, new_port0,
577  ip4_header_t /* cheat */ ,
578  length /* changed member */ );
579  mss_clamping (dm->mss_clamping, tcp0, &sum0);
580  tcp0->checksum = ip_csum_fold (sum0);
581  }
582  else
583  {
584  ses0->state = DET44_SESSION_UDP_ACTIVE;
585 
586  if (PREDICT_FALSE (udp0->checksum))
587  {
588  sum0 = udp0->checksum;
589  sum0 =
590  ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
591  ip4_header_t,
592  dst_address /* changed member */ );
593  sum0 =
594  ip_csum_update (sum0, old_port0, new_port0,
595  ip4_header_t /* cheat */ ,
596  length /* changed member */ );
597  udp0->checksum = ip_csum_fold (sum0);
598  }
599  }
600 
601  switch (ses0->state)
602  {
603  case DET44_SESSION_UDP_ACTIVE:
604  ses0->expire = now + dm->timeouts.udp;
605  break;
606  case DET44_SESSION_TCP_SYN_SENT:
607  case DET44_SESSION_TCP_FIN_WAIT:
608  case DET44_SESSION_TCP_CLOSE_WAIT:
609  case DET44_SESSION_TCP_LAST_ACK:
610  ses0->expire = now + dm->timeouts.tcp.transitory;
611  break;
612  case DET44_SESSION_TCP_ESTABLISHED:
613  ses0->expire = now + dm->timeouts.tcp.established;
614  break;
615  }
616 
617  trace0:
618  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
619  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
620  {
622  vlib_add_trace (vm, node, b0, sizeof (*t));
623  t->sw_if_index = sw_if_index0;
624  t->next_index = next0;
625  t->session_index = ~0;
626  if (ses0)
627  t->session_index = ses0 - mp0->sessions;
628  }
629 
630  pkts_processed += next0 != DET44_IN2OUT_NEXT_DROP;
631 
632  ip1 = vlib_buffer_get_current (b1);
633  udp1 = ip4_next_header (ip1);
634  tcp1 = (tcp_header_t *) udp1;
635 
636  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
637 
638  if (PREDICT_FALSE (ip1->ttl == 1))
639  {
640  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
641  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
642  ICMP4_time_exceeded_ttl_exceeded_in_transit,
643  0);
645  goto trace1;
646  }
647 
648  proto1 = ip_proto_to_nat_proto (ip1->protocol);
649 
650  if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
651  {
652  rx_fib_index1 =
654  icmp1 = (icmp46_header_t *) udp1;
655 
656  next1 = det44_icmp_in2out (b1, ip1, icmp1, sw_if_index1,
657  rx_fib_index1, node, next1,
658  thread_index, &ses1, &mp1);
659  goto trace1;
660  }
661 
662  mp1 = snat_det_map_by_user (&ip1->src_address);
663  if (PREDICT_FALSE (!mp1))
664  {
665  det44_log_info ("no match for internal host %U",
667  next1 = DET44_IN2OUT_NEXT_DROP;
668  b1->error = node->errors[DET44_IN2OUT_ERROR_NO_TRANSLATION];
669  goto trace1;
670  }
671 
672  snat_det_forward (mp1, &ip1->src_address, &new_addr1, &lo_port1);
673 
674  key1.ext_host_addr = ip1->dst_address;
675  key1.ext_host_port = tcp1->dst;
676 
677  ses1 =
678  snat_det_find_ses_by_in (mp1, &ip1->src_address, tcp1->src, key1);
679  if (PREDICT_FALSE (!ses1))
680  {
681  for (i1 = 0; i1 < mp1->ports_per_host; i1++)
682  {
683  key1.out_port = clib_host_to_net_u16 (lo_port1 +
684  ((i1 +
685  clib_net_to_host_u16
686  (tcp1->src)) %
687  mp1->ports_per_host));
688 
690  (mp1, &ip1->src_address, key1.as_u64))
691  continue;
692 
693  ses1 =
694  snat_det_ses_create (thread_index, mp1, &ip1->src_address,
695  tcp1->src, &key1);
696  break;
697  }
698  if (PREDICT_FALSE (!ses1))
699  {
700  /* too many sessions for user, send ICMP error packet */
701  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
703  ICMP4_destination_unreachable,
704  ICMP4_destination_unreachable_destination_unreachable_host,
705  0);
707  goto trace1;
708  }
709  }
710 
711  old_port1 = udp1->src_port;
712  udp1->src_port = new_port1 = ses1->out.out_port;
713 
714  old_addr1.as_u32 = ip1->src_address.as_u32;
715  ip1->src_address.as_u32 = new_addr1.as_u32;
716  vnet_buffer (b1)->sw_if_index[VLIB_TX] = dm->outside_fib_index;
717 
718  sum1 = ip1->checksum;
719  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
720  ip4_header_t, src_address /* changed member */ );
721  ip1->checksum = ip_csum_fold (sum1);
722 
723  if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
724  {
725  if (tcp1->flags & TCP_FLAG_SYN)
726  ses1->state = DET44_SESSION_TCP_SYN_SENT;
727  else if (tcp1->flags & TCP_FLAG_ACK
728  && ses1->state == DET44_SESSION_TCP_SYN_SENT)
729  ses1->state = DET44_SESSION_TCP_ESTABLISHED;
730  else if (tcp1->flags & TCP_FLAG_FIN
731  && ses1->state == DET44_SESSION_TCP_ESTABLISHED)
732  ses1->state = DET44_SESSION_TCP_FIN_WAIT;
733  else if (tcp1->flags & TCP_FLAG_ACK
734  && ses1->state == DET44_SESSION_TCP_FIN_WAIT)
735  snat_det_ses_close (mp1, ses1);
736  else if (tcp1->flags & TCP_FLAG_FIN
737  && ses1->state == DET44_SESSION_TCP_CLOSE_WAIT)
738  ses1->state = DET44_SESSION_TCP_LAST_ACK;
739  else if (tcp1->flags == 0 && ses1->state == DET44_SESSION_UNKNOWN)
740  ses1->state = DET44_SESSION_TCP_ESTABLISHED;
741 
742  sum1 = tcp1->checksum;
743  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
744  ip4_header_t,
745  dst_address /* changed member */ );
746  sum1 = ip_csum_update (sum1, old_port1, new_port1,
747  ip4_header_t /* cheat */ ,
748  length /* changed member */ );
749  mss_clamping (dm->mss_clamping, tcp1, &sum1);
750  tcp1->checksum = ip_csum_fold (sum1);
751  }
752  else
753  {
754  ses1->state = DET44_SESSION_UDP_ACTIVE;
755 
756  if (PREDICT_FALSE (udp1->checksum))
757  {
758  sum1 = udp1->checksum;
759  sum1 =
760  ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
761  ip4_header_t,
762  dst_address /* changed member */ );
763  sum1 =
764  ip_csum_update (sum1, old_port1, new_port1,
765  ip4_header_t /* cheat */ ,
766  length /* changed member */ );
767  udp1->checksum = ip_csum_fold (sum1);
768  }
769  }
770 
771  switch (ses1->state)
772  {
773  case DET44_SESSION_UDP_ACTIVE:
774  ses1->expire = now + dm->timeouts.udp;
775  break;
776  case DET44_SESSION_TCP_SYN_SENT:
777  case DET44_SESSION_TCP_FIN_WAIT:
778  case DET44_SESSION_TCP_CLOSE_WAIT:
779  case DET44_SESSION_TCP_LAST_ACK:
780  ses1->expire = now + dm->timeouts.tcp.transitory;
781  break;
782  case DET44_SESSION_TCP_ESTABLISHED:
783  ses1->expire = now + dm->timeouts.tcp.established;
784  break;
785  }
786 
787  trace1:
788  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
789  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
790  {
792  vlib_add_trace (vm, node, b1, sizeof (*t));
793  t->sw_if_index = sw_if_index1;
794  t->next_index = next1;
795  t->session_index = ~0;
796  if (ses1)
797  t->session_index = ses1 - mp1->sessions;
798  }
799 
800  pkts_processed += next1 != DET44_IN2OUT_NEXT_DROP;
801 
802  n_left_from -= 2;
803  next[0] = next0;
804  next[1] = next1;
805  next += 2;
806  }
807 
808  while (n_left_from > 0)
809  {
810  vlib_buffer_t *b0;
811  u32 next0;
812  u32 sw_if_index0;
813  ip4_header_t *ip0;
814  ip_csum_t sum0;
815  ip4_address_t new_addr0, old_addr0;
816  u16 old_port0, new_port0, lo_port0, i0;
817  udp_header_t *udp0;
818  tcp_header_t *tcp0;
819  u32 proto0;
820  snat_det_out_key_t key0;
821  snat_det_map_t *mp0;
822  snat_det_session_t *ses0 = 0;
823  u32 rx_fib_index0;
824  icmp46_header_t *icmp0;
825 
826  b0 = *b;
827  b++;
828  next0 = DET44_IN2OUT_NEXT_LOOKUP;
829 
830  ip0 = vlib_buffer_get_current (b0);
831  udp0 = ip4_next_header (ip0);
832  tcp0 = (tcp_header_t *) udp0;
833 
834  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
835 
836  if (PREDICT_FALSE (ip0->ttl == 1))
837  {
838  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
839  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
840  ICMP4_time_exceeded_ttl_exceeded_in_transit,
841  0);
843  goto trace00;
844  }
845 
846  proto0 = ip_proto_to_nat_proto (ip0->protocol);
847 
848  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
849  {
850  rx_fib_index0 =
852  icmp0 = (icmp46_header_t *) udp0;
853 
854  next0 = det44_icmp_in2out (b0, ip0, icmp0, sw_if_index0,
855  rx_fib_index0, node, next0,
856  thread_index, &ses0, &mp0);
857  goto trace00;
858  }
859 
860  mp0 = snat_det_map_by_user (&ip0->src_address);
861  if (PREDICT_FALSE (!mp0))
862  {
863  det44_log_info ("no match for internal host %U",
865  next0 = DET44_IN2OUT_NEXT_DROP;
866  b0->error = node->errors[DET44_IN2OUT_ERROR_NO_TRANSLATION];
867  goto trace00;
868  }
869 
870  snat_det_forward (mp0, &ip0->src_address, &new_addr0, &lo_port0);
871 
872  key0.ext_host_addr = ip0->dst_address;
873  key0.ext_host_port = tcp0->dst;
874 
875  ses0 =
876  snat_det_find_ses_by_in (mp0, &ip0->src_address, tcp0->src, key0);
877  if (PREDICT_FALSE (!ses0))
878  {
879  for (i0 = 0; i0 < mp0->ports_per_host; i0++)
880  {
881  key0.out_port = clib_host_to_net_u16 (lo_port0 +
882  ((i0 +
883  clib_net_to_host_u16
884  (tcp0->src)) %
885  mp0->ports_per_host));
886 
888  (mp0, &ip0->src_address, key0.as_u64))
889  continue;
890 
891  ses0 =
892  snat_det_ses_create (thread_index, mp0, &ip0->src_address,
893  tcp0->src, &key0);
894  break;
895  }
896  if (PREDICT_FALSE (!ses0))
897  {
898  /* too many sessions for user, send ICMP error packet */
899  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
901  ICMP4_destination_unreachable,
902  ICMP4_destination_unreachable_destination_unreachable_host,
903  0);
905  goto trace00;
906  }
907  }
908 
909  old_port0 = udp0->src_port;
910  udp0->src_port = new_port0 = ses0->out.out_port;
911 
912  old_addr0.as_u32 = ip0->src_address.as_u32;
913  ip0->src_address.as_u32 = new_addr0.as_u32;
914  vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->outside_fib_index;
915 
916  sum0 = ip0->checksum;
917  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
918  ip4_header_t, src_address /* changed member */ );
919  ip0->checksum = ip_csum_fold (sum0);
920 
921  if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
922  {
923  if (tcp0->flags & TCP_FLAG_SYN)
924  ses0->state = DET44_SESSION_TCP_SYN_SENT;
925  else if (tcp0->flags & TCP_FLAG_ACK
926  && ses0->state == DET44_SESSION_TCP_SYN_SENT)
927  ses0->state = DET44_SESSION_TCP_ESTABLISHED;
928  else if (tcp0->flags & TCP_FLAG_FIN
929  && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
930  ses0->state = DET44_SESSION_TCP_FIN_WAIT;
931  else if (tcp0->flags & TCP_FLAG_ACK
932  && ses0->state == DET44_SESSION_TCP_FIN_WAIT)
933  snat_det_ses_close (mp0, ses0);
934  else if (tcp0->flags & TCP_FLAG_FIN
935  && ses0->state == DET44_SESSION_TCP_CLOSE_WAIT)
936  ses0->state = DET44_SESSION_TCP_LAST_ACK;
937  else if (tcp0->flags == 0 && ses0->state == DET44_SESSION_UNKNOWN)
938  ses0->state = DET44_SESSION_TCP_ESTABLISHED;
939 
940  sum0 = tcp0->checksum;
941  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
942  ip4_header_t,
943  dst_address /* changed member */ );
944  sum0 = ip_csum_update (sum0, old_port0, new_port0,
945  ip4_header_t /* cheat */ ,
946  length /* changed member */ );
947  mss_clamping (dm->mss_clamping, tcp0, &sum0);
948  tcp0->checksum = ip_csum_fold (sum0);
949  }
950  else
951  {
952  ses0->state = DET44_SESSION_UDP_ACTIVE;
953 
954  if (PREDICT_FALSE (udp0->checksum))
955  {
956  sum0 = udp0->checksum;
957  sum0 =
958  ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
959  ip4_header_t,
960  dst_address /* changed member */ );
961  sum0 =
962  ip_csum_update (sum0, old_port0, new_port0,
963  ip4_header_t /* cheat */ ,
964  length /* changed member */ );
965  udp0->checksum = ip_csum_fold (sum0);
966  }
967  }
968 
969  switch (ses0->state)
970  {
971  case DET44_SESSION_UDP_ACTIVE:
972  ses0->expire = now + dm->timeouts.udp;
973  break;
974  case DET44_SESSION_TCP_SYN_SENT:
975  case DET44_SESSION_TCP_FIN_WAIT:
976  case DET44_SESSION_TCP_CLOSE_WAIT:
977  case DET44_SESSION_TCP_LAST_ACK:
978  ses0->expire = now + dm->timeouts.tcp.transitory;
979  break;
980  case DET44_SESSION_TCP_ESTABLISHED:
981  ses0->expire = now + dm->timeouts.tcp.established;
982  break;
983  }
984 
985  trace00:
986  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
987  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
988  {
990  vlib_add_trace (vm, node, b0, sizeof (*t));
991  t->sw_if_index = sw_if_index0;
992  t->next_index = next0;
993  t->session_index = ~0;
994  if (ses0)
995  t->session_index = ses0 - mp0->sessions;
996  }
997 
998  pkts_processed += next0 != DET44_IN2OUT_NEXT_DROP;
999 
1000  n_left_from--;
1001  next[0] = next0;
1002  next++;
1003  }
1004 
1005  vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1006  frame->n_vectors);
1007 
1009  DET44_IN2OUT_ERROR_IN2OUT_PACKETS,
1010  pkts_processed);
1011  return frame->n_vectors;
1012 }
1013 
1014 /* *INDENT-OFF* */
1016  .name = "det44-in2out",
1017  .vector_size = sizeof (u32),
1018  .format_trace = format_det44_in2out_trace,
1021  .error_strings = det44_in2out_error_strings,
1022  .runtime_data_bytes = sizeof (det44_runtime_t),
1023  .n_next_nodes = DET44_IN2OUT_N_NEXT,
1024  /* edit / add dispositions here */
1025  .next_nodes = {
1026  [DET44_IN2OUT_NEXT_DROP] = "error-drop",
1027  [DET44_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1028  [DET44_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1029  },
1030 };
1031 /* *INDENT-ON* */
1032 
1033 /*
1034  * fd.io coding-style-patch-verification: ON
1035  *
1036  * Local Variables:
1037  * eval: (c-set-style "gnu")
1038  * End:
1039  */
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
static ip_csum_t ip_incremental_checksum_buffer(vlib_main_t *vm, vlib_buffer_t *first_buffer, u32 first_buffer_offset, u32 n_bytes_to_checksum, ip_csum_t sum)
Definition: ip.h:152
static_always_inline int det44_translate(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: det44_inlines.h:64
vlib_node_registration_t det44_in2out_node
(constructor) VLIB_REGISTER_NODE (det44_in2out_node)
#define CLIB_UNUSED(x)
Definition: clib.h:87
static_always_inline snat_det_session_t * snat_det_get_ses_by_out(snat_det_map_t *dm, ip4_address_t *in_addr, u64 out_key)
Definition: det44.h:359
#define ntohs(x)
Definition: af_xdp.bpf.c:29
ip4_address_t src_address
Definition: ip4_packet.h:125
#define TCP_FLAG_SYN
Definition: fa_node.h:13
#define PREDICT_TRUE(x)
Definition: clib.h:121
vl_api_ip_port_and_mask_t dst_port
Definition: flow_types.api:92
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:333
u32 thread_index
Definition: main.h:249
u32 established
Definition: det44.h:89
Deterministic NAT (CGN) definitions.
det44_in2out_next_t
Definition: det44_in2out.c:35
uword ip_csum_t
Definition: ip_packet.h:244
vlib_main_t * vm
Definition: in2out_ed.c:1582
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
nat_protocol_t
Definition: lib.h:41
#define VLIB_NODE_FN(node)
Definition: node.h:202
NAT port/address allocation lib.
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:469
struct _tcp_header tcp_header_t
struct nat_timeouts_s::@74 tcp
vhost_vring_addr_t addr
Definition: vhost_user.h:111
unsigned char u8
Definition: types.h:56
static int ip4_is_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:168
nat_timeouts_t timeouts
Definition: det44.h:184
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
u16 mss_clamping
Definition: det44.h:181
static uword ip4_header_checksum_is_valid(ip4_header_t *i)
Definition: ip4_packet.h:384
static nat_protocol_t ip_proto_to_nat_proto(u8 ip_proto)
Common NAT inline functions.
Definition: inlines.h:22
ip4_address_t ext_host_addr
Definition: det44.h:103
static_always_inline 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: det44.h:376
ip4_address_t dst_address
Definition: ip4_packet.h:125
#define TCP_FLAG_ACK
Definition: fa_node.h:16
static_always_inline 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: det44.h:397
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:203
static_always_inline u8 icmp_type_is_error_message(u8 icmp_type)
Definition: inlines.h:53
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:196
unsigned int u32
Definition: types.h:88
#define VLIB_FRAME_SIZE
Definition: node.h:377
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
snat_det_session_t * sessions
Definition: det44.h:138
vl_api_ip_proto_t proto
Definition: acl_types.api:50
unsigned short u16
Definition: types.h:57
#define foreach_det44_in2out_error
Definition: det44_in2out.c:50
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
static void mss_clamping(u16 mss_clamping, tcp_header_t *tcp, ip_csum_t *sum)
Definition: nat_inlines.h:20
#define PREDICT_FALSE(x)
Definition: clib.h:120
det44_main_t det44_main
Definition: det44.c:30
#define TCP_FLAG_FIN
Definition: fa_node.h:12
vl_api_address_union_t src_address
Definition: ip_types.api:111
#define det44_log_info(...)
Definition: det44.h:215
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1231
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
static_always_inline void snat_det_forward(snat_det_map_t *dm, ip4_address_t *in_addr, ip4_address_t *out_addr, u16 *lo_port)
Definition: det44.h:322
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
static_always_inline void vlib_buffer_enqueue_to_next(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, u16 *nexts, uword count)
Definition: buffer_node.h:339
u8 data[]
Packet data.
Definition: buffer.h:181
u32 in2out_node_index
Definition: det44.h:175
u32 icmp
Definition: det44.h:92
u32 outside_fib_index
Definition: det44.h:165
static_always_inline void snat_det_ses_close(snat_det_map_t *dm, snat_det_session_t *ses)
Definition: det44.h:430
#define ARRAY_LEN(x)
Definition: clib.h:67
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1582
Deterministic NAT (CGN) inlines.
#define ASSERT(truth)
static char * det44_in2out_error_strings[]
Definition: det44_in2out.c:65
u32 transitory
Definition: det44.h:88
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
Definition: defs.h:47
vl_api_address_t ip
Definition: l2.api:501
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1583
u16 ports_per_host
Definition: det44.h:134
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:297
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:294
snat_det_out_key_t out
Definition: det44.h:116
u32 det44_icmp_in2out(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: det44_in2out.c:255
u16 port
Definition: lb_types.api:72
static u8 * format_det44_in2out_trace(u8 *s, va_list *args)
Definition: det44_in2out.c:72
#define vnet_buffer(b)
Definition: buffer.h:417
det44_in2out_error_t
Definition: det44_in2out.c:57
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:577
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:190
static_always_inline snat_det_map_t * snat_det_map_by_user(ip4_address_t *user_addr)
Definition: det44.h:292
static_always_inline void vlib_get_buffers(vlib_main_t *vm, u32 *bi, vlib_buffer_t **b, int count)
Translate array of buffer indices into buffer pointers.
Definition: buffer_funcs.h:280
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:301
#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 u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:300
u32 icmp_match_in2out_det(vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, ip4_address_t *addr, u16 *port, u32 *fib_index, nat_protocol_t *proto, void *d, void *e, u8 *dont_translate)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: det44_in2out.c:100
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:33
Definition: defs.h:46