FD.io VPP  v18.10-32-g1161dda
Vector Packet Processing
nat64_out2in.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 IPv4 to IPv6 translation (otside to inside network)
18  */
19 
20 #include <nat/nat64.h>
21 #include <nat/nat_reass.h>
22 #include <nat/nat_inlines.h>
23 #include <vnet/ip/ip4_to_ip6.h>
24 #include <vnet/fib/ip4_fib.h>
25 #include <vnet/udp/udp.h>
26 
27 typedef struct
28 {
32 
33 static u8 *
34 format_nat64_out2in_trace (u8 * s, va_list * args)
35 {
36  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
37  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
38  nat64_out2in_trace_t *t = va_arg (*args, nat64_out2in_trace_t *);
39 
40  s =
41  format (s, "NAT64-out2in: sw_if_index %d, next index %d", t->sw_if_index,
42  t->next_index);
43 
44  return s;
45 }
46 
47 typedef struct
48 {
53 
54 static u8 *
55 format_nat64_out2in_reass_trace (u8 * s, va_list * args)
56 {
57  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
58  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
60  va_arg (*args, nat64_out2in_reass_trace_t *);
61 
62  s =
63  format (s, "NAT64-out2in-reass: sw_if_index %d, next index %d, status %s",
64  t->sw_if_index, t->next_index,
65  t->cached ? "cached" : "translated");
66 
67  return s;
68 }
69 
73 
74 #define foreach_nat64_out2in_error \
75 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
76 _(OUT2IN_PACKETS, "Good out2in packets processed") \
77 _(NO_TRANSLATION, "No translation") \
78 _(UNKNOWN, "unknown") \
79 _(DROP_FRAGMENT, "Drop fragment") \
80 _(MAX_REASS, "Maximum reassemblies exceeded") \
81 _(MAX_FRAG, "Maximum fragments per reassembly exceeded")
82 
83 
84 typedef enum
85 {
86 #define _(sym,str) NAT64_OUT2IN_ERROR_##sym,
88 #undef _
91 
92 static char *nat64_out2in_error_strings[] = {
93 #define _(sym,string) string,
95 #undef _
96 };
97 
98 typedef enum
99 {
106 
108 {
113 
114 static int
116  void *arg)
117 {
118  nat64_main_t *nm = &nat64_main;
120  nat64_db_bib_entry_t *bibe;
121  nat64_db_st_entry_t *ste;
122  ip46_address_t saddr, daddr;
123  ip6_address_t ip6_saddr;
124  udp_header_t *udp = ip4_next_header (ip4);
125  tcp_header_t *tcp = ip4_next_header (ip4);
126  u8 proto = ip4->protocol;
127  u16 dport = udp->dst_port;
128  u16 sport = udp->src_port;
129  u32 sw_if_index, fib_index;
130  u16 *checksum;
131  ip_csum_t csum;
132  nat64_db_t *db = &nm->db[ctx->thread_index];
133 
134  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
135  fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
136 
137  memset (&saddr, 0, sizeof (saddr));
138  saddr.ip4.as_u32 = ip4->src_address.as_u32;
139  memset (&daddr, 0, sizeof (daddr));
140  daddr.ip4.as_u32 = ip4->dst_address.as_u32;
141 
142  ste =
143  nat64_db_st_entry_find (db, &daddr, &saddr, dport, sport, proto,
144  fib_index, 0);
145  if (ste)
146  {
147  bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
148  if (!bibe)
149  return -1;
150  }
151  else
152  {
153  bibe = nat64_db_bib_entry_find (db, &daddr, dport, proto, fib_index, 0);
154 
155  if (!bibe)
156  return -1;
157 
158  nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index);
159  ste =
160  nat64_db_st_entry_create (db, bibe, &ip6_saddr, &saddr.ip4, sport);
161  }
162 
163  ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
164  ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
165 
166  ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
167  ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
168  udp->dst_port = bibe->in_port;
169 
170  if (proto == IP_PROTOCOL_UDP)
171  checksum = &udp->checksum;
172  else
173  {
174  checksum = &tcp->checksum;
175  nat64_tcp_session_set_state (ste, tcp, 0);
176  }
177 
178  csum = ip_csum_sub_even (*checksum, dport);
179  csum = ip_csum_add_even (csum, udp->dst_port);
180  *checksum = ip_csum_fold (csum);
181 
182  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
183 
184  nat64_session_reset_timeout (ste, ctx->vm);
185 
186  return 0;
187 }
188 
189 static int
191 {
192  nat64_main_t *nm = &nat64_main;
194  nat64_db_bib_entry_t *bibe;
195  nat64_db_st_entry_t *ste;
196  ip46_address_t saddr, daddr;
197  ip6_address_t ip6_saddr;
198  u32 sw_if_index, fib_index;
199  icmp46_header_t *icmp = ip4_next_header (ip4);
200  nat64_db_t *db = &nm->db[ctx->thread_index];
201 
202  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
203  fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
204 
205  memset (&saddr, 0, sizeof (saddr));
206  saddr.ip4.as_u32 = ip4->src_address.as_u32;
207  memset (&daddr, 0, sizeof (daddr));
208  daddr.ip4.as_u32 = ip4->dst_address.as_u32;
209 
210  if (icmp->type == ICMP6_echo_request || icmp->type == ICMP6_echo_reply)
211  {
212  u16 out_id = ((u16 *) (icmp))[2];
213  ste =
214  nat64_db_st_entry_find (db, &daddr, &saddr, out_id, 0,
215  IP_PROTOCOL_ICMP, fib_index, 0);
216 
217  if (ste)
218  {
219  bibe =
220  nat64_db_bib_entry_by_index (db, IP_PROTOCOL_ICMP,
221  ste->bibe_index);
222  if (!bibe)
223  return -1;
224  }
225  else
226  {
227  bibe =
228  nat64_db_bib_entry_find (db, &daddr, out_id,
229  IP_PROTOCOL_ICMP, fib_index, 0);
230  if (!bibe)
231  return -1;
232 
233  nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index);
234  ste =
235  nat64_db_st_entry_create (db, bibe, &ip6_saddr, &saddr.ip4, 0);
236  }
237 
238  nat64_session_reset_timeout (ste, ctx->vm);
239 
240  ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
241  ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
242 
243  ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
244  ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
245  ((u16 *) (icmp))[2] = bibe->in_port;
246 
247  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
248  }
249  else
250  {
251  ip6_header_t *inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
252 
254  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX]);
255  ip6->dst_address.as_u64[0] = inner_ip6->src_address.as_u64[0];
256  ip6->dst_address.as_u64[1] = inner_ip6->src_address.as_u64[1];
257  }
258 
259  return 0;
260 }
261 
262 static int
264  void *arg)
265 {
266  nat64_main_t *nm = &nat64_main;
268  nat64_db_bib_entry_t *bibe;
269  nat64_db_st_entry_t *ste;
270  ip46_address_t saddr, daddr;
271  u32 sw_if_index, fib_index;
272  u8 proto = ip4->protocol;
273  nat64_db_t *db = &nm->db[ctx->thread_index];
274 
275  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
276  fib_index =
278 
279  memset (&saddr, 0, sizeof (saddr));
280  saddr.ip4.as_u32 = ip4->src_address.as_u32;
281  memset (&daddr, 0, sizeof (daddr));
282  daddr.ip4.as_u32 = ip4->dst_address.as_u32;
283 
284  if (proto == IP_PROTOCOL_ICMP6)
285  {
286  icmp46_header_t *icmp = ip4_next_header (ip4);
287  u16 out_id = ((u16 *) (icmp))[2];
288  proto = IP_PROTOCOL_ICMP;
289 
290  if (!
291  (icmp->type == ICMP6_echo_request
292  || icmp->type == ICMP6_echo_reply))
293  return -1;
294 
295  ste =
296  nat64_db_st_entry_find (db, &saddr, &daddr, out_id, 0, proto,
297  fib_index, 0);
298  if (!ste)
299  return -1;
300 
301  bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
302  if (!bibe)
303  return -1;
304 
305  ip6->dst_address.as_u64[0] = ste->in_r_addr.as_u64[0];
306  ip6->dst_address.as_u64[1] = ste->in_r_addr.as_u64[1];
307  ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
308  ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
309  ((u16 *) (icmp))[2] = bibe->in_port;
310 
311  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
312  }
313  else
314  {
315  udp_header_t *udp = ip4_next_header (ip4);
316  tcp_header_t *tcp = ip4_next_header (ip4);
317  u16 dport = udp->dst_port;
318  u16 sport = udp->src_port;
319  u16 *checksum;
320  ip_csum_t csum;
321 
322  ste =
323  nat64_db_st_entry_find (db, &saddr, &daddr, sport, dport, proto,
324  fib_index, 0);
325  if (!ste)
326  return -1;
327 
328  bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
329  if (!bibe)
330  return -1;
331 
332  nat64_compose_ip6 (&ip6->dst_address, &daddr.ip4, bibe->fib_index);
333  ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
334  ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
335  udp->src_port = bibe->in_port;
336 
337  if (proto == IP_PROTOCOL_UDP)
338  checksum = &udp->checksum;
339  else
340  checksum = &tcp->checksum;
341  if (*checksum)
342  {
343  csum = ip_csum_sub_even (*checksum, sport);
344  csum = ip_csum_add_even (csum, udp->src_port);
345  *checksum = ip_csum_fold (csum);
346  }
347 
348  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
349  }
350 
351  return 0;
352 }
353 
354 static int
356  void *arg)
357 {
358  nat64_main_t *nm = &nat64_main;
360  nat64_db_bib_entry_t *bibe;
361  nat64_db_st_entry_t *ste;
362  ip46_address_t saddr, daddr;
363  ip6_address_t ip6_saddr;
364  u32 sw_if_index, fib_index;
365  u8 proto = ip4->protocol;
366  nat64_db_t *db = &nm->db[ctx->thread_index];
367 
368  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
369  fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
370 
371  memset (&saddr, 0, sizeof (saddr));
372  saddr.ip4.as_u32 = ip4->src_address.as_u32;
373  memset (&daddr, 0, sizeof (daddr));
374  daddr.ip4.as_u32 = ip4->dst_address.as_u32;
375 
376  ste =
377  nat64_db_st_entry_find (db, &daddr, &saddr, 0, 0, proto, fib_index, 0);
378  if (ste)
379  {
380  bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
381  if (!bibe)
382  return -1;
383  }
384  else
385  {
386  bibe = nat64_db_bib_entry_find (db, &daddr, 0, proto, fib_index, 0);
387 
388  if (!bibe)
389  return -1;
390 
391  nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index);
392  ste = nat64_db_st_entry_create (db, bibe, &ip6_saddr, &saddr.ip4, 0);
393  }
394 
395  nat64_session_reset_timeout (ste, ctx->vm);
396 
397  ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
398  ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
399 
400  ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
401  ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
402 
403  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
404 
405  return 0;
406 }
407 
408 static uword
410  vlib_frame_t * frame)
411 {
412  u32 n_left_from, *from, *to_next;
413  nat64_out2in_next_t next_index;
414  u32 pkts_processed = 0;
416 
417  from = vlib_frame_vector_args (frame);
418  n_left_from = frame->n_vectors;
419  next_index = node->cached_next_index;
420  while (n_left_from > 0)
421  {
422  u32 n_left_to_next;
423 
424  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
425 
426  while (n_left_from > 0 && n_left_to_next > 0)
427  {
428  u32 bi0;
429  vlib_buffer_t *b0;
430  u32 next0;
431  ip4_header_t *ip40;
432  u32 proto0;
434  udp_header_t *udp0;
435 
436  /* speculatively enqueue b0 to the current next frame */
437  bi0 = from[0];
438  to_next[0] = bi0;
439  from += 1;
440  to_next += 1;
441  n_left_from -= 1;
442  n_left_to_next -= 1;
443 
444  b0 = vlib_get_buffer (vm, bi0);
445  ip40 = vlib_buffer_get_current (b0);
446 
447  ctx0.b = b0;
448  ctx0.vm = vm;
449  ctx0.thread_index = thread_index;
450 
452 
453  proto0 = ip_proto_to_snat_proto (ip40->protocol);
454 
455  if (PREDICT_FALSE (proto0 == ~0))
456  {
457  if (ip4_to_ip6 (b0, nat64_out2in_unk_proto_set_cb, &ctx0))
458  {
459  next0 = NAT64_OUT2IN_NEXT_DROP;
460  b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
461  }
462  goto trace0;
463  }
464 
465  if (PREDICT_FALSE (ip4_is_fragment (ip40)))
466  {
467  next0 = NAT64_OUT2IN_NEXT_REASS;
468  goto trace0;
469  }
470 
471  if (proto0 == SNAT_PROTOCOL_ICMP)
472  {
473  if (icmp_to_icmp6
474  (b0, nat64_out2in_icmp_set_cb, &ctx0,
476  {
477  next0 = NAT64_OUT2IN_NEXT_DROP;
478  b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
479  goto trace0;
480  }
481  }
482  else
483  {
485  {
486  udp0 = ip4_next_header (ip40);
487  /*
488  * Send DHCP packets to the ipv4 stack, or we won't
489  * be able to use dhcp client on the outside interface
490  */
491  if ((proto0 == SNAT_PROTOCOL_UDP)
492  && (udp0->dst_port ==
493  clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client)))
494  {
496  goto trace0;
497  }
498  next0 = NAT64_OUT2IN_NEXT_DROP;
499  b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
500  goto trace0;
501  }
502  }
503 
504  trace0:
506  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
507  {
509  vlib_add_trace (vm, node, b0, sizeof (*t));
510  t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
511  t->next_index = next0;
512  }
513 
514  pkts_processed += next0 != NAT64_OUT2IN_NEXT_DROP;
515 
516  /* verify speculative enqueue, maybe switch current next frame */
517  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
518  n_left_to_next, bi0, next0);
519  }
520  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
521  }
523  NAT64_OUT2IN_ERROR_OUT2IN_PACKETS,
524  pkts_processed);
525  return frame->n_vectors;
526 }
527 
528 /* *INDENT-OFF* */
530  .function = nat64_out2in_node_fn,
531  .name = "nat64-out2in",
532  .vector_size = sizeof (u32),
533  .format_trace = format_nat64_out2in_trace,
534  .type = VLIB_NODE_TYPE_INTERNAL,
536  .error_strings = nat64_out2in_error_strings,
537  .n_next_nodes = NAT64_OUT2IN_N_NEXT,
538  /* edit / add dispositions here */
539  .next_nodes = {
540  [NAT64_OUT2IN_NEXT_DROP] = "error-drop",
541  [NAT64_OUT2IN_NEXT_IP6_LOOKUP] = "ip6-lookup",
542  [NAT64_OUT2IN_NEXT_IP4_LOOKUP] = "ip4-lookup",
543  [NAT64_OUT2IN_NEXT_REASS] = "nat64-out2in-reass",
544  },
545 };
546 /* *INDENT-ON* */
547 
549 
551 {
559 
560 static int
562 {
563  nat64_main_t *nm = &nat64_main;
565  nat64_db_st_entry_t *ste;
566  nat64_db_bib_entry_t *bibe;
567  udp_header_t *udp = ip4_next_header (ip4);
568  ip_csum_t csum;
569  u16 *checksum;
570  nat64_db_t *db = &nm->db[ctx->thread_index];
571 
572  ste = nat64_db_st_entry_by_index (db, ctx->proto, ctx->sess_index);
573  if (!ste)
574  return -1;
575 
576  bibe = nat64_db_bib_entry_by_index (db, ctx->proto, ste->bibe_index);
577  if (!bibe)
578  return -1;
579 
580  if (ctx->first_frag)
581  {
582  udp->dst_port = bibe->in_port;
583 
584  if (ip4->protocol == IP_PROTOCOL_UDP)
585  {
586  checksum = &udp->checksum;
587 
588  if (!checksum)
589  {
590  u16 udp_len =
591  clib_host_to_net_u16 (ip4->length) - sizeof (*ip4);
592  csum = ip_incremental_checksum (0, udp, udp_len);
593  csum =
594  ip_csum_with_carry (csum, clib_host_to_net_u16 (udp_len));
595  csum =
596  ip_csum_with_carry (csum,
597  clib_host_to_net_u16 (IP_PROTOCOL_UDP));
598  csum = ip_csum_with_carry (csum, ste->in_r_addr.as_u64[0]);
599  csum = ip_csum_with_carry (csum, ste->in_r_addr.as_u64[1]);
600  csum = ip_csum_with_carry (csum, bibe->in_addr.as_u64[0]);
601  csum = ip_csum_with_carry (csum, bibe->in_addr.as_u64[1]);
602  *checksum = ~ip_csum_fold (csum);
603  }
604  else
605  {
606  csum = ip_csum_sub_even (*checksum, bibe->out_addr.as_u32);
607  csum = ip_csum_sub_even (csum, ste->out_r_addr.as_u32);
608  csum = ip_csum_sub_even (csum, bibe->out_port);
609  csum = ip_csum_add_even (csum, ste->in_r_addr.as_u64[0]);
610  csum = ip_csum_add_even (csum, ste->in_r_addr.as_u64[1]);
611  csum = ip_csum_add_even (csum, bibe->in_addr.as_u64[0]);
612  csum = ip_csum_add_even (csum, bibe->in_addr.as_u64[1]);
613  csum = ip_csum_add_even (csum, bibe->in_port);
614  *checksum = ip_csum_fold (csum);
615  }
616  }
617  else
618  {
619  tcp_header_t *tcp = ip4_next_header (ip4);
620  nat64_tcp_session_set_state (ste, tcp, 0);
621  checksum = &tcp->checksum;
622  csum = ip_csum_sub_even (*checksum, bibe->out_addr.as_u32);
623  csum = ip_csum_sub_even (csum, ste->out_r_addr.as_u32);
624  csum = ip_csum_sub_even (csum, bibe->out_port);
625  csum = ip_csum_add_even (csum, ste->in_r_addr.as_u64[0]);
626  csum = ip_csum_add_even (csum, ste->in_r_addr.as_u64[1]);
627  csum = ip_csum_add_even (csum, bibe->in_addr.as_u64[0]);
628  csum = ip_csum_add_even (csum, bibe->in_addr.as_u64[1]);
629  csum = ip_csum_add_even (csum, bibe->in_port);
630  *checksum = ip_csum_fold (csum);
631  }
632 
633  }
634 
635  ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
636  ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
637 
638  ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
639  ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
640 
641  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
642 
643  nat64_session_reset_timeout (ste, ctx->vm);
644 
645  return 0;
646 }
647 
648 static uword
650  vlib_frame_t * frame)
651 {
652  u32 n_left_from, *from, *to_next;
653  nat64_out2in_next_t next_index;
654  u32 pkts_processed = 0;
655  u32 *fragments_to_drop = 0;
656  u32 *fragments_to_loopback = 0;
657  nat64_main_t *nm = &nat64_main;
659 
660  from = vlib_frame_vector_args (frame);
661  n_left_from = frame->n_vectors;
662  next_index = node->cached_next_index;
663 
664  while (n_left_from > 0)
665  {
666  u32 n_left_to_next;
667 
668  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
669 
670  while (n_left_from > 0 && n_left_to_next > 0)
671  {
672  u32 bi0;
673  vlib_buffer_t *b0;
674  u32 next0;
675  ip4_header_t *ip40;
676  u8 cached0 = 0;
677  u32 sw_if_index0, fib_index0;
678  udp_header_t *udp0;
679  nat_reass_ip4_t *reass0;
680  ip46_address_t saddr0, daddr0;
681  nat64_db_st_entry_t *ste0;
682  nat64_db_bib_entry_t *bibe0;
683  ip6_address_t ip6_saddr0;
685  nat64_db_t *db = &nm->db[thread_index];
686 
687  /* speculatively enqueue b0 to the current next frame */
688  bi0 = from[0];
689  to_next[0] = bi0;
690  from += 1;
691  to_next += 1;
692  n_left_from -= 1;
693  n_left_to_next -= 1;
694 
695  b0 = vlib_get_buffer (vm, bi0);
697 
698  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
699  fib_index0 =
701  sw_if_index0);
702 
703  ctx0.thread_index = thread_index;
704 
706  {
707  next0 = NAT64_OUT2IN_NEXT_DROP;
708  b0->error = node->errors[NAT64_OUT2IN_ERROR_DROP_FRAGMENT];
709  goto trace0;
710  }
711 
712  ip40 = vlib_buffer_get_current (b0);
713 
714  if (PREDICT_FALSE (!(ip40->protocol == IP_PROTOCOL_TCP
715  || ip40->protocol == IP_PROTOCOL_UDP)))
716  {
717  next0 = NAT64_OUT2IN_NEXT_DROP;
718  b0->error = node->errors[NAT64_OUT2IN_ERROR_DROP_FRAGMENT];
719  goto trace0;
720  }
721 
722  udp0 = ip4_next_header (ip40);
723 
725  ip40->dst_address,
726  ip40->fragment_id,
727  ip40->protocol,
728  1, &fragments_to_drop);
729 
730  if (PREDICT_FALSE (!reass0))
731  {
732  next0 = NAT64_OUT2IN_NEXT_DROP;
733  b0->error = node->errors[NAT64_OUT2IN_ERROR_MAX_REASS];
734  goto trace0;
735  }
736 
738  {
739  ctx0.first_frag = 1;
740 
741  memset (&saddr0, 0, sizeof (saddr0));
742  saddr0.ip4.as_u32 = ip40->src_address.as_u32;
743  memset (&daddr0, 0, sizeof (daddr0));
744  daddr0.ip4.as_u32 = ip40->dst_address.as_u32;
745 
746  ste0 =
747  nat64_db_st_entry_find (db, &daddr0, &saddr0,
748  udp0->dst_port, udp0->src_port,
749  ip40->protocol, fib_index0, 0);
750  if (!ste0)
751  {
752  bibe0 =
753  nat64_db_bib_entry_find (db, &daddr0, udp0->dst_port,
754  ip40->protocol, fib_index0, 0);
755  if (!bibe0)
756  {
757  next0 = NAT64_OUT2IN_NEXT_DROP;
758  b0->error =
759  node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
760  goto trace0;
761  }
762 
763  nat64_compose_ip6 (&ip6_saddr0, &ip40->src_address,
764  bibe0->fib_index);
765  ste0 =
766  nat64_db_st_entry_create (db, bibe0, &ip6_saddr0,
767  &saddr0.ip4, udp0->src_port);
768 
769  if (!ste0)
770  {
771  next0 = NAT64_OUT2IN_NEXT_DROP;
772  b0->error =
773  node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
774  goto trace0;
775  }
776  }
777  reass0->sess_index = nat64_db_st_entry_get_index (db, ste0);
778  reass0->thread_index = thread_index;
779 
780  nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
781  }
782  else
783  {
784  ctx0.first_frag = 0;
785 
786  if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
787  {
789  (reass0, bi0, &fragments_to_drop))
790  {
791  b0->error = node->errors[NAT64_OUT2IN_ERROR_MAX_FRAG];
792  next0 = NAT64_OUT2IN_NEXT_DROP;
793  goto trace0;
794  }
795  cached0 = 1;
796  goto trace0;
797  }
798  }
799 
800  ctx0.sess_index = reass0->sess_index;
801  ctx0.proto = ip40->protocol;
802  ctx0.vm = vm;
803  ctx0.b = b0;
804 
806  {
807  next0 = NAT64_OUT2IN_NEXT_DROP;
808  b0->error = node->errors[NAT64_OUT2IN_ERROR_UNKNOWN];
809  goto trace0;
810  }
811 
812  trace0:
813  if (PREDICT_FALSE
814  ((node->flags & VLIB_NODE_FLAG_TRACE)
815  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
816  {
818  vlib_add_trace (vm, node, b0, sizeof (*t));
819  t->cached = cached0;
820  t->sw_if_index = sw_if_index0;
821  t->next_index = next0;
822  }
823 
824  if (cached0)
825  {
826  n_left_to_next++;
827  to_next--;
828  }
829  else
830  {
831  pkts_processed += next0 != NAT64_OUT2IN_NEXT_DROP;
832 
833  /* verify speculative enqueue, maybe switch current next frame */
834  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
835  to_next, n_left_to_next,
836  bi0, next0);
837  }
838 
839  if (n_left_from == 0 && vec_len (fragments_to_loopback))
840  {
841  from = vlib_frame_vector_args (frame);
842  u32 len = vec_len (fragments_to_loopback);
843  if (len <= VLIB_FRAME_SIZE)
844  {
845  clib_memcpy (from, fragments_to_loopback,
846  sizeof (u32) * len);
847  n_left_from = len;
848  vec_reset_length (fragments_to_loopback);
849  }
850  else
851  {
852  clib_memcpy (from,
853  fragments_to_loopback + (len -
855  sizeof (u32) * VLIB_FRAME_SIZE);
856  n_left_from = VLIB_FRAME_SIZE;
857  _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
858  }
859  }
860  }
861 
862  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
863  }
864 
866  NAT64_OUT2IN_ERROR_OUT2IN_PACKETS,
867  pkts_processed);
868 
869  nat_send_all_to_node (vm, fragments_to_drop, node,
870  &node->errors[NAT64_OUT2IN_ERROR_DROP_FRAGMENT],
872 
873  vec_free (fragments_to_drop);
874  vec_free (fragments_to_loopback);
875  return frame->n_vectors;
876 }
877 
878 /* *INDENT-OFF* */
880  .function = nat64_out2in_reass_node_fn,
881  .name = "nat64-out2in-reass",
882  .vector_size = sizeof (u32),
883  .format_trace = format_nat64_out2in_reass_trace,
884  .type = VLIB_NODE_TYPE_INTERNAL,
886  .error_strings = nat64_out2in_error_strings,
887  .n_next_nodes = NAT64_OUT2IN_N_NEXT,
888  /* edit / add dispositions here */
889  .next_nodes = {
890  [NAT64_OUT2IN_NEXT_DROP] = "error-drop",
891  [NAT64_OUT2IN_NEXT_IP6_LOOKUP] = "ip6-lookup",
892  [NAT64_OUT2IN_NEXT_IP4_LOOKUP] = "ip4-lookup",
893  [NAT64_OUT2IN_NEXT_REASS] = "nat64-out2in-reass",
894  },
895 };
896 /* *INDENT-ON* */
897 
900 
901 #define foreach_nat64_out2in_handoff_error \
902 _(CONGESTION_DROP, "congestion drop")
903 
904 typedef enum
905 {
906 #define _(sym,str) NAT64_OUT2IN_HANDOFF_ERROR_##sym,
908 #undef _
911 
913 #define _(sym,string) string,
915 #undef _
916 };
917 
918 typedef struct
919 {
922 
923 static u8 *
925 {
926  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
927  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
929  va_arg (*args, nat64_out2in_handoff_trace_t *);
930 
931  s =
932  format (s, "NAT64-OUT2IN-HANDOFF: next-worker %d", t->next_worker_index);
933 
934  return s;
935 }
936 
937 static inline uword
939  vlib_frame_t * frame)
940 {
941  nat64_main_t *nm = &nat64_main;
942  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
943  u32 n_enq, n_left_from, *from;
944  u16 thread_indices[VLIB_FRAME_SIZE], *ti;
945  u32 fq_index;
946 
947  from = vlib_frame_vector_args (frame);
948  n_left_from = frame->n_vectors;
949  vlib_get_buffers (vm, from, bufs, n_left_from);
950 
951  b = bufs;
952  ti = thread_indices;
953 
954  fq_index = nm->fq_out2in_index;
955 
956  while (n_left_from > 0)
957  {
958  ip4_header_t *ip0;
959 
960  ip0 = vlib_buffer_get_current (b[0]);
961  ti[0] = nat64_get_worker_out2in (ip0);
962 
963  if (PREDICT_FALSE
964  ((node->flags & VLIB_NODE_FLAG_TRACE)
965  && (b[0]->flags & VLIB_BUFFER_IS_TRACED)))
966  {
968  vlib_add_trace (vm, node, b[0], sizeof (*t));
969  t->next_worker_index = ti[0];
970  }
971 
972  n_left_from -= 1;
973  ti += 1;
974  b += 1;
975  }
976 
977  n_enq =
978  vlib_buffer_enqueue_to_thread (vm, fq_index, from, thread_indices,
979  frame->n_vectors, 1);
980 
981  if (n_enq < frame->n_vectors)
983  NAT64_OUT2IN_HANDOFF_ERROR_CONGESTION_DROP,
984  frame->n_vectors - n_enq);
985  return frame->n_vectors;
986 }
987 
988 /* *INDENT-OFF* */
990  .function = nat64_out2in_handoff_node_fn,
991  .name = "nat64-out2in-handoff",
992  .vector_size = sizeof (u32),
993  .format_trace = format_nat64_out2in_handoff_trace,
994  .type = VLIB_NODE_TYPE_INTERNAL,
996  .error_strings = nat64_out2in_handoff_error_strings,
997 
998  .n_next_nodes = 1,
999 
1000  .next_nodes = {
1001  [0] = "error-drop",
1002  },
1003 };
1004 /* *INDENT-ON* */
1005 
1008 /*
1009  * fd.io coding-style-patch-verification: ON
1010  *
1011  * Local Variables:
1012  * eval: (c-set-style "gnu")
1013  * End:
1014  */
nat64_out2in_handoff_error_t
Definition: nat64_out2in.c:904
nat64_db_t * db
BIB and session DB per thread.
Definition: nat64.h:83
#define CLIB_UNUSED(x)
Definition: clib.h:81
static char * nat64_out2in_error_strings[]
Definition: nat64_out2in.c:92
ip4_address_t src_address
Definition: ip4_packet.h:169
struct nat64_out2in_frag_set_ctx_t_ nat64_out2in_frag_set_ctx_t
u64 as_u64[2]
Definition: ip6_packet.h:51
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:372
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:956
nat64_out2in_error_t
Definition: nat64_out2in.c:84
u32 thread_index
Definition: main.h:179
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:205
nat64_out2in_next_t
Definition: nat64_out2in.c:98
uword ip_csum_t
Definition: ip_packet.h:181
static ip_csum_t ip_csum_with_carry(ip_csum_t sum, ip_csum_t x)
Definition: ip_packet.h:184
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
static int nat64_out2in_tcp_udp_set_cb(ip4_header_t *ip4, ip6_header_t *ip6, void *arg)
Definition: nat64_out2in.c:115
nat64_db_st_entry_t * nat64_db_st_entry_by_index(nat64_db_t *db, u8 proto, u32 ste_index)
Get ST entry by index and protocol.
Definition: nat64_db.c:615
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:472
static u8 * format_nat64_out2in_reass_trace(u8 *s, va_list *args)
Definition: nat64_out2in.c:55
vlib_node_registration_t nat64_out2in_reass_node
(constructor) VLIB_REGISTER_NODE (nat64_out2in_reass_node)
Definition: nat64_out2in.c:71
struct _tcp_header tcp_header_t
ip6_address_t src_address
Definition: ip6_packet.h:378
struct nat64_out2in_set_ctx_t_ nat64_out2in_set_ctx_t
unsigned char u8
Definition: types.h:56
IPv4 to IPv6 translation.
vlib_node_registration_t nat64_out2in_handoff_node
(constructor) VLIB_REGISTER_NODE (nat64_out2in_handoff_node)
Definition: nat64_out2in.c:72
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
static int ip4_is_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:212
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:224
memset(h->entries, 0, sizeof(h->entries[0])*entries)
u32 sw_if_index
Definition: vxlan_gbp.api:39
ip4_address_t dst_address
Definition: ip4_packet.h:169
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:240
unsigned int u32
Definition: types.h:88
void nat64_tcp_session_set_state(nat64_db_st_entry_t *ste, tcp_header_t *tcp, u8 is_ip6)
Set NAT64 TCP session state.
Definition: nat64.c:867
#define VLIB_FRAME_SIZE
Definition: node.h:382
u32 nat64_get_worker_out2in(ip4_header_t *ip)
Get worker thread index for NAT64 out2in.
Definition: nat64.c:121
void nat64_session_reset_timeout(nat64_db_st_entry_t *ste, vlib_main_t *vm)
Reset NAT64 session timeout.
Definition: nat64.c:828
long ctx[MAX_CONNS]
Definition: main.c:144
#define foreach_nat64_out2in_handoff_error
Definition: nat64_out2in.c:901
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:205
static char * nat64_out2in_handoff_error_strings[]
Definition: nat64_out2in.c:912
static int nat64_out2in_icmp_set_cb(ip4_header_t *ip4, ip6_header_t *ip6, void *arg)
Definition: nat64_out2in.c:190
static u8 * format_nat64_out2in_trace(u8 *s, va_list *args)
Definition: nat64_out2in.c:34
#define PREDICT_FALSE(x)
Definition: clib.h:107
u32 node_index
Node index.
Definition: node.h:494
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:364
void nat64_compose_ip6(ip6_address_t *ip6, ip4_address_t *ip4, u32 fib_index)
Compose IPv4-embedded IPv6 addresses.
Definition: nat64.c:997
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:138
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1176
static uword nat64_out2in_handoff_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nat64_out2in.c:938
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:155
u16 n_vectors
Definition: node.h:401
static u8 * format_nat64_out2in_handoff_trace(u8 *s, va_list *args)
Definition: nat64_out2in.c:924
u8 nat_reass_is_drop_frag(u8 is_ip6)
Get status of virtual fragmentation reassembly.
Definition: nat_reass.c:168
vlib_main_t * vm
Definition: buffer.c:294
static int ip4_to_ip6_tcp_udp(vlib_buffer_t *p, ip4_to_ip6_set_fn_t fn, void *ctx)
Translate IPv4 UDP/TCP packet to IPv6.
Definition: ip4_to_ip6.h:501
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
static ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_packet.h:254
#define clib_memcpy(a, b, c)
Definition: string.h:75
static int nat64_out2in_frag_set_cb(ip4_header_t *ip4, ip6_header_t *ip6, void *arg)
Definition: nat64_out2in.c:561
#define ARRAY_LEN(x)
Definition: clib.h:61
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:455
static int nat64_out2in_inner_icmp_set_cb(ip4_header_t *ip4, ip6_header_t *ip6, void *arg)
Definition: nat64_out2in.c:263
nat64_main_t nat64_main
Definition: nat64.c:28
u32 fq_out2in_index
Definition: nat64.h:87
static uword nat64_out2in_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nat64_out2in.c:409
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.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:544
VLIB_NODE_FUNCTION_MULTIARCH(nat64_out2in_node, nat64_out2in_node_fn)
static uword nat64_out2in_reass_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nat64_out2in.c:649
u32 nat64_db_st_entry_get_index(nat64_db_t *db, nat64_db_st_entry_t *ste)
Definition: nat64_db.c:592
static ip_csum_t ip_csum_sub_even(ip_csum_t c, ip_csum_t x)
Definition: ip_packet.h:209
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:298
static int icmp_to_icmp6(vlib_buffer_t *p, ip4_to_ip6_set_fn_t fn, void *ctx, ip4_to_ip6_set_fn_t inner_fn, void *inner_ctx)
Translate ICMP4 packet to ICMP6.
Definition: ip4_to_ip6.h:220
vlib_node_registration_t nat64_out2in_node
(constructor) VLIB_REGISTER_NODE (nat64_out2in_node)
Definition: nat64_out2in.c:70
#define u8_ptr_add(ptr, index)
Definition: ip.h:68
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:57
struct _vlib_node_registration vlib_node_registration_t
static int nat64_out2in_unk_proto_set_cb(ip4_header_t *ip4, ip6_header_t *ip6, void *arg)
Definition: nat64_out2in.c:355
NAT64 global declarations.
Definition: defs.h:47
static int ip4_is_first_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:219
static u32 ip_proto_to_snat_proto(u8 ip_proto)
The NAT inline functions.
Definition: nat_inlines.h:26
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
static int ip4_to_ip6_fragmented(vlib_buffer_t *p, ip4_to_ip6_set_fn_t fn, void *ctx)
Translate IPv4 fragmented packet to IPv6.
Definition: ip4_to_ip6.h:450
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
nat_reass_ip4_t * nat_ip4_reass_find_or_create(ip4_address_t src, ip4_address_t dst, u16 frag_id, u8 proto, u8 reset_timeout, u32 **bi_to_drop)
Find or create reassembly.
Definition: nat_reass.c:220
static_always_inline u32 vlib_buffer_enqueue_to_thread(vlib_main_t *vm, u32 frame_queue_index, u32 *buffer_indices, u16 *thread_indices, u32 n_packets, int drop_on_congestion)
Definition: buffer_node.h:452
static int ip4_to_ip6(vlib_buffer_t *p, ip4_to_ip6_set_fn_t fn, void *ctx)
Translate IPv4 packet to IPv6 (IP header only).
Definition: ip4_to_ip6.h:601
#define vnet_buffer(b)
Definition: buffer.h:344
int nat_ip4_reass_add_fragment(nat_reass_ip4_t *reass, u32 bi, u32 **bi_to_drop)
Cache fragment.
Definition: nat_reass.c:338
u16 flags
Copy of main node flags.
Definition: node.h:507
static void nat_send_all_to_node(vlib_main_t *vm, u32 *bi_vector, vlib_node_runtime_t *node, vlib_error_t *error, u32 next)
Definition: nat_inlines.h:104
void nat_ip4_reass_get_frags(nat_reass_ip4_t *reass, u32 **bi)
Get cached fragments.
Definition: nat_reass.c:370
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:141
NAT plugin virtual fragmentation reassembly.
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:310
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:116
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:58
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:237
Definition: defs.h:46
#define foreach_nat64_out2in_error
Definition: nat64_out2in.c:74
static ip_csum_t ip_csum_add_even(ip_csum_t c, ip_csum_t x)
Definition: ip_packet.h:192
ip6_address_t dst_address
Definition: ip6_packet.h:378