FD.io VPP  v21.06-3-gbb25fbf28
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 
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 
100 
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 =
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 
154  ip6->ip_version_traffic_class_and_flow_label =
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];
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 
192  vlib_set_simple_counter (&nm->total_sessions, ctx->thread_index, 0,
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 {
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];
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 =
287  nat64_db_st_entry_create (ctx->thread_index, db,
288  bibe, &ip6_saddr, &saddr.ip4, 0);
289 
290  if (!ste)
291  return -1;
292 
293  vlib_set_simple_counter (&nm->total_sessions, ctx->thread_index, 0,
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 
312  nat64_compose_ip6 (&ip6->src_address, &ip4->src_address,
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 {
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  {
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 
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 =
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 
451  ip6->ip_version_traffic_class_and_flow_label =
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];
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 
498  vlib_set_simple_counter (&nm->total_sessions, ctx->thread_index, 0,
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;
523 
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 */
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 {
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 
721  n_left_from = frame->n_vectors;
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 = vlib_buffer_enqueue_to_thread (vm, node, fq_index, from,
756  thread_indices, frame->n_vectors, 1);
757 
758  if (n_enq < frame->n_vectors)
759  vlib_node_increment_counter (vm, node->node_index,
760  NAT64_OUT2IN_HANDOFF_ERROR_CONGESTION_DROP,
761  frame->n_vectors - n_enq);
762  vlib_node_increment_counter (vm, node->node_index,
763  NAT64_OUT2IN_HANDOFF_ERROR_SAME_WORKER,
764  same_worker);
765  vlib_node_increment_counter (vm, node->node_index,
766  NAT64_OUT2IN_HANDOFF_ERROR_DO_HANDOFF,
767  do_handoff);
768 
769  return frame->n_vectors;
770 }
771 
772 /* *INDENT-OFF* */
774  .name = "nat64-out2in-handoff",
775  .vector_size = sizeof (u32),
776  .format_trace = format_nat64_out2in_handoff_trace,
779  .error_strings = nat64_out2in_handoff_error_strings,
780 
781  .n_next_nodes = 1,
782 
783  .next_nodes = {
784  [0] = "error-drop",
785  },
786 };
787 /* *INDENT-ON* */
788 
789 /*
790  * fd.io coding-style-patch-verification: ON
791  *
792  * Local Variables:
793  * eval: (c-set-style "gnu")
794  * End:
795  */
udp_header_t::src_port
u16 src_port
Definition: udp_packet.h:48
thread_index
u32 thread_index
Definition: nat44_ei_hairpinning.c:492
nat64_out2in_handoff_error_strings
static char * nat64_out2in_handoff_error_strings[]
Definition: nat64_out2in.c:683
bufs
vlib_buffer_t * bufs[VLIB_FRAME_SIZE]
Definition: nat44_ei_out2in.c:717
u8_ptr_add
#define u8_ptr_add(ptr, index)
Definition: ip_types.h:56
vlib_buffer_enqueue_to_thread
static_always_inline u32 vlib_buffer_enqueue_to_thread(vlib_main_t *vm, vlib_node_runtime_t *node, u32 frame_queue_index, u32 *buffer_indices, u16 *thread_indices, u32 n_packets, int drop_on_congestion)
Definition: buffer_node.h:358
frame
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: nat44_ei.c:3048
nat64_out2in_handoff_trace_t::next_worker_index
u32 next_worker_index
Definition: nat64_out2in.c:691
ip4
vl_api_ip4_address_t ip4
Definition: one.api:376
next_index
nat44_ei_hairpin_src_next_t next_index
Definition: nat44_ei_hairpinning.c:412
vlib_get_buffer
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:111
nat64_main
nat64_main_t nat64_main
Definition: nat64.c:27
tcp_header_t
struct _tcp_header tcp_header_t
vlib_get_buffers
vlib_get_buffers(vm, from, b, n_left_from)
ip_proto_to_nat_proto
static nat_protocol_t ip_proto_to_nat_proto(u8 ip_proto)
Common NAT inline functions.
Definition: inlines.h:24
VLIB_NODE_TYPE_INTERNAL
@ VLIB_NODE_TYPE_INTERNAL
Definition: node.h:72
VLIB_FRAME_SIZE
#define VLIB_FRAME_SIZE
Definition: node.h:368
node
vlib_main_t vlib_node_runtime_t * node
Definition: nat44_ei.c:3047
nat64_out2in_set_ctx_t
struct nat64_out2in_set_ctx_t_ nat64_out2in_set_ctx_t
ip4_address_t::as_u32
u32 as_u32
Definition: ip4_packet.h:57
nat64_out2in_frag_set_ctx_t_::sess_index
u32 sess_index
Definition: nat64_out2in.c:664
nat44_ei_main_s::fq_out2in_index
u32 fq_out2in_index
Definition: nat44_ei.h:400
ip6_frag_hdr_offset_and_more
#define ip6_frag_hdr_offset_and_more(offset, more)
Definition: ip6_packet.h:709
ip4_fib_table_get_index_for_sw_if_index
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: pnat_test_stubs.h:21
NAT64_OUT2IN_N_ERROR
@ NAT64_OUT2IN_N_ERROR
Definition: nat64_out2in.c:51
u16
unsigned short u16
Definition: types.h:57
nat64_out2in_frag_set_ctx_t_::thread_index
u32 thread_index
Definition: nat64_out2in.c:665
foreach_nat64_out2in_error
#define foreach_nat64_out2in_error
Definition: nat64_out2in.c:41
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
VLIB_RX
@ VLIB_RX
Definition: defs.h:46
nat44_ei_main_s::counters
struct nat44_ei_main_s::@81 counters
vlib_frame_t
Definition: node.h:372
udp_header_t
Definition: udp_packet.h:45
ip4_header_t
Definition: ip4_packet.h:87
nat64_db_st_t::st_entries_num
u32 st_entries_num
Definition: nat64_db.h:129
frag_id_4to6
#define frag_id_4to6(id)
Definition: ip4_to_ip6.h:40
sport
u16 sport
Definition: pnat.api:43
ti
u32 ti
Definition: interface_output.c:405
vlib_increment_simple_counter
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:74
vlib_buffer_advance
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:276
nat64_out2in_frag_set_ctx_t_::b
vlib_buffer_t * b
Definition: nat64_out2in.c:663
vlib_buffer_t::error
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:145
VLIB_NODE_FN
#define VLIB_NODE_FN(node)
Definition: node.h:202
nat64_out2in_error_strings
static char * nat64_out2in_error_strings[]
Definition: nat64_out2in.c:54
CLIB_UNUSED
#define CLIB_UNUSED(x)
Definition: clib.h:90
vnet_buffer
#define vnet_buffer(b)
Definition: buffer.h:437
VLIB_NODE_FLAG_TRACE
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:291
ip_incremental_checksum
static ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_packet.h:319
PREDICT_FALSE
#define PREDICT_FALSE(x)
Definition: clib.h:124
nat64_out2in_set_ctx_t_::thread_index
u32 thread_index
Definition: nat64_out2in.c:72
ARRAY_LEN
#define ARRAY_LEN(x)
Definition: clib.h:70
vlib_frame_vector_args
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:301
ip4_get_fragment_offset
static u16 ip4_get_fragment_offset(const ip4_header_t *i)
Definition: ip4_packet.h:155
udp_local.h
nat64_out2in_handoff_error_t
nat64_out2in_handoff_error_t
Definition: nat64_out2in.c:675
nat64_out2in_node
vlib_node_registration_t nat64_out2in_node
(constructor) VLIB_REGISTER_NODE (nat64_out2in_node)
Definition: nat64_out2in.c:643
vlib_main_t::thread_index
u32 thread_index
Definition: main.h:213
vlib_node_increment_counter
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1244
nat64_out2in_frag_set_ctx_t_::vm
vlib_main_t * vm
Definition: nat64_out2in.c:662
nat64_out2in_trace_t
Definition: nat64_out2in.c:21
nat64_db_s::st
nat64_db_st_t st
Definition: nat64_db.h:145
ip4_address_t
Definition: ip4_packet.h:50
icmp_to_icmp6
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
struct _vlib_node_registration vlib_node_registration_t
ip4_get_fragment_more
static u16 ip4_get_fragment_more(const ip4_header_t *i)
Definition: ip4_packet.h:161
NAT64_OUT2IN_NEXT_DROP
@ NAT64_OUT2IN_NEXT_DROP
Definition: nat64_out2in.c:64
udp_header_t::checksum
u16 checksum
Definition: udp_packet.h:55
nat64_out2in_next_t
nat64_out2in_next_t
Definition: nat64_out2in.c:60
ip_csum_sub_even
static ip_csum_t ip_csum_sub_even(ip_csum_t c, ip_csum_t x)
Definition: ip_packet.h:273
nat64.h
NAT64_OUT2IN_NEXT_IP6_LOOKUP
@ NAT64_OUT2IN_NEXT_IP6_LOOKUP
Definition: nat64_out2in.c:62
vlib_validate_buffer_enqueue_x1
#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
icmp
icmp
Definition: map.api:387
vlib_set_simple_counter
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:109
u64
unsigned long u64
Definition: types.h:89
format
description fragment has unexpected format
Definition: map.api:433
nat64_main_t
Definition: nat64.h:112
vlib_put_next_frame
vlib_put_next_frame(vm, node, next_index, 0)
ip_csum_with_carry
static ip_csum_t ip_csum_with_carry(ip_csum_t sum, ip_csum_t x)
Definition: ip_packet.h:248
fib_table_get_index_for_sw_if_index
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
dport
u16 dport
Definition: pnat.api:44
nat64_out2in_error_t
nat64_out2in_error_t
Definition: nat64_out2in.c:46
u32
unsigned int u32
Definition: types.h:88
udp_header_t::dst_port
u16 dst_port
Definition: udp_packet.h:48
ip6
vl_api_ip6_address_t ip6
Definition: one.api:424
FIB_PROTOCOL_IP6
@ FIB_PROTOCOL_IP6
Definition: fib_types.h:37
NAT64_OUT2IN_N_NEXT
@ NAT64_OUT2IN_N_NEXT
Definition: nat64_out2in.c:65
ctx
long ctx[MAX_CONNS]
Definition: main.c:144
nat64_out2in_trace_t::sw_if_index
u32 sw_if_index
Definition: nat64_out2in.c:23
nat64_out2in_frag_set_ctx_t
struct nat64_out2in_frag_set_ctx_t_ nat64_out2in_frag_set_ctx_t
NAT64_OUT2IN_HANDOFF_N_ERROR
@ NAT64_OUT2IN_HANDOFF_N_ERROR
Definition: nat64_out2in.c:680
nat64_db_st_entry_find
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
n_vectors
return frame n_vectors
Definition: nat44_ei_hairpinning.c:485
format_nat64_out2in_trace
static u8 * format_nat64_out2in_trace(u8 *s, va_list *args)
Definition: nat64_out2in.c:28
nm
nat44_ei_main_t * nm
Definition: nat44_ei_hairpinning.c:413
nat64_out2in_frag_set_ctx_t_::first_frag
u8 first_frag
Definition: nat64_out2in.c:667
ip6_header_t
Definition: ip6_packet.h:294
nat64_db_st_entry_create
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
ip4_fib.h
nat64_out2in_tcp_udp
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
ip6_header_t::src_address
ip6_address_t src_address
Definition: ip6_packet.h:310
nat64_get_worker_out2in
u32 nat64_get_worker_out2in(vlib_buffer_t *b, ip4_header_t *ip)
Get worker thread index for NAT64 out2in.
Definition: nat64.c:139
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
vlib_main_t
Definition: main.h:102
vlib_node_t
Definition: node.h:247
nat64_db_bib_entry_find
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
vlib_add_trace
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:628
nat64_tcp_session_set_state
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
b
vlib_buffer_t ** b
Definition: nat44_ei_out2in.c:717
u8
unsigned char u8
Definition: types.h:56
vlib_buffer_get_current
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:257
ip
vl_api_address_t ip
Definition: l2.api:558
ip_csum_t
uword ip_csum_t
Definition: ip_packet.h:245
nat64_out2in_inner_icmp_set_cb
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
nat44_ei_main_s::out2in
clib_bihash_8_8_t out2in
Definition: nat44_ei.h:362
ip4_to_ip6.h
IPv4 to IPv6 translation.
format_nat64_out2in_handoff_trace
static u8 * format_nat64_out2in_handoff_trace(u8 *s, va_list *args)
Definition: nat64_out2in.c:695
nat64_out2in_frag_set_ctx_t_::proto
u8 proto
Definition: nat64_out2in.c:666
u16_net_add
#define u16_net_add(u, val)
Definition: ip_types.h:57
nat64_compose_ip6
void nat64_compose_ip6(ip6_address_t *ip6, ip4_address_t *ip4, u32 fib_index)
Compose IPv4-embedded IPv6 addresses.
Definition: nat64.c:1271
nat64_session_reset_timeout
void nat64_session_reset_timeout(nat64_db_st_entry_t *ste, vlib_main_t *vm)
Reset NAT64 session timeout.
Definition: nat64.c:1100
nat64_db_bib_entry_by_index
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
vlib_node_runtime_t
Definition: node.h:454
proto
vl_api_ip_proto_t proto
Definition: acl_types.api:51
nat44_ei_main_s::total_sessions
vlib_simple_counter_main_t total_sessions
Definition: nat44_ei.h:409
foreach_nat64_out2in_handoff_error
#define foreach_nat64_out2in_handoff_error
Definition: nat64_out2in.c:670
from
from
Definition: nat44_ei_hairpinning.c:415
ip_csum_add_even
static ip_csum_t ip_csum_add_even(ip_csum_t c, ip_csum_t x)
Definition: ip_packet.h:256
nat64_out2in_frag_set_ctx_t_
Definition: nat64_out2in.c:660
sw_if_index
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
vlib_get_next_frame
#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:395
nat64_out2in_set_ctx_t_
Definition: nat64_out2in.c:68
ip_csum_fold
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:301
VLIB_TX
@ VLIB_TX
Definition: defs.h:47
nat64_out2in_handoff_node
vlib_node_registration_t nat64_out2in_handoff_node
(constructor) VLIB_REGISTER_NODE (nat64_out2in_handoff_node)
Definition: nat64_out2in.c:773
n_left_from
n_left_from
Definition: nat44_ei_hairpinning.c:416
nat64_out2in_handoff_trace_t
Definition: nat64_out2in.c:689
nat64_out2in_trace_t::next_index
u32 next_index
Definition: nat64_out2in.c:24
nat64_out2in_set_ctx_t_::vm
vlib_main_t * vm
Definition: nat64_out2in.c:71
type
vl_api_fib_path_type_t type
Definition: fib_types.api:123
nat64_db_s
Definition: nat64_db.h:142
ip4_header_t::protocol
u8 protocol
Definition: ip4_packet.h:115
ip4_next_header
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:196
vlib_buffer_t::flags
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index,...
Definition: buffer.h:133
nat64_out2in_unk_proto
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_out2in_icmp_set_cb
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
nat64_out2in_set_ctx_t_::b
vlib_buffer_t * b
Definition: nat64_out2in.c:70
vlib_buffer_t
VLIB buffer representation.
Definition: buffer.h:111
VLIB_REGISTER_NODE
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
NAT64_OUT2IN_NEXT_IP4_LOOKUP
@ NAT64_OUT2IN_NEXT_IP4_LOOKUP
Definition: nat64_out2in.c:63