FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
det44_out2in.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) outside to inside 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_out2in_error \
51 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
52 _(NO_TRANSLATION, "No translation") \
53 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
54 _(OUT2IN_PACKETS, "Good out2in packets processed")
55 
56 typedef enum
57 {
58 #define _(sym,str) DET44_OUT2IN_ERROR_##sym,
60 #undef _
63 
64 static char *det44_out2in_error_strings[] = {
65 #define _(sym,string) string,
67 #undef _
68 };
69 
70 static u8 *
71 format_det44_out2in_trace (u8 * s, va_list * args)
72 {
73  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
74  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
75  det44_out2in_trace_t *t = va_arg (*args, det44_out2in_trace_t *);
76 
77  s =
78  format (s,
79  "DET44_OUT2IN: sw_if_index %d, next index %d, session index %d",
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  icmp46_header_t *icmp0;
109  u32 sw_if_index0;
110  u8 protocol;
111  snat_det_out_key_t key0;
112  u32 next0 = ~0;
113  icmp_echo_header_t *echo0, *inner_echo0 = 0;
114  ip4_header_t *inner_ip0;
115  void *l4_header = 0;
116  icmp46_header_t *inner_icmp0;
117  snat_det_map_t *mp0 = 0;
118  ip4_address_t new_addr0 = { {0} };
119  snat_det_session_t *ses0 = 0;
120  ip4_address_t out_addr;
121  *dont_translate = 0;
122 
123  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
124  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
125  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
126 
128  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
129  {
130  protocol = NAT_PROTOCOL_ICMP;
131  key0.ext_host_addr = ip0->src_address;
132  key0.ext_host_port = 0;
133  key0.out_port = vnet_buffer (b0)->ip.reass.l4_src_port;
134  out_addr = ip0->dst_address;
135  }
136  else
137  {
138  /* if error message, then it's not fragmented and we can access it */
139  inner_ip0 = (ip4_header_t *) (echo0 + 1);
140  l4_header = ip4_next_header (inner_ip0);
141  protocol = ip_proto_to_nat_proto (inner_ip0->protocol);
142  key0.ext_host_addr = inner_ip0->dst_address;
143  out_addr = inner_ip0->src_address;
144  switch (protocol)
145  {
146  case NAT_PROTOCOL_ICMP:
147  inner_icmp0 = (icmp46_header_t *) l4_header;
148  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
149  key0.ext_host_port = 0;
150  key0.out_port = inner_echo0->identifier;
151  break;
152  case NAT_PROTOCOL_UDP:
153  case NAT_PROTOCOL_TCP:
154  key0.ext_host_port = ((tcp_udp_header_t *) l4_header)->dst_port;
155  key0.out_port = ((tcp_udp_header_t *) l4_header)->src_port;
156  break;
157  default:
158  b0->error = node->errors[DET44_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
159  next0 = DET44_OUT2IN_NEXT_DROP;
160  goto out;
161  }
162  }
163 
164  mp0 = snat_det_map_by_out (&out_addr);
165  if (PREDICT_FALSE (!mp0))
166  {
167  /* Don't NAT packet aimed at the intfc address */
168  if (PREDICT_FALSE (!det44_is_interface_addr (node, sw_if_index0,
169  ip0->dst_address.as_u32)))
170  {
171  *dont_translate = 1;
172  goto out;
173  }
174  det44_log_info ("unknown dst address: %U",
176  goto out;
177  }
178 
179  snat_det_reverse (mp0, &ip0->dst_address,
180  clib_net_to_host_u16 (key0.out_port), &new_addr0);
181 
182  ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
183  if (PREDICT_FALSE (!ses0))
184  {
185  /* Don't NAT packet aimed at the intfc address */
186  if (PREDICT_FALSE (!det44_is_interface_addr (node, sw_if_index0,
187  ip0->dst_address.as_u32)))
188  {
189  *dont_translate = 1;
190  goto out;
191  }
192  det44_log_info ("no match src %U:%d dst %U:%d for user %U",
194  clib_net_to_host_u16 (key0.ext_host_port),
195  format_ip4_address, &out_addr,
196  clib_net_to_host_u16 (key0.out_port),
197  format_ip4_address, &new_addr0);
198  b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
199  next0 = DET44_OUT2IN_NEXT_DROP;
200  goto out;
201  }
202 
203  if (PREDICT_FALSE
204  (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_reply
206  reass.icmp_type_or_tcp_flags)))
207  {
208  b0->error = node->errors[DET44_OUT2IN_ERROR_BAD_ICMP_TYPE];
209  next0 = DET44_OUT2IN_NEXT_DROP;
210  goto out;
211  }
212 
213  goto out;
214 
215 out:
216  *proto = protocol;
217  if (ses0)
218  {
219  *addr = new_addr0;
220  *fib_index = dm->inside_fib_index;
221  *port = ses0->in_port;
222  }
223  if (d)
224  *(snat_det_session_t **) d = ses0;
225  if (e)
226  *(snat_det_map_t **) e = mp0;
227  return next0;
228 }
229 #endif
230 
231 #ifndef CLIB_MARCH_VARIANT
232 u32
234  ip4_header_t * ip0,
235  icmp46_header_t * icmp0,
236  u32 sw_if_index0,
237  u32 rx_fib_index0,
239  u32 next0, u32 thread_index, void *d, void *e)
240 {
241  vlib_main_t *vm = vlib_get_main ();
242  u32 new_addr0, old_addr0, next0_tmp, fib_index;
243  u16 old_id0, new_id0, port, checksum0;
244  icmp_echo_header_t *echo0, *inner_echo0;
245  icmp46_header_t *inner_icmp0;
246  ip4_header_t *inner_ip0;
248  void *l4_header;
249  u8 dont_translate;
250  ip_csum_t sum0;
252 
253  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
254  next0_tmp = icmp_match_out2in_det (node, thread_index, b0, ip0,
255  &addr, &port, &fib_index, &proto,
256  d, e, &dont_translate);
257  if (next0_tmp != ~0)
258  next0 = next0_tmp;
259  if (next0 == DET44_OUT2IN_NEXT_DROP || dont_translate)
260  goto out;
261 
262  if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
263  {
264  sum0 =
266  (u8 *) icmp0 -
267  (u8 *) vlib_buffer_get_current (b0),
268  ntohs (ip0->length) -
269  ip4_header_bytes (ip0), 0);
270  checksum0 = ~ip_csum_fold (sum0);
271  if (checksum0 != 0 && checksum0 != 0xffff)
272  {
273  next0 = DET44_OUT2IN_NEXT_DROP;
274  goto out;
275  }
276  }
277 
278  old_addr0 = ip0->dst_address.as_u32;
279  new_addr0 = ip0->dst_address.as_u32 = addr.as_u32;
280  vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
281 
282  sum0 = ip0->checksum;
283  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
284  dst_address /* changed member */ );
285  ip0->checksum = ip_csum_fold (sum0);
286 
287 
288  if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
289  {
290  if (icmp0->checksum == 0)
291  icmp0->checksum = 0xffff;
292 
293  if (!icmp_type_is_error_message (icmp0->type))
294  {
295  new_id0 = port;
296  if (PREDICT_FALSE (new_id0 != echo0->identifier))
297  {
298  old_id0 = echo0->identifier;
299  new_id0 = port;
300  echo0->identifier = new_id0;
301 
302  sum0 = icmp0->checksum;
303  sum0 =
304  ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
305  identifier /* changed member */ );
306  icmp0->checksum = ip_csum_fold (sum0);
307  }
308  }
309  else
310  {
311  inner_ip0 = (ip4_header_t *) (echo0 + 1);
312  l4_header = ip4_next_header (inner_ip0);
313 
314  if (!ip4_header_checksum_is_valid (inner_ip0))
315  {
316  next0 = DET44_OUT2IN_NEXT_DROP;
317  goto out;
318  }
319 
320  old_addr0 = inner_ip0->src_address.as_u32;
321  inner_ip0->src_address = addr;
322  new_addr0 = inner_ip0->src_address.as_u32;
323 
324  sum0 = icmp0->checksum;
325  sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
326  src_address /* changed member */ );
327  icmp0->checksum = ip_csum_fold (sum0);
328 
329  switch (proto)
330  {
331  case NAT_PROTOCOL_ICMP:
332  inner_icmp0 = (icmp46_header_t *) l4_header;
333  inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
334 
335  old_id0 = inner_echo0->identifier;
336  new_id0 = port;
337  inner_echo0->identifier = new_id0;
338 
339  sum0 = icmp0->checksum;
340  sum0 =
341  ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
342  identifier);
343  icmp0->checksum = ip_csum_fold (sum0);
344  break;
345  case NAT_PROTOCOL_UDP:
346  case NAT_PROTOCOL_TCP:
347  old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
348  new_id0 = port;
349  ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
350 
351  sum0 = icmp0->checksum;
352  sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
353  src_port);
354  icmp0->checksum = ip_csum_fold (sum0);
355  break;
356  default:
357  ASSERT (0);
358  }
359  }
360  }
361 
362 out:
363  return next0;
364 }
365 #endif
366 
370 {
371  u32 n_left_from, *from;
372  u32 pkts_processed = 0;
373  det44_main_t *dm = &det44_main;
374  u32 thread_index = vm->thread_index;
375 
376  from = vlib_frame_vector_args (frame);
377  n_left_from = frame->n_vectors;
378 
379  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
380  u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
381  vlib_get_buffers (vm, from, b, n_left_from);
382 
383  while (n_left_from >= 2)
384  {
385  vlib_buffer_t *b0, *b1;
388  u32 sw_if_index0, sw_if_index1;
389  ip4_header_t *ip0, *ip1;
390  ip_csum_t sum0, sum1;
391  ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
392  u16 new_port0, old_port0, old_port1, new_port1;
393  udp_header_t *udp0, *udp1;
394  tcp_header_t *tcp0, *tcp1;
395  u32 proto0, proto1;
396  snat_det_out_key_t key0, key1;
397  snat_det_map_t *mp0, *mp1;
398  snat_det_session_t *ses0 = 0, *ses1 = 0;
399  u32 rx_fib_index0, rx_fib_index1;
400  icmp46_header_t *icmp0, *icmp1;
401 
402  b0 = *b;
403  b++;
404  b1 = *b;
405  b++;
406 
407  /* Prefetch next iteration. */
408  if (PREDICT_TRUE (n_left_from >= 4))
409  {
410  vlib_buffer_t *p2, *p3;
411 
412  p2 = *b;
413  p3 = *(b + 1);
414 
415  vlib_prefetch_buffer_header (p2, LOAD);
416  vlib_prefetch_buffer_header (p3, LOAD);
417 
420  }
421 
422 
423  ip0 = vlib_buffer_get_current (b0);
424  udp0 = ip4_next_header (ip0);
425  tcp0 = (tcp_header_t *) udp0;
426 
427  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
428 
429  if (PREDICT_FALSE (ip0->ttl == 1))
430  {
431  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
432  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
433  ICMP4_time_exceeded_ttl_exceeded_in_transit,
434  0);
436  goto trace0;
437  }
438 
439  proto0 = ip_proto_to_nat_proto (ip0->protocol);
440 
441  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
442  {
443  rx_fib_index0 =
445  icmp0 = (icmp46_header_t *) udp0;
446 
447  next0 = det44_icmp_out2in (b0, ip0, icmp0, sw_if_index0,
448  rx_fib_index0, node, next0,
449  thread_index, &ses0, &mp0);
450  goto trace0;
451  }
452 
453  key0.ext_host_addr = ip0->src_address;
454  key0.ext_host_port = tcp0->src;
455  key0.out_port = tcp0->dst;
456 
457  mp0 = snat_det_map_by_out (&ip0->dst_address);
458  if (PREDICT_FALSE (!mp0))
459  {
460  det44_log_info ("unknown dst address: %U",
462  next0 = DET44_OUT2IN_NEXT_DROP;
463  b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
464  goto trace0;
465  }
466 
467  snat_det_reverse (mp0, &ip0->dst_address,
468  clib_net_to_host_u16 (tcp0->dst), &new_addr0);
469 
470  ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
471  if (PREDICT_FALSE (!ses0))
472  {
473  det44_log_info ("no match src %U:%d dst %U:%d for user %U",
475  clib_net_to_host_u16 (tcp0->src),
477  clib_net_to_host_u16 (tcp0->dst),
478  format_ip4_address, &new_addr0);
479  next0 = DET44_OUT2IN_NEXT_DROP;
480  b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
481  goto trace0;
482  }
483  old_port0 = udp0->dst_port;
484  udp0->dst_port = new_port0 = ses0->in_port;
485 
486  old_addr0 = ip0->dst_address;
487  ip0->dst_address = new_addr0;
488  vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
489 
490  sum0 = ip0->checksum;
491  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
492  ip4_header_t, dst_address /* changed member */ );
493  ip0->checksum = ip_csum_fold (sum0);
494 
495  if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
496  {
497  if (tcp0->flags & TCP_FLAG_FIN
498  && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
499  ses0->state = DET44_SESSION_TCP_CLOSE_WAIT;
500  else if (tcp0->flags & TCP_FLAG_ACK
501  && ses0->state == DET44_SESSION_TCP_LAST_ACK)
502  snat_det_ses_close (mp0, ses0);
503 
504  sum0 = tcp0->checksum;
505  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
506  ip4_header_t,
507  dst_address /* changed member */ );
508  sum0 = ip_csum_update (sum0, old_port0, new_port0,
509  ip4_header_t /* cheat */ ,
510  length /* changed member */ );
511  tcp0->checksum = ip_csum_fold (sum0);
512  }
513  else if (udp0->checksum)
514  {
515  sum0 = udp0->checksum;
516  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
517  ip4_header_t,
518  dst_address /* changed member */ );
519  sum0 = ip_csum_update (sum0, old_port0, new_port0,
520  ip4_header_t /* cheat */ ,
521  length /* changed member */ );
522  udp0->checksum = ip_csum_fold (sum0);
523  }
524 
525  trace0:
526 
527  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
528  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
529  {
531  vlib_add_trace (vm, node, b0, sizeof (*t));
532  t->sw_if_index = sw_if_index0;
533  t->next_index = next0;
534  t->session_index = ~0;
535  if (ses0)
536  t->session_index = ses0 - mp0->sessions;
537  }
538 
539  pkts_processed += next0 != DET44_OUT2IN_NEXT_DROP;
540 
541  ip1 = vlib_buffer_get_current (b1);
542  udp1 = ip4_next_header (ip1);
543  tcp1 = (tcp_header_t *) udp1;
544 
545  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
546 
547  if (PREDICT_FALSE (ip1->ttl == 1))
548  {
549  vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
550  icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
551  ICMP4_time_exceeded_ttl_exceeded_in_transit,
552  0);
554  goto trace1;
555  }
556 
557  proto1 = ip_proto_to_nat_proto (ip1->protocol);
558 
559  if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
560  {
561  rx_fib_index1 =
563  icmp1 = (icmp46_header_t *) udp1;
564 
565  next1 = det44_icmp_out2in (b1, ip1, icmp1, sw_if_index1,
566  rx_fib_index1, node, next1,
567  thread_index, &ses1, &mp1);
568  goto trace1;
569  }
570 
571  key1.ext_host_addr = ip1->src_address;
572  key1.ext_host_port = tcp1->src;
573  key1.out_port = tcp1->dst;
574 
575  mp1 = snat_det_map_by_out (&ip1->dst_address);
576  if (PREDICT_FALSE (!mp1))
577  {
578  det44_log_info ("unknown dst address: %U",
580  next1 = DET44_OUT2IN_NEXT_DROP;
581  b1->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
582  goto trace1;
583  }
584 
585  snat_det_reverse (mp1, &ip1->dst_address,
586  clib_net_to_host_u16 (tcp1->dst), &new_addr1);
587 
588  ses1 = snat_det_get_ses_by_out (mp1, &new_addr1, key1.as_u64);
589  if (PREDICT_FALSE (!ses1))
590  {
591  det44_log_info ("no match src %U:%d dst %U:%d for user %U",
593  clib_net_to_host_u16 (tcp1->src),
595  clib_net_to_host_u16 (tcp1->dst),
596  format_ip4_address, &new_addr1);
597  next1 = DET44_OUT2IN_NEXT_DROP;
598  b1->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
599  goto trace1;
600  }
601  old_port1 = udp1->dst_port;
602  udp1->dst_port = new_port1 = ses1->in_port;
603 
604  old_addr1 = ip1->dst_address;
605  ip1->dst_address = new_addr1;
606  vnet_buffer (b1)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
607 
608  sum1 = ip1->checksum;
609  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
610  ip4_header_t, dst_address /* changed member */ );
611  ip1->checksum = ip_csum_fold (sum1);
612 
613  if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
614  {
615  if (tcp1->flags & TCP_FLAG_FIN
616  && ses1->state == DET44_SESSION_TCP_ESTABLISHED)
617  ses1->state = DET44_SESSION_TCP_CLOSE_WAIT;
618  else if (tcp1->flags & TCP_FLAG_ACK
619  && ses1->state == DET44_SESSION_TCP_LAST_ACK)
620  snat_det_ses_close (mp1, ses1);
621 
622  sum1 = tcp1->checksum;
623  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
624  ip4_header_t,
625  dst_address /* changed member */ );
626  sum1 = ip_csum_update (sum1, old_port1, new_port1,
627  ip4_header_t /* cheat */ ,
628  length /* changed member */ );
629  tcp1->checksum = ip_csum_fold (sum1);
630  }
631  else if (udp1->checksum)
632  {
633  sum1 = udp1->checksum;
634  sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
635  ip4_header_t,
636  dst_address /* changed member */ );
637  sum1 = ip_csum_update (sum1, old_port1, new_port1,
638  ip4_header_t /* cheat */ ,
639  length /* changed member */ );
640  udp1->checksum = ip_csum_fold (sum1);
641  }
642 
643  trace1:
644 
645  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
646  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
647  {
649  vlib_add_trace (vm, node, b1, sizeof (*t));
650  t->sw_if_index = sw_if_index1;
651  t->next_index = next1;
652  t->session_index = ~0;
653  if (ses1)
654  t->session_index = ses1 - mp1->sessions;
655  }
656 
657  pkts_processed += next1 != DET44_OUT2IN_NEXT_DROP;
658 
659  n_left_from -= 2;
660  next[0] = next0;
661  next[1] = next1;
662  next += 2;
663  }
664 
665  while (n_left_from > 0)
666  {
667  vlib_buffer_t *b0;
669  u32 sw_if_index0;
670  ip4_header_t *ip0;
671  ip_csum_t sum0;
672  ip4_address_t new_addr0, old_addr0;
673  u16 new_port0, old_port0;
674  udp_header_t *udp0;
675  tcp_header_t *tcp0;
676  u32 proto0;
677  snat_det_out_key_t key0;
678  snat_det_map_t *mp0;
679  snat_det_session_t *ses0 = 0;
680  u32 rx_fib_index0;
681  icmp46_header_t *icmp0;
682 
683  b0 = *b;
684  b++;
685 
686  ip0 = vlib_buffer_get_current (b0);
687  udp0 = ip4_next_header (ip0);
688  tcp0 = (tcp_header_t *) udp0;
689 
690  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
691 
692  if (PREDICT_FALSE (ip0->ttl == 1))
693  {
694  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
695  icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
696  ICMP4_time_exceeded_ttl_exceeded_in_transit,
697  0);
699  goto trace00;
700  }
701 
702  proto0 = ip_proto_to_nat_proto (ip0->protocol);
703 
704  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
705  {
706  rx_fib_index0 =
708  icmp0 = (icmp46_header_t *) udp0;
709 
710  next0 = det44_icmp_out2in (b0, ip0, icmp0, sw_if_index0,
711  rx_fib_index0, node, next0,
712  thread_index, &ses0, &mp0);
713  goto trace00;
714  }
715 
716  key0.ext_host_addr = ip0->src_address;
717  key0.ext_host_port = tcp0->src;
718  key0.out_port = tcp0->dst;
719 
720  mp0 = snat_det_map_by_out (&ip0->dst_address);
721  if (PREDICT_FALSE (!mp0))
722  {
723  det44_log_info ("unknown dst address: %U",
725  next0 = DET44_OUT2IN_NEXT_DROP;
726  b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
727  goto trace00;
728  }
729 
730  snat_det_reverse (mp0, &ip0->dst_address,
731  clib_net_to_host_u16 (tcp0->dst), &new_addr0);
732 
733  ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
734  if (PREDICT_FALSE (!ses0))
735  {
736  det44_log_info ("no match src %U:%d dst %U:%d for user %U",
738  clib_net_to_host_u16 (tcp0->src),
740  clib_net_to_host_u16 (tcp0->dst),
741  format_ip4_address, &new_addr0);
742  next0 = DET44_OUT2IN_NEXT_DROP;
743  b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
744  goto trace00;
745  }
746  old_port0 = udp0->dst_port;
747  udp0->dst_port = new_port0 = ses0->in_port;
748 
749  old_addr0 = ip0->dst_address;
750  ip0->dst_address = new_addr0;
751  vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
752 
753  sum0 = ip0->checksum;
754  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
755  ip4_header_t, dst_address /* changed member */ );
756  ip0->checksum = ip_csum_fold (sum0);
757 
758  if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
759  {
760  if (tcp0->flags & TCP_FLAG_FIN
761  && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
762  ses0->state = DET44_SESSION_TCP_CLOSE_WAIT;
763  else if (tcp0->flags & TCP_FLAG_ACK
764  && ses0->state == DET44_SESSION_TCP_LAST_ACK)
765  snat_det_ses_close (mp0, ses0);
766 
767  sum0 = tcp0->checksum;
768  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
769  ip4_header_t,
770  dst_address /* changed member */ );
771  sum0 = ip_csum_update (sum0, old_port0, new_port0,
772  ip4_header_t /* cheat */ ,
773  length /* changed member */ );
774  tcp0->checksum = ip_csum_fold (sum0);
775  }
776  else if (udp0->checksum)
777  {
778  sum0 = udp0->checksum;
779  sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
780  ip4_header_t,
781  dst_address /* changed member */ );
782  sum0 = ip_csum_update (sum0, old_port0, new_port0,
783  ip4_header_t /* cheat */ ,
784  length /* changed member */ );
785  udp0->checksum = ip_csum_fold (sum0);
786  }
787 
788  trace00:
789 
790  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
791  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
792  {
794  vlib_add_trace (vm, node, b0, sizeof (*t));
795  t->sw_if_index = sw_if_index0;
796  t->next_index = next0;
797  t->session_index = ~0;
798  if (ses0)
799  t->session_index = ses0 - mp0->sessions;
800  }
801 
802  pkts_processed += next0 != DET44_OUT2IN_NEXT_DROP;
803 
804  n_left_from--;
805  next[0] = next0;
806  next++;
807  }
808  vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
809  frame->n_vectors);
810 
811 
813  DET44_OUT2IN_ERROR_OUT2IN_PACKETS,
814  pkts_processed);
815  return frame->n_vectors;
816 }
817 
818 /* *INDENT-OFF* */
820  .name = "det44-out2in",
821  .vector_size = sizeof (u32),
822  .format_trace = format_det44_out2in_trace,
825  .error_strings = det44_out2in_error_strings,
826  .runtime_data_bytes = sizeof (det44_runtime_t),
827  .n_next_nodes = DET44_OUT2IN_N_NEXT,
828  /* edit / add dispositions here */
829  .next_nodes = {
830  [DET44_OUT2IN_NEXT_DROP] = "error-drop",
831  [DET44_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
832  [DET44_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
833  },
834 };
835 /* *INDENT-ON* */
836 
837 /*
838  * fd.io coding-style-patch-verification: ON
839  *
840  * Local Variables:
841  * eval: (c-set-style "gnu")
842  * End:
843  */
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
#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
static_always_inline void snat_det_reverse(snat_det_map_t *dm, ip4_address_t *out_addr, u16 out_port, ip4_address_t *in_addr)
Definition: det44.h:337
#define ntohs(x)
Definition: af_xdp.bpf.c:29
ip4_address_t src_address
Definition: ip4_packet.h:125
vlib_node_registration_t det44_out2in_node
(constructor) VLIB_REGISTER_NODE (det44_out2in_node)
Definition: det44_out2in.c:819
#define PREDICT_TRUE(x)
Definition: clib.h:121
u32 thread_index
Definition: main.h:249
Deterministic NAT (CGN) definitions.
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
u32 icmp_match_out2in_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_out2in.c:100
#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
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
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
det44_out2in_error_t
Definition: det44_out2in.c:56
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
det44_out2in_next_t
Definition: det44_out2in.c:35
ip4_address_t ext_host_addr
Definition: det44.h:103
ip4_address_t dst_address
Definition: ip4_packet.h:125
#define TCP_FLAG_ACK
Definition: fa_node.h:16
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:203
static_always_inline snat_det_map_t * snat_det_map_by_out(ip4_address_t *out_addr)
Definition: det44.h:307
static_always_inline u8 icmp_type_is_error_message(u8 icmp_type)
Definition: inlines.h:53
u32 out2in_node_index
Definition: det44.h:174
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
static char * det44_out2in_error_strings[]
Definition: det44_out2in.c:64
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
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
#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...
vl_api_ip_port_and_mask_t src_port
Definition: flow_types.api:91
#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
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.
static u8 * format_det44_out2in_trace(u8 *s, va_list *args)
Definition: det44_out2in.c:71
#define foreach_det44_out2in_error
Definition: det44_out2in.c:50
#define ASSERT(truth)
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
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
u16 port
Definition: lb_types.api:72
#define vnet_buffer(b)
Definition: buffer.h:417
u32 inside_fib_index
Definition: det44.h:166
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 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
u32 det44_icmp_out2in(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_out2in.c:233
#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_always_inline int det44_is_interface_addr(vlib_node_runtime_t *node, u32 sw_if_index0, u32 ip4_addr)
Definition: det44_inlines.h:27
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:300
Definition: defs.h:46