FD.io VPP  v21.01.1
Vector Packet Processing
nat64_out2in.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <nat/nat64/nat64.h>
17 #include <vnet/ip/ip4_to_ip6.h>
18 #include <vnet/fib/ip4_fib.h>
19 #include <vnet/udp/udp_local.h>
20 
21 typedef struct
22 {
26 
27 static u8 *
28 format_nat64_out2in_trace (u8 * s, va_list * args)
29 {
30  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
31  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
32  nat64_out2in_trace_t *t = va_arg (*args, nat64_out2in_trace_t *);
33 
34  s =
35  format (s, "NAT64-out2in: sw_if_index %d, next index %d", t->sw_if_index,
36  t->next_index);
37 
38  return s;
39 }
40 
41 #define foreach_nat64_out2in_error \
42 _(UNSUPPORTED_PROTOCOL, "unsupported protocol") \
43 _(NO_TRANSLATION, "no translation") \
44 _(UNKNOWN, "unknown")
45 
46 typedef enum
47 {
48 #define _(sym,str) NAT64_OUT2IN_ERROR_##sym,
50 #undef _
53 
54 static char *nat64_out2in_error_strings[] = {
55 #define _(sym,string) string,
57 #undef _
58 };
59 
60 typedef enum
61 {
67 
69 {
74 
75 static int
78 {
81  ip_csum_t csum;
82  u16 *checksum = NULL;
83  ip6_frag_hdr_t *frag;
84  u32 frag_id;
85  ip4_address_t old_src, old_dst;
86 
87  nat64_main_t *nm = &nat64_main;
88  nat64_db_bib_entry_t *bibe;
89  nat64_db_st_entry_t *ste;
90  ip46_address_t saddr;
91  ip46_address_t daddr;
92  ip6_address_t ip6_saddr;
93  u8 proto = vnet_buffer (b)->ip.reass.ip_proto;
94  u16 dport = vnet_buffer (b)->ip.reass.l4_dst_port;
95  u16 sport = vnet_buffer (b)->ip.reass.l4_src_port;
96  u32 sw_if_index, fib_index;
97  nat64_db_t *db = &nm->db[ctx->thread_index];
98 
99  ip4 = vlib_buffer_get_current (b);
100 
101  udp_header_t *udp = ip4_next_header (ip4);
102  tcp_header_t *tcp = ip4_next_header (ip4);
103  if (!vnet_buffer (b)->ip.reass.is_non_first_fragment)
104  {
105  if (ip4->protocol == IP_PROTOCOL_UDP)
106  {
107  checksum = &udp->checksum;
108  //UDP checksum is optional over IPv4 but mandatory for IPv6
109  //We do not check udp->length sanity but use our safe computed value instead
110  if (PREDICT_FALSE (!*checksum))
111  {
112  u16 udp_len =
113  clib_host_to_net_u16 (ip4->length) - sizeof (*ip4);
114  csum = ip_incremental_checksum (0, udp, udp_len);
115  csum =
116  ip_csum_with_carry (csum, clib_host_to_net_u16 (udp_len));
117  csum =
118  ip_csum_with_carry (csum,
119  clib_host_to_net_u16 (IP_PROTOCOL_UDP));
120  csum =
121  ip_csum_with_carry (csum, *((u64 *) (&ip4->src_address)));
122  *checksum = ~ip_csum_fold (csum);
123  }
124  }
125  else
126  {
127  checksum = &tcp->checksum;
128  }
129  }
130 
131  old_src.as_u32 = ip4->src_address.as_u32;
132  old_dst.as_u32 = ip4->dst_address.as_u32;
133 
134  // Deal with fragmented packets
135  u16 frag_offset = ip4_get_fragment_offset (ip4);
136  if (PREDICT_FALSE (ip4_get_fragment_more (ip4) || frag_offset))
137  {
138  ip6 =
139  (ip6_header_t *) u8_ptr_add (ip4,
140  sizeof (*ip4) - sizeof (*ip6) -
141  sizeof (*frag));
142  frag =
143  (ip6_frag_hdr_t *) u8_ptr_add (ip4, sizeof (*ip4) - sizeof (*frag));
144  frag_id = frag_id_4to6 (ip4->fragment_id);
145  vlib_buffer_advance (b, sizeof (*ip4) - sizeof (*ip6) - sizeof (*frag));
146  }
147  else
148  {
149  ip6 = (ip6_header_t *) (((u8 *) ip4) + sizeof (*ip4) - sizeof (*ip6));
150  vlib_buffer_advance (b, sizeof (*ip4) - sizeof (*ip6));
151  frag = NULL;
152  }
153 
155  clib_host_to_net_u32 ((6 << 28) + (ip4->tos << 20));
156  ip6->payload_length = u16_net_add (ip4->length, -sizeof (*ip4));
157  ip6->hop_limit = ip4->ttl;
158  ip6->protocol = ip4->protocol;
159 
160  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
161  fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
162 
163  clib_memset (&saddr, 0, sizeof (saddr));
164  saddr.ip4.as_u32 = ip4->src_address.as_u32;
165  clib_memset (&daddr, 0, sizeof (daddr));
166  daddr.ip4.as_u32 = ip4->dst_address.as_u32;
167 
168  ste =
169  nat64_db_st_entry_find (db, &daddr, &saddr, dport, sport, proto,
170  fib_index, 0);
171  if (ste)
172  {
173  bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
174  if (!bibe)
175  return -1;
176  }
177  else
178  {
179  bibe = nat64_db_bib_entry_find (db, &daddr, dport, proto, fib_index, 0);
180 
181  if (!bibe)
182  return -1;
183 
184  nat64_compose_ip6 (&ip6_saddr, &old_src, bibe->fib_index);
185  ste =
186  nat64_db_st_entry_create (ctx->thread_index, db, bibe, &ip6_saddr,
187  &saddr.ip4, sport);
188 
189  if (!ste)
190  return -1;
191 
193  db->st.st_entries_num);
194  }
195 
196  ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
197  ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
198 
199  ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
200  ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
201 
202  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
203 
204  nat64_session_reset_timeout (ste, ctx->vm);
205 
206  if (PREDICT_FALSE (frag != NULL))
207  {
208  frag->next_hdr = ip6->protocol;
209  frag->identification = frag_id;
210  frag->rsv = 0;
211  frag->fragment_offset_and_more =
212  ip6_frag_hdr_offset_and_more (frag_offset, 1);
213  ip6->protocol = IP_PROTOCOL_IPV6_FRAGMENTATION;
214  ip6->payload_length = u16_net_add (ip6->payload_length, sizeof (*frag));
215  }
216 
217  if (!vnet_buffer (b)->ip.reass.is_non_first_fragment)
218  {
219  udp->dst_port = bibe->in_port;
220 
221  if (proto == IP_PROTOCOL_TCP)
222  {
223  nat64_tcp_session_set_state (ste, tcp, 0);
224  }
225 
226  csum = ip_csum_sub_even (*checksum, dport);
227  csum = ip_csum_add_even (csum, udp->dst_port);
228  csum = ip_csum_sub_even (csum, old_src.as_u32);
229  csum = ip_csum_sub_even (csum, old_dst.as_u32);
230  csum = ip_csum_add_even (csum, ip6->src_address.as_u64[0]);
231  csum = ip_csum_add_even (csum, ip6->src_address.as_u64[1]);
232  csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[0]);
233  csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[1]);
234  *checksum = ip_csum_fold (csum);
235  }
236 
237  return 0;
238 }
239 
240 static int
242  ip6_header_t * ip6, void *arg)
243 {
244  nat64_main_t *nm = &nat64_main;
246  nat64_db_bib_entry_t *bibe;
247  nat64_db_st_entry_t *ste;
248  ip46_address_t saddr, daddr;
249  ip6_address_t ip6_saddr;
250  u32 sw_if_index, fib_index;
251  icmp46_header_t *icmp = ip4_next_header (ip4);
252  nat64_db_t *db = &nm->db[ctx->thread_index];
253 
254  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
255  fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
256 
257  clib_memset (&saddr, 0, sizeof (saddr));
258  saddr.ip4.as_u32 = ip4->src_address.as_u32;
259  clib_memset (&daddr, 0, sizeof (daddr));
260  daddr.ip4.as_u32 = ip4->dst_address.as_u32;
261 
262  if (icmp->type == ICMP6_echo_request || icmp->type == ICMP6_echo_reply)
263  {
264  u16 out_id = ((u16 *) (icmp))[2];
265  ste =
266  nat64_db_st_entry_find (db, &daddr, &saddr, out_id, 0,
267  IP_PROTOCOL_ICMP, fib_index, 0);
268 
269  if (ste)
270  {
271  bibe =
272  nat64_db_bib_entry_by_index (db, IP_PROTOCOL_ICMP,
273  ste->bibe_index);
274  if (!bibe)
275  return -1;
276  }
277  else
278  {
279  bibe =
280  nat64_db_bib_entry_find (db, &daddr, out_id,
281  IP_PROTOCOL_ICMP, fib_index, 0);
282  if (!bibe)
283  return -1;
284 
285  nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index);
286  ste =
288  bibe, &ip6_saddr, &saddr.ip4, 0);
289 
290  if (!ste)
291  return -1;
292 
294  db->st.st_entries_num);
295  }
296 
297  nat64_session_reset_timeout (ste, ctx->vm);
298 
299  ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
300  ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
301 
302  ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
303  ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
304  ((u16 *) (icmp))[2] = bibe->in_port;
305 
306  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
307  }
308  else
309  {
310  ip6_header_t *inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
311 
313  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX]);
314  ip6->dst_address.as_u64[0] = inner_ip6->src_address.as_u64[0];
315  ip6->dst_address.as_u64[1] = inner_ip6->src_address.as_u64[1];
316  }
317 
318  return 0;
319 }
320 
321 static int
323  ip6_header_t * ip6, void *arg)
324 {
325  nat64_main_t *nm = &nat64_main;
327  nat64_db_bib_entry_t *bibe;
328  nat64_db_st_entry_t *ste;
329  ip46_address_t saddr, daddr;
330  u32 sw_if_index, fib_index;
331  u8 proto = ip4->protocol;
332  nat64_db_t *db = &nm->db[ctx->thread_index];
333 
334  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
335  fib_index =
337 
338  clib_memset (&saddr, 0, sizeof (saddr));
339  saddr.ip4.as_u32 = ip4->src_address.as_u32;
340  clib_memset (&daddr, 0, sizeof (daddr));
341  daddr.ip4.as_u32 = ip4->dst_address.as_u32;
342 
343  if (proto == IP_PROTOCOL_ICMP6)
344  {
345  icmp46_header_t *icmp = ip4_next_header (ip4);
346  u16 out_id = ((u16 *) (icmp))[2];
347  proto = IP_PROTOCOL_ICMP;
348 
349  if (!
350  (icmp->type == ICMP6_echo_request
351  || icmp->type == ICMP6_echo_reply))
352  return -1;
353 
354  ste =
355  nat64_db_st_entry_find (db, &saddr, &daddr, out_id, 0, proto,
356  fib_index, 0);
357  if (!ste)
358  return -1;
359 
360  bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
361  if (!bibe)
362  return -1;
363 
364  ip6->dst_address.as_u64[0] = ste->in_r_addr.as_u64[0];
365  ip6->dst_address.as_u64[1] = ste->in_r_addr.as_u64[1];
366  ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
367  ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
368  ((u16 *) (icmp))[2] = bibe->in_port;
369 
370  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
371  }
372  else
373  {
374  udp_header_t *udp = ip4_next_header (ip4);
375  tcp_header_t *tcp = ip4_next_header (ip4);
376  u16 dport = udp->dst_port;
377  u16 sport = udp->src_port;
378  u16 *checksum;
379  ip_csum_t csum;
380 
381  ste =
382  nat64_db_st_entry_find (db, &saddr, &daddr, sport, dport, proto,
383  fib_index, 0);
384  if (!ste)
385  return -1;
386 
387  bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
388  if (!bibe)
389  return -1;
390 
391  nat64_compose_ip6 (&ip6->dst_address, &daddr.ip4, bibe->fib_index);
392  ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
393  ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
394  udp->src_port = bibe->in_port;
395 
396  if (proto == IP_PROTOCOL_UDP)
397  checksum = &udp->checksum;
398  else
399  checksum = &tcp->checksum;
400  if (*checksum)
401  {
402  csum = ip_csum_sub_even (*checksum, sport);
403  csum = ip_csum_add_even (csum, udp->src_port);
404  *checksum = ip_csum_fold (csum);
405  }
406 
407  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
408  }
409 
410  return 0;
411 }
412 
413 static int
416 {
418  ip6_header_t *ip6;
419  ip6_frag_hdr_t *frag;
420  u32 frag_id;
421 
422  nat64_main_t *nm = &nat64_main;
423  nat64_db_bib_entry_t *bibe;
424  nat64_db_st_entry_t *ste;
425  ip46_address_t saddr, daddr;
426  ip6_address_t ip6_saddr;
427  u32 sw_if_index, fib_index;
428  u8 proto = ip4->protocol;
429  nat64_db_t *db = &nm->db[ctx->thread_index];
430 
431  // Deal with fragmented packets
432  u16 frag_offset = ip4_get_fragment_offset (ip4);
433  if (PREDICT_FALSE (ip4_get_fragment_more (ip4) || frag_offset))
434  {
435  ip6 =
436  (ip6_header_t *) u8_ptr_add (ip4,
437  sizeof (*ip4) - sizeof (*ip6) -
438  sizeof (*frag));
439  frag =
440  (ip6_frag_hdr_t *) u8_ptr_add (ip4, sizeof (*ip4) - sizeof (*frag));
441  frag_id = frag_id_4to6 (ip4->fragment_id);
442  vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6) - sizeof (*frag));
443  }
444  else
445  {
446  ip6 = (ip6_header_t *) (((u8 *) ip4) + sizeof (*ip4) - sizeof (*ip6));
447  vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6));
448  frag = NULL;
449  }
450 
452  clib_host_to_net_u32 ((6 << 28) + (ip4->tos << 20));
453  ip6->payload_length = u16_net_add (ip4->length, -sizeof (*ip4));
454  ip6->hop_limit = ip4->ttl;
455  ip6->protocol = ip4->protocol;
456 
457  if (PREDICT_FALSE (frag != NULL))
458  {
459  frag->next_hdr = ip6->protocol;
460  frag->identification = frag_id;
461  frag->rsv = 0;
462  frag->fragment_offset_and_more =
463  ip6_frag_hdr_offset_and_more (frag_offset, 1);
464  ip6->protocol = IP_PROTOCOL_IPV6_FRAGMENTATION;
465  ip6->payload_length = u16_net_add (ip6->payload_length, sizeof (*frag));
466  }
467 
468  sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
469  fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
470 
471  clib_memset (&saddr, 0, sizeof (saddr));
472  saddr.ip4.as_u32 = ip4->src_address.as_u32;
473  clib_memset (&daddr, 0, sizeof (daddr));
474  daddr.ip4.as_u32 = ip4->dst_address.as_u32;
475 
476  ste =
477  nat64_db_st_entry_find (db, &daddr, &saddr, 0, 0, proto, fib_index, 0);
478  if (ste)
479  {
480  bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
481  if (!bibe)
482  return -1;
483  }
484  else
485  {
486  bibe = nat64_db_bib_entry_find (db, &daddr, 0, proto, fib_index, 0);
487 
488  if (!bibe)
489  return -1;
490 
491  nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index);
492  ste = nat64_db_st_entry_create (ctx->thread_index, db,
493  bibe, &ip6_saddr, &saddr.ip4, 0);
494 
495  if (!ste)
496  return -1;
497 
499  db->st.st_entries_num);
500  }
501 
502  nat64_session_reset_timeout (ste, ctx->vm);
503 
504  ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
505  ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
506 
507  ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
508  ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
509 
510  vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
511 
512  return 0;
513 }
514 
518 {
519  u32 n_left_from, *from, *to_next;
520  nat64_out2in_next_t next_index;
521  nat64_main_t *nm = &nat64_main;
523 
524  from = vlib_frame_vector_args (frame);
525  n_left_from = frame->n_vectors;
526  next_index = node->cached_next_index;
527  while (n_left_from > 0)
528  {
529  u32 n_left_to_next;
530 
531  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
532 
533  while (n_left_from > 0 && n_left_to_next > 0)
534  {
535  u32 bi0;
536  vlib_buffer_t *b0;
537  u32 next0;
538  ip4_header_t *ip40;
539  u32 proto0;
541  udp_header_t *udp0;
542  u32 sw_if_index0;
543 
544  /* speculatively enqueue b0 to the current next frame */
545  bi0 = from[0];
546  to_next[0] = bi0;
547  from += 1;
548  to_next += 1;
549  n_left_from -= 1;
550  n_left_to_next -= 1;
551 
552  b0 = vlib_get_buffer (vm, bi0);
553  ip40 = vlib_buffer_get_current (b0);
554 
555  ctx0.b = b0;
556  ctx0.vm = vm;
557  ctx0.thread_index = thread_index;
558 
560 
561  proto0 = ip_proto_to_nat_proto (ip40->protocol);
562  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
563  if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
564  {
565  if (nat64_out2in_unk_proto (vm, b0, &ctx0))
566  {
567  next0 = NAT64_OUT2IN_NEXT_DROP;
568  b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
569  }
571  thread_index, sw_if_index0, 1);
572  goto trace0;
573  }
574 
575  if (proto0 == NAT_PROTOCOL_ICMP)
576  {
578  thread_index, sw_if_index0, 1);
579  if (icmp_to_icmp6
580  (b0, nat64_out2in_icmp_set_cb, &ctx0,
582  {
583  next0 = NAT64_OUT2IN_NEXT_DROP;
584  b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
585  goto trace0;
586  }
587  }
588  else
589  {
590  if (proto0 == NAT_PROTOCOL_TCP)
592  thread_index, sw_if_index0, 1);
593  else
595  thread_index, sw_if_index0, 1);
596 
597  if (nat64_out2in_tcp_udp (vm, b0, &ctx0))
598  {
599  udp0 = ip4_next_header (ip40);
600  /*
601  * Send DHCP packets to the ipv4 stack, or we won't
602  * be able to use dhcp client on the outside interface
603  */
604  if ((proto0 == NAT_PROTOCOL_UDP)
605  && (udp0->dst_port ==
606  clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client)))
607  {
609  goto trace0;
610  }
611  next0 = NAT64_OUT2IN_NEXT_DROP;
612  b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
613  goto trace0;
614  }
615  }
616 
617  trace0:
618  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
619  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
620  {
622  vlib_add_trace (vm, node, b0, sizeof (*t));
623  t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
624  t->next_index = next0;
625  }
626 
627  if (next0 == NAT64_OUT2IN_NEXT_DROP)
628  {
630  thread_index, sw_if_index0, 1);
631  }
632 
633  /* verify speculative enqueue, maybe switch current next frame */
634  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
635  n_left_to_next, bi0, next0);
636  }
637  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
638  }
639  return frame->n_vectors;
640 }
641 
642 /* *INDENT-OFF* */
644  .name = "nat64-out2in",
645  .vector_size = sizeof (u32),
646  .format_trace = format_nat64_out2in_trace,
649  .error_strings = nat64_out2in_error_strings,
650  .n_next_nodes = NAT64_OUT2IN_N_NEXT,
651  /* edit / add dispositions here */
652  .next_nodes = {
653  [NAT64_OUT2IN_NEXT_DROP] = "error-drop",
654  [NAT64_OUT2IN_NEXT_IP6_LOOKUP] = "ip6-lookup",
655  [NAT64_OUT2IN_NEXT_IP4_LOOKUP] = "ip4-lookup",
656  },
657 };
658 /* *INDENT-ON* */
659 
661 {
669 
670 #define foreach_nat64_out2in_handoff_error \
671 _(CONGESTION_DROP, "congestion drop") \
672 _(SAME_WORKER, "same worker") \
673 _(DO_HANDOFF, "do handoff")
674 
675 typedef enum
676 {
677 #define _(sym,str) NAT64_OUT2IN_HANDOFF_ERROR_##sym,
679 #undef _
682 
684 #define _(sym,string) string,
686 #undef _
687 };
688 
689 typedef struct
690 {
693 
694 static u8 *
696 {
697  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
698  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
700  va_arg (*args, nat64_out2in_handoff_trace_t *);
701 
702  s =
703  format (s, "NAT64-OUT2IN-HANDOFF: next-worker %d", t->next_worker_index);
704 
705  return s;
706 }
707 
711 {
712  nat64_main_t *nm = &nat64_main;
713  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
714  u32 n_enq, n_left_from, *from;
715  u16 thread_indices[VLIB_FRAME_SIZE], *ti;
716  u32 fq_index;
718  u32 do_handoff = 0, same_worker = 0;
719 
720  from = vlib_frame_vector_args (frame);
721  n_left_from = frame->n_vectors;
722  vlib_get_buffers (vm, from, bufs, n_left_from);
723 
724  b = bufs;
725  ti = thread_indices;
726 
727  fq_index = nm->fq_out2in_index;
728 
729  while (n_left_from > 0)
730  {
731  ip4_header_t *ip0;
732 
733  ip0 = vlib_buffer_get_current (b[0]);
734  ti[0] = nat64_get_worker_out2in (b[0], ip0);
735 
736  if (ti[0] != thread_index)
737  do_handoff++;
738  else
739  same_worker++;
740 
741  if (PREDICT_FALSE
742  ((node->flags & VLIB_NODE_FLAG_TRACE)
743  && (b[0]->flags & VLIB_BUFFER_IS_TRACED)))
744  {
746  vlib_add_trace (vm, node, b[0], sizeof (*t));
747  t->next_worker_index = ti[0];
748  }
749 
750  n_left_from -= 1;
751  ti += 1;
752  b += 1;
753  }
754 
755  n_enq =
756  vlib_buffer_enqueue_to_thread (vm, fq_index, from, thread_indices,
757  frame->n_vectors, 1);
758 
759  if (n_enq < frame->n_vectors)
760  vlib_node_increment_counter (vm, node->node_index,
761  NAT64_OUT2IN_HANDOFF_ERROR_CONGESTION_DROP,
762  frame->n_vectors - n_enq);
763  vlib_node_increment_counter (vm, node->node_index,
764  NAT64_OUT2IN_HANDOFF_ERROR_SAME_WORKER,
765  same_worker);
766  vlib_node_increment_counter (vm, node->node_index,
767  NAT64_OUT2IN_HANDOFF_ERROR_DO_HANDOFF,
768  do_handoff);
769 
770  return frame->n_vectors;
771 }
772 
773 /* *INDENT-OFF* */
775  .name = "nat64-out2in-handoff",
776  .vector_size = sizeof (u32),
777  .format_trace = format_nat64_out2in_handoff_trace,
780  .error_strings = nat64_out2in_handoff_error_strings,
781 
782  .n_next_nodes = 1,
783 
784  .next_nodes = {
785  [0] = "error-drop",
786  },
787 };
788 /* *INDENT-ON* */
789 
790 /*
791  * fd.io coding-style-patch-verification: ON
792  *
793  * Local Variables:
794  * eval: (c-set-style "gnu")
795  * End:
796  */
nat64_out2in_handoff_error_t
Definition: nat64_out2in.c:675
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
nat64_db_t * db
BIB and session DB per thread.
Definition: nat64.h:137
#define CLIB_UNUSED(x)
Definition: clib.h:87
static char * nat64_out2in_error_strings[]
Definition: nat64_out2in.c:54
ip4_address_t src_address
Definition: ip4_packet.h:125
struct nat64_out2in_frag_set_ctx_t_ nat64_out2in_frag_set_ctx_t
unsigned long u64
Definition: types.h:89
vlib_buffer_t * b
Definition: nat64_out2in.c:70
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
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:998
nat64_out2in_error_t
Definition: nat64_out2in.c:46
u32 thread_index
Definition: main.h:250
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:225
nat64_out2in_next_t
Definition: nat64_out2in.c:60
uword ip_csum_t
Definition: ip_packet.h:246
static ip_csum_t ip_csum_with_carry(ip_csum_t sum, ip_csum_t x)
Definition: ip_packet.h:249
static void vlib_increment_simple_counter(vlib_simple_counter_main_t *cm, u32 thread_index, u32 index, u64 increment)
Increment a simple counter.
Definition: counter.h:78
#define VLIB_NODE_FN(node)
Definition: node.h:203
static int nat64_out2in_icmp_set_cb(vlib_buffer_t *b, ip4_header_t *ip4, ip6_header_t *ip6, void *arg)
Definition: nat64_out2in.c:241
struct _tcp_header tcp_header_t
ip6_address_t src_address
Definition: ip6_packet.h:310
struct nat64_out2in_set_ctx_t_ nat64_out2in_set_ctx_t
unsigned char u8
Definition: types.h:56
IPv4 to IPv6 translation.
u32 st_entries_num
Definition: nat64_db.h:129
vlib_node_registration_t nat64_out2in_handoff_node
(constructor) VLIB_REGISTER_NODE (nat64_out2in_handoff_node)
Definition: nat64_out2in.c:774
#define u8_ptr_add(ptr, index)
Definition: ip_types.h:56
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:227
static nat_protocol_t ip_proto_to_nat_proto(u8 ip_proto)
Common NAT inline functions.
Definition: inlines.h:24
nat64_db_st_entry_t * nat64_db_st_entry_create(u32 thread_index, 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:392
static u16 ip4_get_fragment_more(const ip4_header_t *i)
Definition: ip4_packet.h:161
vl_api_ip6_address_t ip6
Definition: one.api:424
ip4_address_t dst_address
Definition: ip4_packet.h:125
description fragment has unexpected format
Definition: map.api:433
struct nat64_main_t::@102 counters
#define frag_id_4to6(id)
Definition: ip4_to_ip6.h:40
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:196
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:1139
#define VLIB_FRAME_SIZE
Definition: node.h:378
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
void nat64_session_reset_timeout(nat64_db_st_entry_t *ste, vlib_main_t *vm)
Reset NAT64 session timeout.
Definition: nat64.c:1100
vl_api_ip_proto_t proto
Definition: acl_types.api:51
icmp
Definition: map.api:387
long ctx[MAX_CONNS]
Definition: main.c:144
#define foreach_nat64_out2in_handoff_error
Definition: nat64_out2in.c:670
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:233
static char * nat64_out2in_handoff_error_strings[]
Definition: nat64_out2in.c:683
static u8 * format_nat64_out2in_trace(u8 *s, va_list *args)
Definition: nat64_out2in.c:28
nat64_db_st_t st
Definition: nat64_db.h:145
#define PREDICT_FALSE(x)
Definition: clib.h:121
vl_api_ip4_address_t ip4
Definition: one.api:376
static void vlib_set_simple_counter(vlib_simple_counter_main_t *cm, u32 thread_index, u32 index, u64 value)
Set a simple counter.
Definition: counter.h:113
#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:224
#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:391
void nat64_compose_ip6(ip6_address_t *ip6, ip4_address_t *ip4, u32 fib_index)
Compose IPv4-embedded IPv6 addresses.
Definition: nat64.c:1271
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1231
vlib_simple_counter_main_t total_sessions
Definition: nat64.h:169
static int nat64_out2in_tcp_udp(vlib_main_t *vm, vlib_buffer_t *b, nat64_out2in_set_ctx_t *ctx)
Definition: nat64_out2in.c:76
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:170
static u8 * format_nat64_out2in_handoff_trace(u8 *s, va_list *args)
Definition: nat64_out2in.c:695
static u16 ip4_get_fragment_offset(const ip4_header_t *i)
Definition: ip4_packet.h:155
#define ARRAY_LEN(x)
Definition: clib.h:67
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:483
static int nat64_out2in_unk_proto(vlib_main_t *vm, vlib_buffer_t *p, nat64_out2in_set_ctx_t *ctx)
Definition: nat64_out2in.c:414
nat64_main_t nat64_main
Definition: nat64.c:27
u32 fq_out2in_index
Definition: nat64.h:141
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1580
struct nat64_main_t::@102::@104 out2in
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:571
u32 nat64_get_worker_out2in(vlib_buffer_t *b, ip4_header_t *ip)
Get worker thread index for NAT64 out2in.
Definition: nat64.c:139
static int nat64_out2in_inner_icmp_set_cb(vlib_buffer_t *b, ip4_header_t *ip4, ip6_header_t *ip6, void *arg)
Definition: nat64_out2in.c:322
ip_dscp_t tos
Definition: ip4_packet.h:96
static ip_csum_t ip_csum_sub_even(ip_csum_t c, ip_csum_t x)
Definition: ip_packet.h:274
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:318
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:643
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:252
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:297
Definition: defs.h:47
u16 payload_length
Definition: ip6_packet.h:301
vl_api_address_t ip
Definition: l2.api:501
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1581
VLIB buffer representation.
Definition: buffer.h:102
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:297
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:494
#define vnet_buffer(b)
Definition: buffer.h:417
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:634
#define u16_net_add(u, val)
Definition: ip_types.h:57
#define ip6_frag_hdr_offset_and_more(offset, more)
Definition: ip6_packet.h:678
static_always_inline void vlib_get_buffers(vlib_main_t *vm, u32 *bi, vlib_buffer_t **b, int count)
Translate array of buffer indices into buffer pointers.
Definition: buffer_funcs.h:280
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
static ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_packet.h:320
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:302
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
Definition: defs.h:46
#define foreach_nat64_out2in_error
Definition: nat64_out2in.c:41
static ip_csum_t ip_csum_add_even(ip_csum_t c, ip_csum_t x)
Definition: ip_packet.h:257
ip6_address_t dst_address
Definition: ip6_packet.h:310