FD.io VPP  v17.07.01-10-g3be13f0
Vector Packet Processing
nat64_in2out.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 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 NAT64 IPv6 to IPv4 translation (inside to outside network)
18  */
19 
20 #include <snat/nat64.h>
21 #include <vnet/ip/ip6_to_ip4.h>
22 #include <vnet/fib/fib_table.h>
23 
24 typedef struct
25 {
29 
30 static u8 *
31 format_nat64_in2out_trace (u8 * s, va_list * args)
32 {
33  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
34  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
35  nat64_in2out_trace_t *t = va_arg (*args, nat64_in2out_trace_t *);
36 
37  s =
38  format (s, "NAT64-in2out: sw_if_index %d, next index %d", t->sw_if_index,
39  t->next_index);
40 
41  return s;
42 }
43 
45 
46 #define foreach_nat64_in2out_error \
47 _(UNSUPPORTED_PROTOCOL, "unsupported protocol") \
48 _(IN2OUT_PACKETS, "good in2out packets processed") \
49 _(NO_TRANSLATION, "no translation") \
50 _(UNKNOWN, "unknown")
51 
52 typedef enum
53 {
54 #define _(sym,str) NAT64_IN2OUT_ERROR_##sym,
56 #undef _
59 
60 static char *nat64_in2out_error_strings[] = {
61 #define _(sym,string) string,
63 #undef _
64 };
65 
66 typedef enum
67 {
73 
75 {
79 
80 /**
81  * @brief Check whether is a hairpinning.
82  *
83  * If the destination IP address of the packet is an IPv4 address assigned to
84  * the NAT64 itself, then the packet is a hairpin packet.
85  *
86  * param dst_addr Destination address of the packet.
87  *
88  * @returns 1 if hairpinning, otherwise 0.
89  */
92 {
93  nat64_main_t *nm = &nat64_main;
94  int i;
95 
96  for (i = 0; i < vec_len (nm->addr_pool); i++)
97  {
98  if (nm->addr_pool[i].addr.as_u32 == dst_addr->as_u32[3])
99  return 1;
100  }
101 
102  return 0;
103 }
104 
105 static int
107  void *arg)
108 {
109  nat64_main_t *nm = &nat64_main;
110  nat64_in2out_set_ctx_t *ctx = arg;
111  nat64_db_bib_entry_t *bibe;
112  nat64_db_st_entry_t *ste;
113  ip46_address_t saddr, daddr;
114  u32 sw_if_index, fib_index;
115  udp_header_t *udp = ip6_next_header (ip6);
117  u16 sport = udp->src_port;
118  u16 dport = udp->dst_port;
119 
120  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
121  fib_index =
123 
124  saddr.as_u64[0] = ip6->src_address.as_u64[0];
125  saddr.as_u64[1] = ip6->src_address.as_u64[1];
126  daddr.as_u64[0] = ip6->dst_address.as_u64[0];
127  daddr.as_u64[1] = ip6->dst_address.as_u64[1];
128 
129  ste =
130  nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto,
131  fib_index, 1);
132 
133  if (ste)
134  {
135  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
136  if (!bibe)
137  return -1;
138  }
139  else
140  {
141  bibe =
142  nat64_db_bib_entry_find (&nm->db, &saddr, sport, proto, fib_index, 1);
143 
144  if (!bibe)
145  {
146  u16 out_port;
147  ip4_address_t out_addr;
149  (fib_index, proto, &out_addr, &out_port))
150  return -1;
151 
152  bibe =
153  nat64_db_bib_entry_create (&nm->db, &ip6->src_address, &out_addr,
154  sport, clib_host_to_net_u16 (out_port),
155  fib_index, proto, 0);
156  if (!bibe)
157  return -1;
158  }
159 
160  nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index);
161  ste =
162  nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address,
163  &daddr.ip4, dport);
164  if (!ste)
165  return -1;
166  }
167 
168  nat64_session_reset_timeout (ste, ctx->vm);
169 
170  ip4->src_address.as_u32 = bibe->out_addr.as_u32;
171  udp->src_port = bibe->out_port;
172 
173  ip4->dst_address.as_u32 = ste->out_r_addr.as_u32;
174 
175  if (proto == SNAT_PROTOCOL_TCP)
176  {
177  u16 *checksum;
178  ip_csum_t csum;
179  tcp_header_t *tcp = ip6_next_header (ip6);
180 
181  checksum = &tcp->checksum;
182  csum = ip_csum_sub_even (*checksum, sport);
183  csum = ip_csum_add_even (csum, udp->src_port);
184  *checksum = ip_csum_fold (csum);
185  }
186 
187  return 0;
188 }
189 
190 static int
192 {
193  nat64_main_t *nm = &nat64_main;
194  nat64_in2out_set_ctx_t *ctx = arg;
195  nat64_db_bib_entry_t *bibe;
196  nat64_db_st_entry_t *ste;
197  ip46_address_t saddr, daddr;
198  u32 sw_if_index, fib_index;
199  icmp46_header_t *icmp = ip6_next_header (ip6);
200 
201  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
202  fib_index =
204 
205  saddr.as_u64[0] = ip6->src_address.as_u64[0];
206  saddr.as_u64[1] = ip6->src_address.as_u64[1];
207  daddr.as_u64[0] = ip6->dst_address.as_u64[0];
208  daddr.as_u64[1] = ip6->dst_address.as_u64[1];
209 
210  if (icmp->type == ICMP4_echo_request || icmp->type == ICMP4_echo_reply)
211  {
212  u16 in_id = ((u16 *) (icmp))[2];
213  ste =
214  nat64_db_st_entry_find (&nm->db, &saddr, &daddr, in_id, 0,
215  SNAT_PROTOCOL_ICMP, fib_index, 1);
216 
217  if (ste)
218  {
219  bibe =
220  nat64_db_bib_entry_by_index (&nm->db, SNAT_PROTOCOL_ICMP,
221  ste->bibe_index);
222  if (!bibe)
223  return -1;
224  }
225  else
226  {
227  bibe =
228  nat64_db_bib_entry_find (&nm->db, &saddr, in_id,
229  SNAT_PROTOCOL_ICMP, fib_index, 1);
230 
231  if (!bibe)
232  {
233  u16 out_id;
234  ip4_address_t out_addr;
236  (fib_index, SNAT_PROTOCOL_ICMP, &out_addr, &out_id))
237  return -1;
238 
239  bibe =
241  &out_addr, in_id,
242  clib_host_to_net_u16 (out_id),
243  fib_index, SNAT_PROTOCOL_ICMP, 0);
244  if (!bibe)
245  return -1;
246  }
247 
248  nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index);
249  ste =
250  nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address,
251  &daddr.ip4, 0);
252  if (!ste)
253  return -1;
254  }
255 
256  nat64_session_reset_timeout (ste, ctx->vm);
257 
258  ip4->src_address.as_u32 = bibe->out_addr.as_u32;
259  ((u16 *) (icmp))[2] = bibe->out_port;
260 
261  ip4->dst_address.as_u32 = ste->out_r_addr.as_u32;
262  }
263  else
264  {
265  if (!vec_len (nm->addr_pool))
266  return -1;
267 
268  ip4->src_address.as_u32 = nm->addr_pool[0].addr.as_u32;
269  nat64_extract_ip4 (&ip6->dst_address, &ip4->dst_address, fib_index);
270  }
271 
272  return 0;
273 }
274 
275 static int
277  void *arg)
278 {
279  nat64_main_t *nm = &nat64_main;
280  nat64_in2out_set_ctx_t *ctx = arg;
281  nat64_db_st_entry_t *ste;
282  nat64_db_bib_entry_t *bibe;
283  ip46_address_t saddr, daddr;
284  u32 sw_if_index, fib_index;
286 
287  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
288  fib_index =
290 
291  saddr.as_u64[0] = ip6->src_address.as_u64[0];
292  saddr.as_u64[1] = ip6->src_address.as_u64[1];
293  daddr.as_u64[0] = ip6->dst_address.as_u64[0];
294  daddr.as_u64[1] = ip6->dst_address.as_u64[1];
295 
296  if (proto == SNAT_PROTOCOL_ICMP)
297  {
298  icmp46_header_t *icmp = ip6_next_header (ip6);
299  u16 in_id = ((u16 *) (icmp))[2];
300 
301  if (!
302  (icmp->type == ICMP4_echo_request
303  || icmp->type == ICMP4_echo_reply))
304  return -1;
305 
306  ste =
307  nat64_db_st_entry_find (&nm->db, &daddr, &saddr, in_id, 0, proto,
308  fib_index, 1);
309  if (!ste)
310  return -1;
311 
312  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
313  if (!bibe)
314  return -1;
315 
316  ip4->dst_address.as_u32 = bibe->out_addr.as_u32;
317  ((u16 *) (icmp))[2] = bibe->out_port;
318  ip4->src_address.as_u32 = ste->out_r_addr.as_u32;
319  }
320  else
321  {
322  udp_header_t *udp = ip6_next_header (ip6);
323  tcp_header_t *tcp = ip6_next_header (ip6);
324  u16 *checksum;
325  ip_csum_t csum;
326 
327  u16 sport = udp->src_port;
328  u16 dport = udp->dst_port;
329 
330  ste =
331  nat64_db_st_entry_find (&nm->db, &daddr, &saddr, dport, sport, proto,
332  fib_index, 1);
333  if (!ste)
334  return -1;
335 
336  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
337  if (!bibe)
338  return -1;
339 
340  ip4->dst_address.as_u32 = bibe->out_addr.as_u32;
341  udp->dst_port = bibe->out_port;
342  ip4->src_address.as_u32 = ste->out_r_addr.as_u32;
343 
344  if (proto == SNAT_PROTOCOL_TCP)
345  checksum = &tcp->checksum;
346  else
347  checksum = &udp->checksum;
348  csum = ip_csum_sub_even (*checksum, dport);
349  csum = ip_csum_add_even (csum, udp->dst_port);
350  *checksum = ip_csum_fold (csum);
351  }
352 
353  return 0;
354 }
355 
356 static int
358  ip6_header_t * ip6)
359 {
360  nat64_main_t *nm = &nat64_main;
361  nat64_db_bib_entry_t *bibe;
362  nat64_db_st_entry_t *ste;
363  ip46_address_t saddr, daddr;
364  u32 sw_if_index, fib_index;
365  udp_header_t *udp = ip6_next_header (ip6);
366  tcp_header_t *tcp = ip6_next_header (ip6);
368  u16 sport = udp->src_port;
369  u16 dport = udp->dst_port;
370  u16 *checksum;
371  ip_csum_t csum;
372 
373  sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
374  fib_index =
376 
377  saddr.as_u64[0] = ip6->src_address.as_u64[0];
378  saddr.as_u64[1] = ip6->src_address.as_u64[1];
379  daddr.as_u64[0] = ip6->dst_address.as_u64[0];
380  daddr.as_u64[1] = ip6->dst_address.as_u64[1];
381 
382  if (proto == SNAT_PROTOCOL_UDP)
383  checksum = &udp->checksum;
384  else
385  checksum = &tcp->checksum;
386 
387  csum = ip_csum_sub_even (*checksum, ip6->src_address.as_u64[0]);
388  csum = ip_csum_sub_even (csum, ip6->src_address.as_u64[1]);
389  csum = ip_csum_sub_even (csum, ip6->dst_address.as_u64[0]);
390  csum = ip_csum_sub_even (csum, ip6->dst_address.as_u64[1]);
391  csum = ip_csum_sub_even (csum, sport);
392  csum = ip_csum_sub_even (csum, dport);
393 
394  ste =
395  nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto,
396  fib_index, 1);
397 
398  if (ste)
399  {
400  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
401  if (!bibe)
402  return -1;
403  }
404  else
405  {
406  bibe =
407  nat64_db_bib_entry_find (&nm->db, &saddr, sport, proto, fib_index, 1);
408 
409  if (!bibe)
410  {
411  u16 out_port;
412  ip4_address_t out_addr;
414  (fib_index, proto, &out_addr, &out_port))
415  return -1;
416 
417  bibe =
418  nat64_db_bib_entry_create (&nm->db, &ip6->src_address, &out_addr,
419  sport, clib_host_to_net_u16 (out_port),
420  fib_index, proto, 0);
421  if (!bibe)
422  return -1;
423  }
424 
425  nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index);
426  ste =
427  nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address,
428  &daddr.ip4, dport);
429  if (!ste)
430  return -1;
431  }
432 
433  nat64_session_reset_timeout (ste, vm);
434 
435  sport = udp->src_port = bibe->out_port;
436  nat64_compose_ip6 (&ip6->src_address, &bibe->out_addr, fib_index);
437 
438  memset (&saddr, 0, sizeof (saddr));
439  memset (&daddr, 0, sizeof (daddr));
440  saddr.ip4.as_u32 = bibe->out_addr.as_u32;
441  daddr.ip4.as_u32 = ste->out_r_addr.as_u32;
442 
443  ste =
444  nat64_db_st_entry_find (&nm->db, &daddr, &saddr, dport, sport, proto, 0,
445  0);
446 
447  if (ste)
448  {
449  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
450  if (!bibe)
451  return -1;
452  }
453  else
454  {
455  bibe = nat64_db_bib_entry_find (&nm->db, &daddr, dport, proto, 0, 0);
456 
457  if (!bibe)
458  return -1;
459 
460  ste =
461  nat64_db_st_entry_create (&nm->db, bibe, &ip6->src_address,
462  &saddr.ip4, sport);
463  }
464 
465  ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
466  ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
467  udp->dst_port = bibe->in_port;
468 
469  csum = ip_csum_add_even (csum, ip6->src_address.as_u64[0]);
470  csum = ip_csum_add_even (csum, ip6->src_address.as_u64[1]);
471  csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[0]);
472  csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[1]);
473  csum = ip_csum_add_even (csum, udp->src_port);
474  csum = ip_csum_add_even (csum, udp->dst_port);
475  *checksum = ip_csum_fold (csum);
476 
477  return 0;
478 }
479 
480 static int
482  ip6_header_t * ip6)
483 {
484  nat64_main_t *nm = &nat64_main;
485  nat64_db_bib_entry_t *bibe;
486  nat64_db_st_entry_t *ste;
487  icmp46_header_t *icmp = ip6_next_header (ip6);
488  ip6_header_t *inner_ip6;
489  ip46_address_t saddr, daddr;
490  u32 sw_if_index, fib_index;
491  snat_protocol_t proto;
492  udp_header_t *udp;
493  tcp_header_t *tcp;
494  u16 *checksum, sport, dport;
495  ip_csum_t csum;
496 
497  if (icmp->type == ICMP6_echo_request || icmp->type == ICMP6_echo_reply)
498  return -1;
499 
500  inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
501 
502  proto = ip_proto_to_snat_proto (inner_ip6->protocol);
503 
504  if (proto == SNAT_PROTOCOL_ICMP)
505  return -1;
506 
507  sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
508  fib_index =
510 
511  saddr.as_u64[0] = inner_ip6->src_address.as_u64[0];
512  saddr.as_u64[1] = inner_ip6->src_address.as_u64[1];
513  daddr.as_u64[0] = inner_ip6->dst_address.as_u64[0];
514  daddr.as_u64[1] = inner_ip6->dst_address.as_u64[1];
515 
516  udp = ip6_next_header (inner_ip6);
517  tcp = ip6_next_header (inner_ip6);
518 
519  sport = udp->src_port;
520  dport = udp->dst_port;
521 
522  if (proto == SNAT_PROTOCOL_UDP)
523  checksum = &udp->checksum;
524  else
525  checksum = &tcp->checksum;
526 
527  csum = ip_csum_sub_even (*checksum, inner_ip6->src_address.as_u64[0]);
528  csum = ip_csum_sub_even (csum, inner_ip6->src_address.as_u64[1]);
529  csum = ip_csum_sub_even (csum, inner_ip6->dst_address.as_u64[0]);
530  csum = ip_csum_sub_even (csum, inner_ip6->dst_address.as_u64[1]);
531  csum = ip_csum_sub_even (csum, sport);
532  csum = ip_csum_sub_even (csum, dport);
533 
534  ste =
535  nat64_db_st_entry_find (&nm->db, &daddr, &saddr, dport, sport, proto,
536  fib_index, 1);
537  if (!ste)
538  return -1;
539 
540  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
541  if (!bibe)
542  return -1;
543 
544  dport = udp->dst_port = bibe->out_port;
545  nat64_compose_ip6 (&inner_ip6->dst_address, &bibe->out_addr, fib_index);
546 
547  memset (&saddr, 0, sizeof (saddr));
548  memset (&daddr, 0, sizeof (daddr));
549  saddr.ip4.as_u32 = ste->out_r_addr.as_u32;
550  daddr.ip4.as_u32 = bibe->out_addr.as_u32;
551 
552  ste =
553  nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto, 0,
554  0);
555  if (!ste)
556  return -1;
557 
558  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
559  if (!bibe)
560  return -1;
561 
562  inner_ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
563  inner_ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
564  udp->src_port = bibe->in_port;
565 
566  csum = ip_csum_add_even (csum, inner_ip6->src_address.as_u64[0]);
567  csum = ip_csum_add_even (csum, inner_ip6->src_address.as_u64[1]);
568  csum = ip_csum_add_even (csum, inner_ip6->dst_address.as_u64[0]);
569  csum = ip_csum_add_even (csum, inner_ip6->dst_address.as_u64[1]);
570  csum = ip_csum_add_even (csum, udp->src_port);
571  csum = ip_csum_add_even (csum, udp->dst_port);
572  *checksum = ip_csum_fold (csum);
573 
574  if (!vec_len (nm->addr_pool))
575  return -1;
576 
577  nat64_compose_ip6 (&ip6->src_address, &nm->addr_pool[0].addr, fib_index);
578  ip6->dst_address.as_u64[0] = inner_ip6->src_address.as_u64[0];
579  ip6->dst_address.as_u64[1] = inner_ip6->src_address.as_u64[1];
580 
581  icmp->checksum = 0;
582  csum = ip_csum_with_carry (0, ip6->payload_length);
583  csum = ip_csum_with_carry (csum, clib_host_to_net_u16 (ip6->protocol));
584  csum = ip_csum_with_carry (csum, ip6->src_address.as_u64[0]);
585  csum = ip_csum_with_carry (csum, ip6->src_address.as_u64[1]);
586  csum = ip_csum_with_carry (csum, ip6->dst_address.as_u64[0]);
587  csum = ip_csum_with_carry (csum, ip6->dst_address.as_u64[1]);
588  csum =
589  ip_incremental_checksum (csum, icmp,
590  clib_net_to_host_u16 (ip6->payload_length));
591  icmp->checksum = ~ip_csum_fold (csum);
592 
593  return 0;
594 }
595 
596 static uword
598  vlib_frame_t * frame)
599 {
600  u32 n_left_from, *from, *to_next;
601  nat64_in2out_next_t next_index;
602  u32 pkts_processed = 0;
603 
604  from = vlib_frame_vector_args (frame);
605  n_left_from = frame->n_vectors;
606  next_index = node->cached_next_index;
607 
608  while (n_left_from > 0)
609  {
610  u32 n_left_to_next;
611 
612  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
613 
614  while (n_left_from > 0 && n_left_to_next > 0)
615  {
616  u32 bi0;
617  vlib_buffer_t *b0;
618  u32 next0;
619  ip6_header_t *ip60;
620  u16 l4_offset0, frag_offset0;
621  u8 l4_protocol0;
622  u32 proto0;
624 
625  /* speculatively enqueue b0 to the current next frame */
626  bi0 = from[0];
627  to_next[0] = bi0;
628  from += 1;
629  to_next += 1;
630  n_left_from -= 1;
631  n_left_to_next -= 1;
632 
633  b0 = vlib_get_buffer (vm, bi0);
634  ip60 = vlib_buffer_get_current (b0);
635 
636  ctx0.b = b0;
637  ctx0.vm = vm;
638 
640 
641  if (PREDICT_FALSE
642  (ip6_parse
643  (ip60, b0->current_length, &l4_protocol0, &l4_offset0,
644  &frag_offset0)))
645  {
646  next0 = NAT64_IN2OUT_NEXT_DROP;
647  b0->error = node->errors[NAT64_IN2OUT_ERROR_UNKNOWN];
648  goto trace0;
649  }
650 
651  proto0 = ip_proto_to_snat_proto (l4_protocol0);
652  if (PREDICT_FALSE ((proto0 == ~0) || (frag_offset0 != 0)))
653  {
654  next0 = NAT64_IN2OUT_NEXT_DROP;
655  b0->error =
656  node->errors[NAT64_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
657  goto trace0;
658  }
659 
660  if (proto0 == SNAT_PROTOCOL_ICMP)
661  {
662  if (is_hairpinning (&ip60->dst_address))
663  {
665  if (nat64_in2out_icmp_hairpinning (vm, b0, ip60))
666  {
667  next0 = NAT64_IN2OUT_NEXT_DROP;
668  b0->error =
669  node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
670  }
671  goto trace0;
672  }
673 
674  if (icmp6_to_icmp
675  (b0, nat64_in2out_icmp_set_cb, &ctx0,
677  {
678  next0 = NAT64_IN2OUT_NEXT_DROP;
679  b0->error = node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
680  goto trace0;
681  }
682  }
683  else
684  {
685  if (is_hairpinning (&ip60->dst_address))
686  {
688  if (nat64_in2out_tcp_udp_hairpinning (vm, b0, ip60))
689  {
690  next0 = NAT64_IN2OUT_NEXT_DROP;
691  b0->error =
692  node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
693  }
694  goto trace0;
695  }
696 
698  (b0, nat64_in2out_tcp_udp_set_cb, &ctx0, 0))
699  {
700  next0 = NAT64_IN2OUT_NEXT_DROP;
701  b0->error = node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
702  goto trace0;
703  }
704  }
705 
706  trace0:
708  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
709  {
711  vlib_add_trace (vm, node, b0, sizeof (*t));
712  t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
713  t->next_index = next0;
714  }
715 
716  pkts_processed += next0 != NAT64_IN2OUT_NEXT_DROP;
717 
718  /* verify speculative enqueue, maybe switch current next frame */
719  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
720  n_left_to_next, bi0, next0);
721  }
722  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
723  }
725  NAT64_IN2OUT_ERROR_IN2OUT_PACKETS,
726  pkts_processed);
727  return frame->n_vectors;
728 }
729 
730 /* *INDENT-OFF* */
732  .function = nat64_in2out_node_fn,.name = "nat64-in2out",
733  .vector_size = sizeof (u32),
734  .format_trace = format_nat64_in2out_trace,
735  .type = VLIB_NODE_TYPE_INTERNAL,
737  .error_strings = nat64_in2out_error_strings,
738  .n_next_nodes = 2,
739  /* edit / add dispositions here */
740  .next_nodes = {
741  [NAT64_IN2OUT_NEXT_DROP] = "error-drop",
742  [NAT64_IN2OUT_NEXT_IP4_LOOKUP] = "ip4-lookup",
743  [NAT64_IN2OUT_NEXT_IP6_LOOKUP] = "ip6-lookup",
744  },
745 };
746 /* *INDENT-ON* */
747 
749 
750 /*
751  * fd.io coding-style-patch-verification: ON
752  *
753  * Local Variables:
754  * eval: (c-set-style "gnu")
755  * End:
756  */
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
#define CLIB_UNUSED(x)
Definition: clib.h:79
int nat64_alloc_out_addr_and_port(u32 fib_index, snat_protocol_t proto, ip4_address_t *addr, u16 *port)
Alloce IPv4 address and port pair from NAT64 pool.
Definition: nat64.c:227
ip4_address_t src_address
Definition: ip4_packet.h:164
snat_address_t * addr_pool
Address pool vector.
Definition: nat64.h:56
static int icmp6_to_icmp(vlib_buffer_t *p, ip6_to_ip4_set_fn_t fn, void *ctx, ip6_to_ip4_set_fn_t inner_fn, void *inner_ctx)
Translate ICMP6 packet to ICMP4.
Definition: ip6_to_ip4.h:249
void nat64_extract_ip4(ip6_address_t *ip6, ip4_address_t *ip4, u32 fib_index)
Extract IPv4 address from the IPv4-embedded IPv6 addresses.
Definition: nat64.c:744
nat64_db_bib_entry_t * nat64_db_bib_entry_create(nat64_db_t *db, ip6_address_t *in_addr, ip4_address_t *out_addr, u16 in_port, u16 out_port, u32 fib_index, snat_protocol_t proto, u8 is_static)
Create new NAT64 BIB entry.
Definition: nat64_db.c:45
u64 as_u64[2]
Definition: ip6_packet.h:51
vlib_node_registration_t nat64_in2out_node
(constructor) VLIB_REGISTER_NODE (nat64_in2out_node)
Definition: nat64_in2out.c:44
nat64_db_st_entry_t * nat64_db_st_entry_create(nat64_db_t *db, nat64_db_bib_entry_t *bibe, ip6_address_t *in_r_addr, ip4_address_t *out_r_addr, u16 r_port)
Create new NAT64 session table entry.
Definition: nat64_db.c:297
nat64_in2out_next_t
Definition: nat64_in2out.c:66
u32 fib_table_get_index_for_sw_if_index(fib_protocol_t proto, u32 sw_if_index)
Get the index of the FIB bound to the interface.
Definition: fib_table.c:929
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:459
struct _vlib_node_registration vlib_node_registration_t
uword ip_csum_t
Definition: ip_packet.h:90
static ip_csum_t ip_csum_with_carry(ip_csum_t sum, ip_csum_t x)
Definition: ip_packet.h:93
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
static u8 * format_nat64_in2out_trace(u8 *s, va_list *args)
Definition: nat64_in2out.c:31
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:419
static int nat64_in2out_icmp_hairpinning(vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip6)
Definition: nat64_in2out.c:481
struct _tcp_header tcp_header_t
ip6_address_t src_address
Definition: ip6_packet.h:341
nat64_db_st_entry_t * nat64_db_st_entry_find(nat64_db_t *db, ip46_address_t *l_addr, ip46_address_t *r_addr, u16 l_port, u16 r_port, snat_protocol_t proto, u32 fib_index, u8 is_ip6)
Find NAT64 session table entry.
Definition: nat64_db.c:439
#define static_always_inline
Definition: clib.h:85
ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_checksum.c:43
nat64_db_bib_entry_t * nat64_db_bib_entry_find(nat64_db_t *db, ip46_address_t *addr, u16 port, snat_protocol_t proto, u32 fib_index, u8 is_ip6)
Find NAT64 BIB entry.
Definition: nat64_db.c:171
ip4_address_t dst_address
Definition: ip4_packet.h:164
static_always_inline int ip6_parse(const ip6_header_t *ip6, u32 buff_len, u8 *l4_protocol, u16 *l4_offset, u16 *frag_hdr_offset)
Parse some useful information from IPv6 header.
Definition: ip6_to_ip4.h:59
nat64_db_t db
BIB and session DB.
Definition: nat64.h:62
static int ip6_to_ip4_tcp_udp(vlib_buffer_t *p, ip6_to_ip4_set_fn_t fn, void *ctx, u8 udp_checksum)
Translate IPv6 UDP/TCP packet to IPv4.
Definition: ip6_to_ip4.h:478
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:71
void nat64_session_reset_timeout(nat64_db_st_entry_t *ste, vlib_main_t *vm)
Reset NAT64 session timeout.
Definition: nat64.c:506
vlib_buffer_t * b
Definition: nat64_in2out.c:76
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:188
#define PREDICT_FALSE(x)
Definition: clib.h:97
static int nat64_in2out_inner_icmp_set_cb(ip6_header_t *ip6, ip4_header_t *ip4, void *arg)
Definition: nat64_in2out.c:276
static char * nat64_in2out_error_strings[]
Definition: nat64_in2out.c:60
#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:216
#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:366
void nat64_compose_ip6(ip6_address_t *ip6, ip4_address_t *ip4, u32 fib_index)
Compose IPv4-embedded IPv6 addresses.
Definition: nat64.c:673
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:113
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1131
u32 as_u32[4]
Definition: ip6_packet.h:50
static int nat64_in2out_icmp_set_cb(ip6_header_t *ip6, ip4_header_t *ip4, void *arg)
Definition: nat64_in2out.c:191
u16 n_vectors
Definition: node.h:345
nat64_db_bib_entry_t * nat64_db_bib_entry_by_index(nat64_db_t *db, snat_protocol_t proto, u32 bibe_index)
Get BIB entry by index and protocol.
Definition: nat64_db.c:243
static int nat64_in2out_tcp_udp_set_cb(ip6_header_t *ip6, ip4_header_t *ip4, void *arg)
Definition: nat64_in2out.c:106
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:85
#define ARRAY_LEN(x)
Definition: clib.h:59
static int nat64_in2out_tcp_udp_hairpinning(vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip6)
Definition: nat64_in2out.c:357
nat64_main_t nat64_main
Definition: nat64.c:25
static void * ip6_next_header(ip6_header_t *i)
Definition: ip6_packet.h:351
snat_protocol_t
Definition: snat.h:98
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:460
#define u8_ptr_add(ptr, index)
Definition: map.h:513
unsigned int u32
Definition: types.h:88
nat64_in2out_error_t
Definition: nat64_in2out.c:52
static ip_csum_t ip_csum_sub_even(ip_csum_t c, ip_csum_t x)
Definition: ip_packet.h:117
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:260
IPv6 to IPv4 translation.
ip4_address_t addr
Definition: snat.h:158
u64 uword
Definition: types.h:112
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
NAT64 global declarations.
unsigned short u16
Definition: types.h:57
u16 payload_length
Definition: ip6_packet.h:332
VLIB_NODE_FUNCTION_MULTIARCH(nat64_in2out_node, nat64_in2out_node_fn)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:269
static u32 ip_proto_to_snat_proto(u8 ip_proto)
Definition: snat.h:389
#define vnet_buffer(b)
Definition: buffer.h:304
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:144
static_always_inline int is_hairpinning(ip6_address_t *dst_addr)
Check whether is a hairpinning.
Definition: nat64_in2out.c:91
static uword nat64_in2out_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nat64_in2out.c:597
u16 flags
Copy of main node flags.
Definition: node.h:454
#define foreach_nat64_in2out_error
Definition: nat64_in2out.c:46
struct nat64_in2out_set_ctx_t_ nat64_in2out_set_ctx_t
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:74
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:145
Definition: defs.h:46
static ip_csum_t ip_csum_add_even(ip_csum_t c, ip_csum_t x)
Definition: ip_packet.h:101
ip6_address_t dst_address
Definition: ip6_packet.h:341