FD.io VPP  v17.10-9-gd594711
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 <nat/nat64.h>
21 #include <vnet/ip/ip6_to_ip4.h>
22 #include <vnet/fib/fib_table.h>
23 
24 typedef struct
25 {
30 
31 static u8 *
32 format_nat64_in2out_trace (u8 * s, va_list * args)
33 {
34  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
35  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
36  nat64_in2out_trace_t *t = va_arg (*args, nat64_in2out_trace_t *);
37  char *tag;
38 
39  tag = t->is_slow_path ? "NAT64-in2out-slowpath" : "NAT64-in2out";
40 
41  s =
42  format (s, "%s: sw_if_index %d, next index %d", tag, t->sw_if_index,
43  t->next_index);
44 
45  return s;
46 }
47 
50 
51 #define foreach_nat64_in2out_error \
52 _(UNSUPPORTED_PROTOCOL, "unsupported protocol") \
53 _(IN2OUT_PACKETS, "good in2out packets processed") \
54 _(NO_TRANSLATION, "no translation") \
55 _(UNKNOWN, "unknown")
56 
57 typedef enum
58 {
59 #define _(sym,str) NAT64_IN2OUT_ERROR_##sym,
61 #undef _
64 
65 static char *nat64_in2out_error_strings[] = {
66 #define _(sym,string) string,
68 #undef _
69 };
70 
71 typedef enum
72 {
79 
81 {
85 
86 /**
87  * @brief Check whether is a hairpinning.
88  *
89  * If the destination IP address of the packet is an IPv4 address assigned to
90  * the NAT64 itself, then the packet is a hairpin packet.
91  *
92  * param dst_addr Destination address of the packet.
93  *
94  * @returns 1 if hairpinning, otherwise 0.
95  */
98 {
99  nat64_main_t *nm = &nat64_main;
100  int i;
101 
102  for (i = 0; i < vec_len (nm->addr_pool); i++)
103  {
104  if (nm->addr_pool[i].addr.as_u32 == dst_addr->as_u32[3])
105  return 1;
106  }
107 
108  return 0;
109 }
110 
111 static int
113  void *arg)
114 {
115  nat64_main_t *nm = &nat64_main;
117  nat64_db_bib_entry_t *bibe;
118  nat64_db_st_entry_t *ste;
119  ip46_address_t saddr, daddr;
120  u32 sw_if_index, fib_index;
121  udp_header_t *udp = ip6_next_header (ip6);
122  u8 proto = ip6->protocol;
123  u16 sport = udp->src_port;
124  u16 dport = udp->dst_port;
125 
126  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
127  fib_index =
129 
130  saddr.as_u64[0] = ip6->src_address.as_u64[0];
131  saddr.as_u64[1] = ip6->src_address.as_u64[1];
132  daddr.as_u64[0] = ip6->dst_address.as_u64[0];
133  daddr.as_u64[1] = ip6->dst_address.as_u64[1];
134 
135  ste =
136  nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto,
137  fib_index, 1);
138 
139  if (ste)
140  {
141  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
142  if (!bibe)
143  return -1;
144  }
145  else
146  {
147  bibe =
148  nat64_db_bib_entry_find (&nm->db, &saddr, sport, proto, fib_index, 1);
149 
150  if (!bibe)
151  {
152  u16 out_port;
153  ip4_address_t out_addr;
155  (fib_index, ip_proto_to_snat_proto (proto), &out_addr,
156  &out_port))
157  return -1;
158 
159  bibe =
160  nat64_db_bib_entry_create (&nm->db, &ip6->src_address, &out_addr,
161  sport, clib_host_to_net_u16 (out_port),
162  fib_index, proto, 0);
163  if (!bibe)
164  return -1;
165  }
166 
167  nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index);
168  ste =
169  nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address,
170  &daddr.ip4, dport);
171  if (!ste)
172  return -1;
173  }
174 
175  nat64_session_reset_timeout (ste, ctx->vm);
176 
177  ip4->src_address.as_u32 = bibe->out_addr.as_u32;
178  udp->src_port = bibe->out_port;
179 
180  ip4->dst_address.as_u32 = ste->out_r_addr.as_u32;
181 
182  if (proto == IP_PROTOCOL_TCP)
183  {
184  u16 *checksum;
185  ip_csum_t csum;
186  tcp_header_t *tcp = ip6_next_header (ip6);
187 
188  checksum = &tcp->checksum;
189  csum = ip_csum_sub_even (*checksum, sport);
190  csum = ip_csum_add_even (csum, udp->src_port);
191  *checksum = ip_csum_fold (csum);
192  }
193 
194  return 0;
195 }
196 
197 static int
199 {
200  nat64_main_t *nm = &nat64_main;
202  nat64_db_bib_entry_t *bibe;
203  nat64_db_st_entry_t *ste;
204  ip46_address_t saddr, daddr;
205  u32 sw_if_index, fib_index;
206  icmp46_header_t *icmp = ip6_next_header (ip6);
207 
208  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
209  fib_index =
211 
212  saddr.as_u64[0] = ip6->src_address.as_u64[0];
213  saddr.as_u64[1] = ip6->src_address.as_u64[1];
214  daddr.as_u64[0] = ip6->dst_address.as_u64[0];
215  daddr.as_u64[1] = ip6->dst_address.as_u64[1];
216 
217  if (icmp->type == ICMP4_echo_request || icmp->type == ICMP4_echo_reply)
218  {
219  u16 in_id = ((u16 *) (icmp))[2];
220  ste =
221  nat64_db_st_entry_find (&nm->db, &saddr, &daddr, in_id, 0,
222  IP_PROTOCOL_ICMP, fib_index, 1);
223 
224  if (ste)
225  {
226  bibe =
227  nat64_db_bib_entry_by_index (&nm->db, IP_PROTOCOL_ICMP,
228  ste->bibe_index);
229  if (!bibe)
230  return -1;
231  }
232  else
233  {
234  bibe =
235  nat64_db_bib_entry_find (&nm->db, &saddr, in_id,
236  IP_PROTOCOL_ICMP, fib_index, 1);
237 
238  if (!bibe)
239  {
240  u16 out_id;
241  ip4_address_t out_addr;
243  (fib_index, SNAT_PROTOCOL_ICMP, &out_addr, &out_id))
244  return -1;
245 
246  bibe =
248  &out_addr, in_id,
249  clib_host_to_net_u16 (out_id),
250  fib_index, IP_PROTOCOL_ICMP, 0);
251  if (!bibe)
252  return -1;
253  }
254 
255  nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index);
256  ste =
257  nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address,
258  &daddr.ip4, 0);
259  if (!ste)
260  return -1;
261  }
262 
263  nat64_session_reset_timeout (ste, ctx->vm);
264 
265  ip4->src_address.as_u32 = bibe->out_addr.as_u32;
266  ((u16 *) (icmp))[2] = bibe->out_port;
267 
268  ip4->dst_address.as_u32 = ste->out_r_addr.as_u32;
269  }
270  else
271  {
272  if (!vec_len (nm->addr_pool))
273  return -1;
274 
275  ip4->src_address.as_u32 = nm->addr_pool[0].addr.as_u32;
276  nat64_extract_ip4 (&ip6->dst_address, &ip4->dst_address, fib_index);
277  }
278 
279  return 0;
280 }
281 
282 static int
284  void *arg)
285 {
286  nat64_main_t *nm = &nat64_main;
288  nat64_db_st_entry_t *ste;
289  nat64_db_bib_entry_t *bibe;
290  ip46_address_t saddr, daddr;
291  u32 sw_if_index, fib_index;
292  u8 proto = ip6->protocol;
293 
294  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
295  fib_index =
297 
298  saddr.as_u64[0] = ip6->src_address.as_u64[0];
299  saddr.as_u64[1] = ip6->src_address.as_u64[1];
300  daddr.as_u64[0] = ip6->dst_address.as_u64[0];
301  daddr.as_u64[1] = ip6->dst_address.as_u64[1];
302 
303  if (proto == IP_PROTOCOL_ICMP6)
304  {
305  icmp46_header_t *icmp = ip6_next_header (ip6);
306  u16 in_id = ((u16 *) (icmp))[2];
307  proto = IP_PROTOCOL_ICMP;
308 
309  if (!
310  (icmp->type == ICMP4_echo_request
311  || icmp->type == ICMP4_echo_reply))
312  return -1;
313 
314  ste =
315  nat64_db_st_entry_find (&nm->db, &daddr, &saddr, in_id, 0, proto,
316  fib_index, 1);
317  if (!ste)
318  return -1;
319 
320  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
321  if (!bibe)
322  return -1;
323 
324  ip4->dst_address.as_u32 = bibe->out_addr.as_u32;
325  ((u16 *) (icmp))[2] = bibe->out_port;
326  ip4->src_address.as_u32 = ste->out_r_addr.as_u32;
327  }
328  else
329  {
330  udp_header_t *udp = ip6_next_header (ip6);
331  tcp_header_t *tcp = ip6_next_header (ip6);
332  u16 *checksum;
333  ip_csum_t csum;
334 
335  u16 sport = udp->src_port;
336  u16 dport = udp->dst_port;
337 
338  ste =
339  nat64_db_st_entry_find (&nm->db, &daddr, &saddr, dport, sport, proto,
340  fib_index, 1);
341  if (!ste)
342  return -1;
343 
344  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
345  if (!bibe)
346  return -1;
347 
348  ip4->dst_address.as_u32 = bibe->out_addr.as_u32;
349  udp->dst_port = bibe->out_port;
350  ip4->src_address.as_u32 = ste->out_r_addr.as_u32;
351 
352  if (proto == IP_PROTOCOL_TCP)
353  checksum = &tcp->checksum;
354  else
355  checksum = &udp->checksum;
356  csum = ip_csum_sub_even (*checksum, dport);
357  csum = ip_csum_add_even (csum, udp->dst_port);
358  *checksum = ip_csum_fold (csum);
359  }
360 
361  return 0;
362 }
363 
365 {
372 
373 static int
374 unk_proto_st_walk (nat64_db_st_entry_t * ste, void *arg)
375 {
376  nat64_main_t *nm = &nat64_main;
378  nat64_db_bib_entry_t *bibe;
379  ip46_address_t saddr, daddr;
380 
381  if (ip46_address_is_equal (&ste->in_r_addr, &ctx->dst_addr))
382  {
383  bibe =
384  nat64_db_bib_entry_by_index (&nm->db, ste->proto, ste->bibe_index);
385  if (!bibe)
386  return -1;
387 
388  if (ip46_address_is_equal (&bibe->in_addr, &ctx->src_addr)
389  && bibe->fib_index == ctx->fib_index)
390  {
391  memset (&saddr, 0, sizeof (saddr));
392  saddr.ip4.as_u32 = bibe->out_addr.as_u32;
393  memset (&daddr, 0, sizeof (daddr));
394  nat64_extract_ip4 (&ctx->dst_addr, &daddr.ip4, ctx->fib_index);
395 
397  (&nm->db, &daddr, &saddr, 0, 0, ctx->proto, ctx->fib_index, 0))
398  return -1;
399 
400  ctx->out_addr.as_u32 = bibe->out_addr.as_u32;
401  return 1;
402  }
403  }
404 
405  return 0;
406 }
407 
408 static int
410  void *arg)
411 {
412  nat64_main_t *nm = &nat64_main;
414  nat64_db_bib_entry_t *bibe;
415  nat64_db_st_entry_t *ste;
416  ip46_address_t saddr, daddr, addr;
417  u32 sw_if_index, fib_index;
418  u8 proto = ip6->protocol;
419  int i;
420 
421  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
422  fib_index =
424 
425  saddr.as_u64[0] = ip6->src_address.as_u64[0];
426  saddr.as_u64[1] = ip6->src_address.as_u64[1];
427  daddr.as_u64[0] = ip6->dst_address.as_u64[0];
428  daddr.as_u64[1] = ip6->dst_address.as_u64[1];
429 
430  ste =
431  nat64_db_st_entry_find (&nm->db, &saddr, &daddr, 0, 0, proto, fib_index,
432  1);
433 
434  if (ste)
435  {
436  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
437  if (!bibe)
438  return -1;
439  }
440  else
441  {
442  bibe =
443  nat64_db_bib_entry_find (&nm->db, &saddr, 0, proto, fib_index, 1);
444 
445  if (!bibe)
446  {
447  /* Choose same out address as for TCP/UDP session to same dst */
449  .src_addr.as_u64[0] = ip6->src_address.as_u64[0],
450  .src_addr.as_u64[1] = ip6->src_address.as_u64[1],
451  .dst_addr.as_u64[0] = ip6->dst_address.as_u64[0],
452  .dst_addr.as_u64[1] = ip6->dst_address.as_u64[1],
453  .out_addr.as_u32 = 0,
454  .fib_index = fib_index,
455  .proto = proto,
456  };
457 
458  nat64_db_st_walk (&nm->db, IP_PROTOCOL_TCP, unk_proto_st_walk,
459  &ctx);
460 
461  if (!ctx.out_addr.as_u32)
462  nat64_db_st_walk (&nm->db, IP_PROTOCOL_UDP, unk_proto_st_walk,
463  &ctx);
464 
465  /* Verify if out address is not already in use for protocol */
466  memset (&addr, 0, sizeof (addr));
467  addr.ip4.as_u32 = ctx.out_addr.as_u32;
468  if (nat64_db_bib_entry_find (&nm->db, &addr, 0, proto, 0, 0))
469  ctx.out_addr.as_u32 = 0;
470 
471  if (!ctx.out_addr.as_u32)
472  {
473  for (i = 0; i < vec_len (nm->addr_pool); i++)
474  {
475  addr.ip4.as_u32 = nm->addr_pool[i].addr.as_u32;
477  (&nm->db, &addr, 0, proto, 0, 0))
478  break;
479  }
480  }
481 
482  if (!ctx.out_addr.as_u32)
483  return -1;
484 
485  bibe =
487  &ctx.out_addr, 0, 0, fib_index, proto,
488  0);
489  if (!bibe)
490  return -1;
491  }
492 
493  nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index);
494  ste =
495  nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address,
496  &daddr.ip4, 0);
497  if (!ste)
498  return -1;
499  }
500 
501  nat64_session_reset_timeout (ste, ctx->vm);
502 
503  ip4->src_address.as_u32 = bibe->out_addr.as_u32;
504  ip4->dst_address.as_u32 = ste->out_r_addr.as_u32;
505 
506  return 0;
507 }
508 
509 
510 
511 static int
513  ip6_header_t * ip6)
514 {
515  nat64_main_t *nm = &nat64_main;
516  nat64_db_bib_entry_t *bibe;
517  nat64_db_st_entry_t *ste;
518  ip46_address_t saddr, daddr;
519  u32 sw_if_index, fib_index;
520  udp_header_t *udp = ip6_next_header (ip6);
521  tcp_header_t *tcp = ip6_next_header (ip6);
522  u8 proto = ip6->protocol;
523  u16 sport = udp->src_port;
524  u16 dport = udp->dst_port;
525  u16 *checksum;
526  ip_csum_t csum;
527 
528  sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
529  fib_index =
531 
532  saddr.as_u64[0] = ip6->src_address.as_u64[0];
533  saddr.as_u64[1] = ip6->src_address.as_u64[1];
534  daddr.as_u64[0] = ip6->dst_address.as_u64[0];
535  daddr.as_u64[1] = ip6->dst_address.as_u64[1];
536 
537  if (proto == IP_PROTOCOL_UDP)
538  checksum = &udp->checksum;
539  else
540  checksum = &tcp->checksum;
541 
542  csum = ip_csum_sub_even (*checksum, ip6->src_address.as_u64[0]);
543  csum = ip_csum_sub_even (csum, ip6->src_address.as_u64[1]);
544  csum = ip_csum_sub_even (csum, ip6->dst_address.as_u64[0]);
545  csum = ip_csum_sub_even (csum, ip6->dst_address.as_u64[1]);
546  csum = ip_csum_sub_even (csum, sport);
547  csum = ip_csum_sub_even (csum, dport);
548 
549  ste =
550  nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto,
551  fib_index, 1);
552 
553  if (ste)
554  {
555  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
556  if (!bibe)
557  return -1;
558  }
559  else
560  {
561  bibe =
562  nat64_db_bib_entry_find (&nm->db, &saddr, sport, proto, fib_index, 1);
563 
564  if (!bibe)
565  {
566  u16 out_port;
567  ip4_address_t out_addr;
569  (fib_index, ip_proto_to_snat_proto (proto), &out_addr,
570  &out_port))
571  return -1;
572 
573  bibe =
574  nat64_db_bib_entry_create (&nm->db, &ip6->src_address, &out_addr,
575  sport, clib_host_to_net_u16 (out_port),
576  fib_index, proto, 0);
577  if (!bibe)
578  return -1;
579  }
580 
581  nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index);
582  ste =
583  nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address,
584  &daddr.ip4, dport);
585  if (!ste)
586  return -1;
587  }
588 
589  nat64_session_reset_timeout (ste, vm);
590 
591  sport = udp->src_port = bibe->out_port;
592  nat64_compose_ip6 (&ip6->src_address, &bibe->out_addr, fib_index);
593 
594  memset (&saddr, 0, sizeof (saddr));
595  memset (&daddr, 0, sizeof (daddr));
596  saddr.ip4.as_u32 = bibe->out_addr.as_u32;
597  daddr.ip4.as_u32 = ste->out_r_addr.as_u32;
598 
599  ste =
600  nat64_db_st_entry_find (&nm->db, &daddr, &saddr, dport, sport, proto, 0,
601  0);
602 
603  if (ste)
604  {
605  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
606  if (!bibe)
607  return -1;
608  }
609  else
610  {
611  bibe = nat64_db_bib_entry_find (&nm->db, &daddr, dport, proto, 0, 0);
612 
613  if (!bibe)
614  return -1;
615 
616  ste =
617  nat64_db_st_entry_create (&nm->db, bibe, &ip6->src_address,
618  &saddr.ip4, sport);
619  }
620 
621  ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
622  ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
623  udp->dst_port = bibe->in_port;
624 
625  csum = ip_csum_add_even (csum, ip6->src_address.as_u64[0]);
626  csum = ip_csum_add_even (csum, ip6->src_address.as_u64[1]);
627  csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[0]);
628  csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[1]);
629  csum = ip_csum_add_even (csum, udp->src_port);
630  csum = ip_csum_add_even (csum, udp->dst_port);
631  *checksum = ip_csum_fold (csum);
632 
633  return 0;
634 }
635 
636 static int
638  ip6_header_t * ip6)
639 {
640  nat64_main_t *nm = &nat64_main;
641  nat64_db_bib_entry_t *bibe;
642  nat64_db_st_entry_t *ste;
643  icmp46_header_t *icmp = ip6_next_header (ip6);
644  ip6_header_t *inner_ip6;
645  ip46_address_t saddr, daddr;
646  u32 sw_if_index, fib_index;
647  u8 proto;
648  udp_header_t *udp;
649  tcp_header_t *tcp;
650  u16 *checksum, sport, dport;
651  ip_csum_t csum;
652 
653  if (icmp->type == ICMP6_echo_request || icmp->type == ICMP6_echo_reply)
654  return -1;
655 
656  inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
657 
658  proto = inner_ip6->protocol;
659 
660  if (proto == IP_PROTOCOL_ICMP6)
661  return -1;
662 
663  sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
664  fib_index =
666 
667  saddr.as_u64[0] = inner_ip6->src_address.as_u64[0];
668  saddr.as_u64[1] = inner_ip6->src_address.as_u64[1];
669  daddr.as_u64[0] = inner_ip6->dst_address.as_u64[0];
670  daddr.as_u64[1] = inner_ip6->dst_address.as_u64[1];
671 
672  udp = ip6_next_header (inner_ip6);
673  tcp = ip6_next_header (inner_ip6);
674 
675  sport = udp->src_port;
676  dport = udp->dst_port;
677 
678  if (proto == IP_PROTOCOL_UDP)
679  checksum = &udp->checksum;
680  else
681  checksum = &tcp->checksum;
682 
683  csum = ip_csum_sub_even (*checksum, inner_ip6->src_address.as_u64[0]);
684  csum = ip_csum_sub_even (csum, inner_ip6->src_address.as_u64[1]);
685  csum = ip_csum_sub_even (csum, inner_ip6->dst_address.as_u64[0]);
686  csum = ip_csum_sub_even (csum, inner_ip6->dst_address.as_u64[1]);
687  csum = ip_csum_sub_even (csum, sport);
688  csum = ip_csum_sub_even (csum, dport);
689 
690  ste =
691  nat64_db_st_entry_find (&nm->db, &daddr, &saddr, dport, sport, proto,
692  fib_index, 1);
693  if (!ste)
694  return -1;
695 
696  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
697  if (!bibe)
698  return -1;
699 
700  dport = udp->dst_port = bibe->out_port;
701  nat64_compose_ip6 (&inner_ip6->dst_address, &bibe->out_addr, fib_index);
702 
703  memset (&saddr, 0, sizeof (saddr));
704  memset (&daddr, 0, sizeof (daddr));
705  saddr.ip4.as_u32 = ste->out_r_addr.as_u32;
706  daddr.ip4.as_u32 = bibe->out_addr.as_u32;
707 
708  ste =
709  nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto, 0,
710  0);
711  if (!ste)
712  return -1;
713 
714  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
715  if (!bibe)
716  return -1;
717 
718  inner_ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
719  inner_ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
720  udp->src_port = bibe->in_port;
721 
722  csum = ip_csum_add_even (csum, inner_ip6->src_address.as_u64[0]);
723  csum = ip_csum_add_even (csum, inner_ip6->src_address.as_u64[1]);
724  csum = ip_csum_add_even (csum, inner_ip6->dst_address.as_u64[0]);
725  csum = ip_csum_add_even (csum, inner_ip6->dst_address.as_u64[1]);
726  csum = ip_csum_add_even (csum, udp->src_port);
727  csum = ip_csum_add_even (csum, udp->dst_port);
728  *checksum = ip_csum_fold (csum);
729 
730  if (!vec_len (nm->addr_pool))
731  return -1;
732 
733  nat64_compose_ip6 (&ip6->src_address, &nm->addr_pool[0].addr, fib_index);
734  ip6->dst_address.as_u64[0] = inner_ip6->src_address.as_u64[0];
735  ip6->dst_address.as_u64[1] = inner_ip6->src_address.as_u64[1];
736 
737  icmp->checksum = 0;
738  csum = ip_csum_with_carry (0, ip6->payload_length);
739  csum = ip_csum_with_carry (csum, clib_host_to_net_u16 (ip6->protocol));
740  csum = ip_csum_with_carry (csum, ip6->src_address.as_u64[0]);
741  csum = ip_csum_with_carry (csum, ip6->src_address.as_u64[1]);
742  csum = ip_csum_with_carry (csum, ip6->dst_address.as_u64[0]);
743  csum = ip_csum_with_carry (csum, ip6->dst_address.as_u64[1]);
744  csum =
745  ip_incremental_checksum (csum, icmp,
746  clib_net_to_host_u16 (ip6->payload_length));
747  icmp->checksum = ~ip_csum_fold (csum);
748 
749  return 0;
750 }
751 
752 static int
754  ip6_header_t * ip6)
755 {
756  nat64_main_t *nm = &nat64_main;
757  nat64_db_bib_entry_t *bibe;
758  nat64_db_st_entry_t *ste;
759  ip46_address_t saddr, daddr, addr;
760  u32 sw_if_index, fib_index;
761  u8 proto = ip6->protocol;
762  int i;
763 
764  sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
765  fib_index =
767 
768  saddr.as_u64[0] = ip6->src_address.as_u64[0];
769  saddr.as_u64[1] = ip6->src_address.as_u64[1];
770  daddr.as_u64[0] = ip6->dst_address.as_u64[0];
771  daddr.as_u64[1] = ip6->dst_address.as_u64[1];
772 
773  ste =
774  nat64_db_st_entry_find (&nm->db, &saddr, &daddr, 0, 0, proto, fib_index,
775  1);
776 
777  if (ste)
778  {
779  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
780  if (!bibe)
781  return -1;
782  }
783  else
784  {
785  bibe =
786  nat64_db_bib_entry_find (&nm->db, &saddr, 0, proto, fib_index, 1);
787 
788  if (!bibe)
789  {
790  /* Choose same out address as for TCP/UDP session to same dst */
792  .src_addr.as_u64[0] = ip6->src_address.as_u64[0],
793  .src_addr.as_u64[1] = ip6->src_address.as_u64[1],
794  .dst_addr.as_u64[0] = ip6->dst_address.as_u64[0],
795  .dst_addr.as_u64[1] = ip6->dst_address.as_u64[1],
796  .out_addr.as_u32 = 0,
797  .fib_index = fib_index,
798  .proto = proto,
799  };
800 
801  nat64_db_st_walk (&nm->db, IP_PROTOCOL_TCP, unk_proto_st_walk,
802  &ctx);
803 
804  if (!ctx.out_addr.as_u32)
805  nat64_db_st_walk (&nm->db, IP_PROTOCOL_UDP, unk_proto_st_walk,
806  &ctx);
807 
808  /* Verify if out address is not already in use for protocol */
809  memset (&addr, 0, sizeof (addr));
810  addr.ip4.as_u32 = ctx.out_addr.as_u32;
811  if (nat64_db_bib_entry_find (&nm->db, &addr, 0, proto, 0, 0))
812  ctx.out_addr.as_u32 = 0;
813 
814  if (!ctx.out_addr.as_u32)
815  {
816  for (i = 0; i < vec_len (nm->addr_pool); i++)
817  {
818  addr.ip4.as_u32 = nm->addr_pool[i].addr.as_u32;
820  (&nm->db, &addr, 0, proto, 0, 0))
821  break;
822  }
823  }
824 
825  if (!ctx.out_addr.as_u32)
826  return -1;
827 
828  bibe =
830  &ctx.out_addr, 0, 0, fib_index, proto,
831  0);
832  if (!bibe)
833  return -1;
834  }
835 
836  nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index);
837  ste =
838  nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address,
839  &daddr.ip4, 0);
840  if (!ste)
841  return -1;
842  }
843 
844  nat64_session_reset_timeout (ste, vm);
845 
846  nat64_compose_ip6 (&ip6->src_address, &bibe->out_addr, fib_index);
847 
848  memset (&saddr, 0, sizeof (saddr));
849  memset (&daddr, 0, sizeof (daddr));
850  saddr.ip4.as_u32 = bibe->out_addr.as_u32;
851  daddr.ip4.as_u32 = ste->out_r_addr.as_u32;
852 
853  ste = nat64_db_st_entry_find (&nm->db, &daddr, &saddr, 0, 0, proto, 0, 0);
854 
855  if (ste)
856  {
857  bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
858  if (!bibe)
859  return -1;
860  }
861  else
862  {
863  bibe = nat64_db_bib_entry_find (&nm->db, &daddr, 0, proto, 0, 0);
864 
865  if (!bibe)
866  return -1;
867 
868  ste =
869  nat64_db_st_entry_create (&nm->db, bibe, &ip6->src_address,
870  &saddr.ip4, 0);
871  }
872 
873  ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
874  ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
875 
876  return 0;
877 }
878 
879 static inline uword
881  vlib_frame_t * frame, u8 is_slow_path)
882 {
883  u32 n_left_from, *from, *to_next;
884  nat64_in2out_next_t next_index;
885  u32 pkts_processed = 0;
886  u32 stats_node_index;
887 
888  stats_node_index =
889  is_slow_path ? nat64_in2out_slowpath_node.index : nat64_in2out_node.index;
890 
891  from = vlib_frame_vector_args (frame);
892  n_left_from = frame->n_vectors;
893  next_index = node->cached_next_index;
894 
895  while (n_left_from > 0)
896  {
897  u32 n_left_to_next;
898 
899  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
900 
901  while (n_left_from > 0 && n_left_to_next > 0)
902  {
903  u32 bi0;
904  vlib_buffer_t *b0;
905  u32 next0;
906  ip6_header_t *ip60;
907  u16 l4_offset0, frag_offset0;
908  u8 l4_protocol0;
909  u32 proto0;
911 
912  /* speculatively enqueue b0 to the current next frame */
913  bi0 = from[0];
914  to_next[0] = bi0;
915  from += 1;
916  to_next += 1;
917  n_left_from -= 1;
918  n_left_to_next -= 1;
919 
920  b0 = vlib_get_buffer (vm, bi0);
921  ip60 = vlib_buffer_get_current (b0);
922 
923  ctx0.b = b0;
924  ctx0.vm = vm;
925 
927 
928  if (PREDICT_FALSE
929  (ip6_parse
930  (ip60, b0->current_length, &l4_protocol0, &l4_offset0,
931  &frag_offset0)))
932  {
933  next0 = NAT64_IN2OUT_NEXT_DROP;
934  b0->error = node->errors[NAT64_IN2OUT_ERROR_UNKNOWN];
935  goto trace0;
936  }
937 
938  proto0 = ip_proto_to_snat_proto (l4_protocol0);
939  if (frag_offset0 != 0)
940  {
941  next0 = NAT64_IN2OUT_NEXT_DROP;
942  b0->error =
943  node->errors[NAT64_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
944  goto trace0;
945  }
946 
947  if (is_slow_path)
948  {
949  if (PREDICT_TRUE (proto0 == ~0))
950  {
951  if (is_hairpinning (&ip60->dst_address))
952  {
954  if (nat64_in2out_unk_proto_hairpinning (vm, b0, ip60))
955  {
956  next0 = NAT64_IN2OUT_NEXT_DROP;
957  b0->error =
958  node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
959  }
960  goto trace0;
961  }
962 
963  if (ip6_to_ip4 (b0, nat64_in2out_unk_proto_set_cb, &ctx0))
964  {
965  next0 = NAT64_IN2OUT_NEXT_DROP;
966  b0->error =
967  node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
968  goto trace0;
969  }
970  }
971  goto trace0;
972  }
973  else
974  {
975  if (PREDICT_FALSE (proto0 == ~0))
976  {
978  goto trace0;
979  }
980  }
981 
982  if (proto0 == SNAT_PROTOCOL_ICMP)
983  {
984  if (is_hairpinning (&ip60->dst_address))
985  {
987  if (nat64_in2out_icmp_hairpinning (vm, b0, ip60))
988  {
989  next0 = NAT64_IN2OUT_NEXT_DROP;
990  b0->error =
991  node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
992  }
993  goto trace0;
994  }
995 
996  if (icmp6_to_icmp
997  (b0, nat64_in2out_icmp_set_cb, &ctx0,
999  {
1000  next0 = NAT64_IN2OUT_NEXT_DROP;
1001  b0->error = node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
1002  goto trace0;
1003  }
1004  }
1005  else if (proto0 == SNAT_PROTOCOL_TCP || proto0 == SNAT_PROTOCOL_UDP)
1006  {
1007  if (is_hairpinning (&ip60->dst_address))
1008  {
1010  if (nat64_in2out_tcp_udp_hairpinning (vm, b0, ip60))
1011  {
1012  next0 = NAT64_IN2OUT_NEXT_DROP;
1013  b0->error =
1014  node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
1015  }
1016  goto trace0;
1017  }
1018 
1019  if (ip6_to_ip4_tcp_udp
1020  (b0, nat64_in2out_tcp_udp_set_cb, &ctx0, 0))
1021  {
1022  next0 = NAT64_IN2OUT_NEXT_DROP;
1023  b0->error = node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
1024  goto trace0;
1025  }
1026  }
1027 
1028  trace0:
1030  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1031  {
1033  vlib_add_trace (vm, node, b0, sizeof (*t));
1034  t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1035  t->next_index = next0;
1036  t->is_slow_path = is_slow_path;
1037  }
1038 
1039  pkts_processed += next0 != NAT64_IN2OUT_NEXT_DROP;
1040 
1041  /* verify speculative enqueue, maybe switch current next frame */
1042  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1043  n_left_to_next, bi0, next0);
1044  }
1045  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1046  }
1047  vlib_node_increment_counter (vm, stats_node_index,
1048  NAT64_IN2OUT_ERROR_IN2OUT_PACKETS,
1049  pkts_processed);
1050  return frame->n_vectors;
1051 }
1052 
1053 static uword
1055  vlib_frame_t * frame)
1056 {
1057  return nat64_in2out_node_fn_inline (vm, node, frame, 0);
1058 }
1059 
1060 /* *INDENT-OFF* */
1062  .function = nat64_in2out_node_fn,
1063  .name = "nat64-in2out",
1064  .vector_size = sizeof (u32),
1065  .format_trace = format_nat64_in2out_trace,
1066  .type = VLIB_NODE_TYPE_INTERNAL,
1067  .n_errors = ARRAY_LEN (nat64_in2out_error_strings),
1068  .error_strings = nat64_in2out_error_strings,
1069  .n_next_nodes = NAT64_IN2OUT_N_NEXT,
1070  /* edit / add dispositions here */
1071  .next_nodes = {
1072  [NAT64_IN2OUT_NEXT_DROP] = "error-drop",
1073  [NAT64_IN2OUT_NEXT_IP4_LOOKUP] = "ip4-lookup",
1074  [NAT64_IN2OUT_NEXT_IP6_LOOKUP] = "ip6-lookup",
1075  [NAT64_IN2OUT_NEXT_SLOWPATH] = "nat64-in2out-slowpath",
1076  },
1077 };
1078 /* *INDENT-ON* */
1079 
1081 
1082 static uword
1084  vlib_frame_t * frame)
1085 {
1086  return nat64_in2out_node_fn_inline (vm, node, frame, 1);
1087 }
1088 
1089 /* *INDENT-OFF* */
1091  .function = nat64_in2out_slowpath_node_fn,
1092  .name = "nat64-in2out-slowpath",
1093  .vector_size = sizeof (u32),
1094  .format_trace = format_nat64_in2out_trace,
1095  .type = VLIB_NODE_TYPE_INTERNAL,
1096  .n_errors = ARRAY_LEN (nat64_in2out_error_strings),
1097  .error_strings = nat64_in2out_error_strings,
1098  .n_next_nodes = NAT64_IN2OUT_N_NEXT,
1099  /* edit / add dispositions here */
1100  .next_nodes = {
1101  [NAT64_IN2OUT_NEXT_DROP] = "error-drop",
1102  [NAT64_IN2OUT_NEXT_IP4_LOOKUP] = "ip4-lookup",
1103  [NAT64_IN2OUT_NEXT_IP6_LOOKUP] = "ip6-lookup",
1104  [NAT64_IN2OUT_NEXT_SLOWPATH] = "nat64-in2out-slowpath",
1105  },
1106 };
1107 /* *INDENT-ON* */
1108 
1111 
1112 /*
1113  * fd.io coding-style-patch-verification: ON
1114  *
1115  * Local Variables:
1116  * eval: (c-set-style "gnu")
1117  * End:
1118  */
static int unk_proto_st_walk(nat64_db_st_entry_t *ste, void *arg)
Definition: nat64_in2out.c:374
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:234
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:756
#define PREDICT_TRUE(x)
Definition: clib.h:98
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:48
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:340
nat64_in2out_next_t
Definition: nat64_in2out.c:71
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
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, u8 proto, u8 is_static)
Create new NAT64 BIB entry.
Definition: nat64_db.c:45
nat64_db_bib_entry_t * nat64_db_bib_entry_find(nat64_db_t *db, ip46_address_t *addr, u16 port, u8 proto, u32 fib_index, u8 is_ip6)
Find NAT64 BIB entry.
Definition: nat64_db.c:173
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:32
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:415
static int nat64_in2out_icmp_hairpinning(vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip6)
Definition: nat64_in2out.c:637
struct _tcp_header tcp_header_t
ip6_address_t src_address
Definition: ip6_packet.h:341
#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
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
struct unk_proto_st_walk_ctx_t_ unk_proto_st_walk_ctx_t
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:72
void nat64_session_reset_timeout(nat64_db_st_entry_t *ste, vlib_main_t *vm)
Reset NAT64 session timeout.
Definition: nat64.c:516
static uword nat64_in2out_slowpath_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
vlib_buffer_t * b
Definition: nat64_in2out.c:82
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:193
#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:283
static char * nat64_in2out_error_strings[]
Definition: nat64_in2out.c:65
#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:364
static int nat64_in2out_unk_proto_hairpinning(vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip6)
Definition: nat64_in2out.c:753
void nat64_compose_ip6(ip6_address_t *ip6, ip4_address_t *ip4, u32 fib_index)
Compose IPv4-embedded IPv6 addresses.
Definition: nat64.c:685
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:1158
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:198
u16 n_vectors
Definition: node.h:344
vlib_main_t * vm
Definition: buffer.c:283
static int nat64_in2out_tcp_udp_set_cb(ip6_header_t *ip6, ip4_header_t *ip4, void *arg)
Definition: nat64_in2out.c:112
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:93
vlib_node_registration_t nat64_in2out_slowpath_node
(constructor) VLIB_REGISTER_NODE (nat64_in2out_slowpath_node)
Definition: nat64_in2out.c:49
#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:512
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:454
nat64_main_t nat64_main
Definition: nat64.c:25
static void * ip6_next_header(ip6_header_t *i)
Definition: ip6_packet.h:351
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:456
#define u8_ptr_add(ptr, index)
Definition: map.h:513
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, u8 proto, u32 fib_index, u8 is_ip6)
Find NAT64 session table entry.
Definition: nat64_db.c:485
unsigned int u32
Definition: types.h:88
nat64_in2out_error_t
Definition: nat64_in2out.c:57
void nat64_db_st_walk(nat64_db_t *db, u8 proto, nat64_db_st_walk_fn_t fn, void *ctx)
Walk NAT64 session table.
Definition: nat64_db.c:289
long ctx[MAX_CONNS]
Definition: main.c:95
static u32 ip_proto_to_snat_proto(u8 ip_proto)
Definition: nat.h:429
static ip_csum_t ip_csum_sub_even(ip_csum_t c, ip_csum_t x)
Definition: ip_packet.h:117
nat64_db_bib_entry_t * nat64_db_bib_entry_by_index(nat64_db_t *db, u8 proto, u32 bibe_index)
Get BIB entry by index and protocol.
Definition: nat64_db.c:266
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
IPv6 to IPv4 translation.
ip4_address_t addr
Definition: nat.h:169
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 ip46_address_is_equal(a1, a2)
Definition: ip6_packet.h:82
#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:267
static uword nat64_in2out_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, u8 is_slow_path)
Definition: nat64_in2out.c:880
#define vnet_buffer(b)
Definition: buffer.h:306
static int nat64_in2out_unk_proto_set_cb(ip6_header_t *ip6, ip4_header_t *ip4, void *arg)
Definition: nat64_in2out.c:409
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
static_always_inline int is_hairpinning(ip6_address_t *dst_addr)
Check whether is a hairpinning.
Definition: nat64_in2out.c:97
static uword nat64_in2out_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
u16 flags
Copy of main node flags.
Definition: node.h:450
vhost_vring_addr_t addr
Definition: vhost-user.h:83
#define foreach_nat64_in2out_error
Definition: nat64_in2out.c:51
struct nat64_in2out_set_ctx_t_ nat64_in2out_set_ctx_t
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:75
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 int ip6_to_ip4(vlib_buffer_t *p, ip6_to_ip4_set_fn_t fn, void *ctx)
Translate IPv6 packet to IPv4 (IP header only).
Definition: ip6_to_ip4.h:575
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