FD.io VPP  v21.01.1
Vector Packet Processing
cnat_node.h
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 #ifndef __CNAT_NODE_H__
17 #define __CNAT_NODE_H__
18 
19 #include <vlibmemory/api.h>
20 #include <cnat/cnat_session.h>
21 #include <cnat/cnat_client.h>
22 #include <cnat/cnat_inline.h>
23 
26  vlib_buffer_t * b,
27  cnat_node_ctx_t * ctx, int rv,
28  cnat_session_t * session);
29 
32 {
33  switch (icmp_type)
34  {
35  case ICMP4_destination_unreachable:
36  case ICMP4_time_exceeded:
37  case ICMP4_parameter_problem:
38  case ICMP4_source_quench:
39  case ICMP4_redirect:
40  case ICMP4_alternate_host_address:
41  return 1;
42  }
43  return 0;
44 }
45 
47 icmp_type_is_echo (u8 icmp_type)
48 {
49  switch (icmp_type)
50  {
51  case ICMP4_echo_request:
52  case ICMP4_echo_reply:
53  return 1;
54  }
55  return 0;
56 }
57 
60 {
61  switch (icmp_type)
62  {
63  case ICMP6_echo_request:
64  case ICMP6_echo_reply:
65  return 1;
66  }
67  return 0;
68 }
69 
72 {
73  switch (icmp_type)
74  {
75  case ICMP6_destination_unreachable:
76  case ICMP6_time_exceeded:
77  case ICMP6_parameter_problem:
78  return 1;
79  }
80  return 0;
81 }
82 
84 cmp_ip6_address (const ip6_address_t * a1, const ip6_address_t * a2)
85 {
86  return ((a1->as_u64[0] == a2->as_u64[0])
87  && (a1->as_u64[1] == a2->as_u64[1]));
88 }
89 
90 /**
91  * Inline translation functions
92  */
93 
95 has_ip6_address (ip6_address_t * a)
96 {
97  return ((0 != a->as_u64[0]) || (0 != a->as_u64[1]));
98 }
99 
102  ip_csum_t * sum,
103  ip4_address_t new_addr[VLIB_N_DIR],
104  u16 new_port[VLIB_N_DIR])
105 {
106  u16 old_port[VLIB_N_DIR];
107  ip4_address_t old_addr[VLIB_N_DIR];
108 
109  /* Fastpath no checksum */
110  if (PREDICT_TRUE (0 == *sum))
111  {
112  udp->dst_port = new_port[VLIB_TX];
113  udp->src_port = new_port[VLIB_RX];
114  return;
115  }
116 
117  old_port[VLIB_TX] = udp->dst_port;
118  old_port[VLIB_RX] = udp->src_port;
119  old_addr[VLIB_TX] = ip4->dst_address;
120  old_addr[VLIB_RX] = ip4->src_address;
121 
122  if (new_addr[VLIB_TX].as_u32)
123  {
124  *sum =
125  ip_csum_update (*sum, old_addr[VLIB_TX].as_u32,
126  new_addr[VLIB_TX].as_u32, ip4_header_t, dst_address);
127  }
128  if (new_port[VLIB_TX])
129  {
130  udp->dst_port = new_port[VLIB_TX];
131  *sum = ip_csum_update (*sum, old_port[VLIB_TX], new_port[VLIB_TX],
132  ip4_header_t /* cheat */ ,
133  length /* changed member */ );
134  }
135  if (new_addr[VLIB_RX].as_u32)
136  {
137  *sum =
138  ip_csum_update (*sum, old_addr[VLIB_RX].as_u32,
139  new_addr[VLIB_RX].as_u32, ip4_header_t, src_address);
140  }
141  if (new_port[VLIB_RX])
142  {
143  udp->src_port = new_port[VLIB_RX];
144  *sum = ip_csum_update (*sum, old_port[VLIB_RX], new_port[VLIB_RX],
145  ip4_header_t /* cheat */ ,
146  length /* changed member */ );
147  }
148 }
149 
152 {
153  ip4_address_t old_addr[VLIB_N_DIR];
154  ip_csum_t sum;
155 
156  old_addr[VLIB_TX] = ip4->dst_address;
157  old_addr[VLIB_RX] = ip4->src_address;
158 
159  sum = ip4->checksum;
160  if (new_addr[VLIB_TX].as_u32)
161  {
162  ip4->dst_address = new_addr[VLIB_TX];
163  sum =
164  ip_csum_update (sum, old_addr[VLIB_TX].as_u32,
165  new_addr[VLIB_TX].as_u32, ip4_header_t, dst_address);
166  }
167  if (new_addr[VLIB_RX].as_u32)
168  {
169  ip4->src_address = new_addr[VLIB_RX];
170  sum =
171  ip_csum_update (sum, old_addr[VLIB_RX].as_u32,
172  new_addr[VLIB_RX].as_u32, ip4_header_t, src_address);
173  }
174  ip4->checksum = ip_csum_fold (sum);
175 }
176 
179 {
181  if (PREDICT_FALSE (tcp_fin (tcp)))
182  {
184  }
185 
186  if (PREDICT_FALSE (tcp_rst (tcp)))
187  {
189  }
190 
191  if (PREDICT_FALSE (tcp_syn (tcp) && tcp_ack (tcp)))
192  {
194  }
195 }
196 
199  ip4_address_t new_addr[VLIB_N_DIR],
200  u16 new_port[VLIB_N_DIR])
201 {
202  ip_csum_t sum;
203  u16 old_port;
204  cnat_echo_header_t *echo = (cnat_echo_header_t *) (icmp + 1);
205 
206  cnat_ip4_translate_l3 (ip4, new_addr);
207  old_port = echo->identifier;
208  echo->identifier = new_port[VLIB_RX];
209 
210  sum = icmp->checksum;
211  sum = ip_csum_update (sum, old_port, new_port[VLIB_RX],
212  ip4_header_t /* cheat */ ,
213  length /* changed member */ );
214 
215  icmp->checksum = ip_csum_fold (sum);
216 }
217 
220  icmp46_header_t * icmp,
221  ip4_address_t outer_new_addr[VLIB_N_DIR],
222  u16 outer_new_port[VLIB_N_DIR],
223  u8 snat_outer_ip)
224 {
225  ip4_address_t new_addr[VLIB_N_DIR];
226  ip4_address_t old_addr[VLIB_N_DIR];
227  u16 new_port[VLIB_N_DIR];
228  u16 old_port[VLIB_N_DIR];
229  ip_csum_t sum, old_ip_sum, inner_l4_sum, inner_l4_old_sum;
230 
231  ip4_header_t *ip4 = (ip4_header_t *) (icmp + 2);
232  udp_header_t *udp = (udp_header_t *) (ip4 + 1);
233  tcp_header_t *tcp = (tcp_header_t *) udp;
234 
235  /* Swap inner ports */
236  new_addr[VLIB_TX] = outer_new_addr[VLIB_RX];
237  new_addr[VLIB_RX] = outer_new_addr[VLIB_TX];
238  new_port[VLIB_TX] = outer_new_port[VLIB_RX];
239  new_port[VLIB_RX] = outer_new_port[VLIB_TX];
240 
241  old_addr[VLIB_TX] = ip4->dst_address;
242  old_addr[VLIB_RX] = ip4->src_address;
243  old_port[VLIB_RX] = udp->src_port;
244  old_port[VLIB_TX] = udp->dst_port;
245 
246  sum = icmp->checksum;
247  old_ip_sum = ip4->checksum;
248 
249  /* translate outer ip. */
250  if (!snat_outer_ip)
251  outer_new_addr[VLIB_RX] = outer_ip4->src_address;
252  cnat_ip4_translate_l3 (outer_ip4, outer_new_addr);
253 
254  if (ip4->protocol == IP_PROTOCOL_TCP)
255  {
256  inner_l4_old_sum = inner_l4_sum = tcp->checksum;
257  cnat_ip4_translate_l4 (ip4, udp, &inner_l4_sum, new_addr, new_port);
258  tcp->checksum = ip_csum_fold (inner_l4_sum);
259  }
260  else if (ip4->protocol == IP_PROTOCOL_UDP)
261  {
262  inner_l4_old_sum = inner_l4_sum = udp->checksum;
263  cnat_ip4_translate_l4 (ip4, udp, &inner_l4_sum, new_addr, new_port);
264  udp->checksum = ip_csum_fold (inner_l4_sum);
265  }
266  else
267  return;
268 
269  /* UDP/TCP checksum changed */
270  sum = ip_csum_update (sum, inner_l4_old_sum, inner_l4_sum,
271  ip4_header_t, checksum);
272 
273  /* UDP/TCP Ports changed */
274  if (old_port[VLIB_TX] && new_port[VLIB_TX])
275  sum = ip_csum_update (sum, old_port[VLIB_TX], new_port[VLIB_TX],
276  ip4_header_t /* cheat */ ,
277  length /* changed member */ );
278 
279  if (old_port[VLIB_RX] && new_port[VLIB_RX])
280  sum = ip_csum_update (sum, old_port[VLIB_RX], new_port[VLIB_RX],
281  ip4_header_t /* cheat */ ,
282  length /* changed member */ );
283 
284 
285  cnat_ip4_translate_l3 (ip4, new_addr);
286  ip_csum_t new_ip_sum = ip4->checksum;
287  /* IP checksum changed */
288  sum = ip_csum_update (sum, old_ip_sum, new_ip_sum, ip4_header_t, checksum);
289 
290  /* IP src/dst addr changed */
291  if (new_addr[VLIB_TX].as_u32)
292  sum =
293  ip_csum_update (sum, old_addr[VLIB_TX].as_u32, new_addr[VLIB_TX].as_u32,
294  ip4_header_t, dst_address);
295 
296  if (new_addr[VLIB_RX].as_u32)
297  sum =
298  ip_csum_update (sum, old_addr[VLIB_RX].as_u32, new_addr[VLIB_RX].as_u32,
300 
301  icmp->checksum = ip_csum_fold (sum);
302 }
303 
306  ip4_header_t * ip4, udp_header_t * udp)
307 {
308  tcp_header_t *tcp = (tcp_header_t *) udp;
309  ip4_address_t new_addr[VLIB_N_DIR];
310  u16 new_port[VLIB_N_DIR];
311 
312  new_addr[VLIB_TX] = session->value.cs_ip[VLIB_TX].ip4;
313  new_addr[VLIB_RX] = session->value.cs_ip[VLIB_RX].ip4;
314  new_port[VLIB_TX] = session->value.cs_port[VLIB_TX];
315  new_port[VLIB_RX] = session->value.cs_port[VLIB_RX];
316 
317  if (ip4->protocol == IP_PROTOCOL_TCP)
318  {
319  ip_csum_t sum = tcp->checksum;
320  cnat_ip4_translate_l4 (ip4, udp, &sum, new_addr, new_port);
321  tcp->checksum = ip_csum_fold (sum);
322  cnat_ip4_translate_l3 (ip4, new_addr);
324  }
325  else if (ip4->protocol == IP_PROTOCOL_UDP)
326  {
327  ip_csum_t sum = udp->checksum;
328  cnat_ip4_translate_l4 (ip4, udp, &sum, new_addr, new_port);
329  udp->checksum = ip_csum_fold (sum);
330  cnat_ip4_translate_l3 (ip4, new_addr);
331  }
332  else if (ip4->protocol == IP_PROTOCOL_ICMP)
333  {
334  icmp46_header_t *icmp = (icmp46_header_t *) udp;
335  if (icmp_type_is_error_message (icmp->type))
336  {
337  /* SNAT only if src_addr was translated */
338  u8 snat_outer_ip =
339  (ip4->src_address.as_u32 ==
340  session->key.cs_ip[VLIB_RX].ip4.as_u32);
341  cnat_translation_icmp4_error (ip4, icmp, new_addr, new_port,
342  snat_outer_ip);
343  }
344  else if (icmp_type_is_echo (icmp->type))
345  cnat_translation_icmp4_echo (ip4, icmp, new_addr, new_port);
346  }
347 }
348 
350 cnat_ip6_translate_l3 (ip6_header_t * ip6, ip6_address_t new_addr[VLIB_N_DIR])
351 {
352  if (has_ip6_address (&new_addr[VLIB_TX]))
353  ip6_address_copy (&ip6->dst_address, &new_addr[VLIB_TX]);
354  if (has_ip6_address (&new_addr[VLIB_RX]))
355  ip6_address_copy (&ip6->src_address, &new_addr[VLIB_RX]);
356 }
357 
360  ip_csum_t * sum,
361  ip6_address_t new_addr[VLIB_N_DIR],
362  u16 new_port[VLIB_N_DIR])
363 {
364  u16 old_port[VLIB_N_DIR];
365  ip6_address_t old_addr[VLIB_N_DIR];
366 
367  /* Fastpath no checksum */
368  if (PREDICT_TRUE (0 == *sum))
369  {
370  udp->dst_port = new_port[VLIB_TX];
371  udp->src_port = new_port[VLIB_RX];
372  return;
373  }
374 
375  old_port[VLIB_TX] = udp->dst_port;
376  old_port[VLIB_RX] = udp->src_port;
377  ip6_address_copy (&old_addr[VLIB_TX], &ip6->dst_address);
378  ip6_address_copy (&old_addr[VLIB_RX], &ip6->src_address);
379 
380  if (has_ip6_address (&new_addr[VLIB_TX]))
381  {
382  *sum = ip_csum_add_even (*sum, new_addr[VLIB_TX].as_u64[0]);
383  *sum = ip_csum_add_even (*sum, new_addr[VLIB_TX].as_u64[1]);
384  *sum = ip_csum_sub_even (*sum, old_addr[VLIB_TX].as_u64[0]);
385  *sum = ip_csum_sub_even (*sum, old_addr[VLIB_TX].as_u64[1]);
386  }
387 
388  if (new_port[VLIB_TX])
389  {
390  udp->dst_port = new_port[VLIB_TX];
391  *sum = ip_csum_update (*sum, old_port[VLIB_TX], new_port[VLIB_TX],
392  ip4_header_t /* cheat */ ,
393  length /* changed member */ );
394  }
395  if (has_ip6_address (&new_addr[VLIB_RX]))
396  {
397  *sum = ip_csum_add_even (*sum, new_addr[VLIB_RX].as_u64[0]);
398  *sum = ip_csum_add_even (*sum, new_addr[VLIB_RX].as_u64[1]);
399  *sum = ip_csum_sub_even (*sum, old_addr[VLIB_RX].as_u64[0]);
400  *sum = ip_csum_sub_even (*sum, old_addr[VLIB_RX].as_u64[1]);
401  }
402 
403  if (new_port[VLIB_RX])
404  {
405  udp->src_port = new_port[VLIB_RX];
406  *sum = ip_csum_update (*sum, old_port[VLIB_RX], new_port[VLIB_RX],
407  ip4_header_t /* cheat */ ,
408  length /* changed member */ );
409  }
410 }
411 
414  ip6_address_t new_addr[VLIB_N_DIR],
415  u16 new_port[VLIB_N_DIR])
416 {
417  cnat_echo_header_t *echo = (cnat_echo_header_t *) (icmp + 1);
418  ip6_address_t old_addr[VLIB_N_DIR];
419  ip_csum_t sum;
420  u16 old_port;
421  old_port = echo->identifier;
422  ip6_address_copy (&old_addr[VLIB_TX], &ip6->dst_address);
423  ip6_address_copy (&old_addr[VLIB_RX], &ip6->src_address);
424 
425  sum = icmp->checksum;
426 
427  cnat_ip6_translate_l3 (ip6, new_addr);
428  if (has_ip6_address (&new_addr[VLIB_TX]))
429  {
430  sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[0]);
431  sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[1]);
432  sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[0]);
433  sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[1]);
434  }
435 
436  if (has_ip6_address (&new_addr[VLIB_RX]))
437  {
438  sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[0]);
439  sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[1]);
440  sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[0]);
441  sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[1]);
442  }
443 
444  echo->identifier = new_port[VLIB_RX];
445  sum = ip_csum_update (sum, old_port, new_port[VLIB_RX],
446  ip4_header_t /* cheat */ ,
447  length /* changed member */ );
448 
449  icmp->checksum = ip_csum_fold (sum);
450 }
451 
454  icmp46_header_t * icmp,
455  ip6_address_t outer_new_addr[VLIB_N_DIR],
456  u16 outer_new_port[VLIB_N_DIR],
457  u8 snat_outer_ip)
458 {
459  ip6_address_t new_addr[VLIB_N_DIR];
460  ip6_address_t old_addr[VLIB_N_DIR];
461  ip6_address_t outer_old_addr[VLIB_N_DIR];
462  u16 new_port[VLIB_N_DIR];
463  u16 old_port[VLIB_N_DIR];
464  ip_csum_t sum, inner_l4_sum, inner_l4_old_sum;
465 
466  if (!icmp6_type_is_error_message (icmp->type))
467  return;
468 
469  ip6_header_t *ip6 = (ip6_header_t *) (icmp + 2);
470  udp_header_t *udp = (udp_header_t *) (ip6 + 1);
471  tcp_header_t *tcp = (tcp_header_t *) udp;
472 
473  /* Swap inner ports */
474  ip6_address_copy (&new_addr[VLIB_RX], &outer_new_addr[VLIB_TX]);
475  ip6_address_copy (&new_addr[VLIB_TX], &outer_new_addr[VLIB_RX]);
476  new_port[VLIB_TX] = outer_new_port[VLIB_RX];
477  new_port[VLIB_RX] = outer_new_port[VLIB_TX];
478 
479  ip6_address_copy (&old_addr[VLIB_TX], &ip6->dst_address);
480  ip6_address_copy (&old_addr[VLIB_RX], &ip6->src_address);
481  old_port[VLIB_RX] = udp->src_port;
482  old_port[VLIB_TX] = udp->dst_port;
483 
484  sum = icmp->checksum;
485  /* Translate outer ip */
486  ip6_address_copy (&outer_old_addr[VLIB_TX], &outer_ip6->dst_address);
487  ip6_address_copy (&outer_old_addr[VLIB_RX], &outer_ip6->src_address);
488  if (!snat_outer_ip)
489  ip6_address_copy (&outer_new_addr[VLIB_RX], &outer_ip6->src_address);
490  cnat_ip6_translate_l3 (outer_ip6, outer_new_addr);
491  if (has_ip6_address (&outer_new_addr[VLIB_TX]))
492  {
493  sum = ip_csum_add_even (sum, outer_new_addr[VLIB_TX].as_u64[0]);
494  sum = ip_csum_add_even (sum, outer_new_addr[VLIB_TX].as_u64[1]);
495  sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_TX].as_u64[0]);
496  sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_TX].as_u64[1]);
497  }
498 
499  if (has_ip6_address (&outer_new_addr[VLIB_RX]))
500  {
501  sum = ip_csum_add_even (sum, outer_new_addr[VLIB_RX].as_u64[0]);
502  sum = ip_csum_add_even (sum, outer_new_addr[VLIB_RX].as_u64[1]);
503  sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_RX].as_u64[0]);
504  sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_RX].as_u64[1]);
505  }
506 
507  /* Translate inner TCP / UDP */
508  if (ip6->protocol == IP_PROTOCOL_TCP)
509  {
510  inner_l4_old_sum = inner_l4_sum = tcp->checksum;
511  cnat_ip6_translate_l4 (ip6, udp, &inner_l4_sum, new_addr, new_port);
512  tcp->checksum = ip_csum_fold (inner_l4_sum);
513  }
514  else if (ip6->protocol == IP_PROTOCOL_UDP)
515  {
516  inner_l4_old_sum = inner_l4_sum = udp->checksum;
517  cnat_ip6_translate_l4 (ip6, udp, &inner_l4_sum, new_addr, new_port);
518  udp->checksum = ip_csum_fold (inner_l4_sum);
519  }
520  else
521  return;
522 
523  /* UDP/TCP checksum changed */
524  sum = ip_csum_update (sum, inner_l4_old_sum, inner_l4_sum,
525  ip4_header_t /* cheat */ ,
526  checksum);
527 
528  /* UDP/TCP Ports changed */
529  if (old_port[VLIB_TX] && new_port[VLIB_TX])
530  sum = ip_csum_update (sum, old_port[VLIB_TX], new_port[VLIB_TX],
531  ip4_header_t /* cheat */ ,
532  length /* changed member */ );
533 
534  if (old_port[VLIB_RX] && new_port[VLIB_RX])
535  sum = ip_csum_update (sum, old_port[VLIB_RX], new_port[VLIB_RX],
536  ip4_header_t /* cheat */ ,
537  length /* changed member */ );
538 
539 
540  cnat_ip6_translate_l3 (ip6, new_addr);
541  /* IP src/dst addr changed */
542  if (has_ip6_address (&new_addr[VLIB_TX]))
543  {
544  sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[0]);
545  sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[1]);
546  sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[0]);
547  sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[1]);
548  }
549 
550  if (has_ip6_address (&new_addr[VLIB_RX]))
551  {
552  sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[0]);
553  sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[1]);
554  sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[0]);
555  sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[1]);
556  }
557 
558  icmp->checksum = ip_csum_fold (sum);
559 }
560 
563  ip6_header_t * ip6, udp_header_t * udp)
564 {
565  tcp_header_t *tcp = (tcp_header_t *) udp;
566  ip6_address_t new_addr[VLIB_N_DIR];
567  u16 new_port[VLIB_N_DIR];
568 
569  ip6_address_copy (&new_addr[VLIB_TX], &session->value.cs_ip[VLIB_TX].ip6);
570  ip6_address_copy (&new_addr[VLIB_RX], &session->value.cs_ip[VLIB_RX].ip6);
571  new_port[VLIB_TX] = session->value.cs_port[VLIB_TX];
572  new_port[VLIB_RX] = session->value.cs_port[VLIB_RX];
573 
574  if (ip6->protocol == IP_PROTOCOL_TCP)
575  {
576  ip_csum_t sum = tcp->checksum;
577  cnat_ip6_translate_l4 (ip6, udp, &sum, new_addr, new_port);
578  tcp->checksum = ip_csum_fold (sum);
579  cnat_ip6_translate_l3 (ip6, new_addr);
581  }
582  else if (ip6->protocol == IP_PROTOCOL_UDP)
583  {
584  ip_csum_t sum = udp->checksum;
585  cnat_ip6_translate_l4 (ip6, udp, &sum, new_addr, new_port);
586  udp->checksum = ip_csum_fold (sum);
587  cnat_ip6_translate_l3 (ip6, new_addr);
588  }
589  else if (ip6->protocol == IP_PROTOCOL_ICMP6)
590  {
591  icmp46_header_t *icmp = (icmp46_header_t *) udp;
592  if (icmp6_type_is_error_message (icmp->type))
593  {
594  /* SNAT only if src_addr was translated */
595  u8 snat_outer_ip = cmp_ip6_address (&ip6->src_address,
596  &session->key.
597  cs_ip[VLIB_RX].ip6);
598  cnat_translation_icmp6_error (ip6, icmp, new_addr, new_port,
599  snat_outer_ip);
600  }
601  else if (icmp6_type_is_echo (icmp->type))
602  cnat_translation_icmp6_echo (ip6, icmp, new_addr, new_port);
603  }
604 }
605 
608  clib_bihash_kv_40_48_t * bkey)
609 {
610  udp_header_t *udp;
611  cnat_session_t *session = (cnat_session_t *) bkey;
612  session->key.cs_af = af;
613  session->key.__cs_pad[0] = 0;
614  session->key.__cs_pad[1] = 0;
615  if (AF_IP4 == af)
616  {
617  ip4_header_t *ip4;
618  ip4 = vlib_buffer_get_current (b);
619  if (PREDICT_FALSE (ip4->protocol == IP_PROTOCOL_ICMP))
620  {
621  icmp46_header_t *icmp = (icmp46_header_t *) (ip4 + 1);
622  if (icmp_type_is_error_message (icmp->type))
623  {
624  ip4 = (ip4_header_t *) (icmp + 2); /* Use inner packet */
625  udp = (udp_header_t *) (ip4 + 1);
626  /* Swap dst & src for search as ICMP payload is reversed */
628  &ip4->dst_address);
630  &ip4->src_address);
631  session->key.cs_proto = ip4->protocol;
632  session->key.cs_port[VLIB_TX] = udp->src_port;
633  session->key.cs_port[VLIB_RX] = udp->dst_port;
634  }
635  else if (icmp_type_is_echo (icmp->type))
636  {
637  cnat_echo_header_t *echo = (cnat_echo_header_t *) (icmp + 1);
639  &ip4->dst_address);
641  &ip4->src_address);
642  session->key.cs_proto = ip4->protocol;
643  session->key.cs_port[VLIB_TX] = echo->identifier;
644  session->key.cs_port[VLIB_RX] = echo->identifier;
645  }
646  else
647  goto error;
648  }
649  else
650  {
651  udp = (udp_header_t *) (ip4 + 1);
653  &ip4->dst_address);
655  &ip4->src_address);
656  session->key.cs_proto = ip4->protocol;
657  session->key.cs_port[VLIB_RX] = udp->src_port;
658  session->key.cs_port[VLIB_TX] = udp->dst_port;
659  }
660 
661  }
662  else
663  {
664  ip6_header_t *ip6;
665  ip6 = vlib_buffer_get_current (b);
666  if (PREDICT_FALSE (ip6->protocol == IP_PROTOCOL_ICMP6))
667  {
668  icmp46_header_t *icmp = (icmp46_header_t *) (ip6 + 1);
669  if (icmp6_type_is_error_message (icmp->type))
670  {
671  ip6 = (ip6_header_t *) (icmp + 2); /* Use inner packet */
672  udp = (udp_header_t *) (ip6 + 1);
673  /* Swap dst & src for search as ICMP payload is reversed */
675  &ip6->dst_address);
677  &ip6->src_address);
678  session->key.cs_proto = ip6->protocol;
679  session->key.cs_port[VLIB_TX] = udp->src_port;
680  session->key.cs_port[VLIB_RX] = udp->dst_port;
681  }
682  else if (icmp6_type_is_echo (icmp->type))
683  {
684  cnat_echo_header_t *echo = (cnat_echo_header_t *) (icmp + 1);
686  &ip6->dst_address);
688  &ip6->src_address);
689  session->key.cs_proto = ip6->protocol;
690  session->key.cs_port[VLIB_TX] = echo->identifier;
691  session->key.cs_port[VLIB_RX] = echo->identifier;
692  }
693  else
694  goto error;
695  }
696  else
697  {
698  udp = (udp_header_t *) (ip6 + 1);
700  &ip6->dst_address);
702  &ip6->src_address);
703  session->key.cs_port[VLIB_RX] = udp->src_port;
704  session->key.cs_port[VLIB_TX] = udp->dst_port;
705  session->key.cs_proto = ip6->protocol;
706  }
707  }
708  return;
709 
710 error:
711  /* Ensure we dont find anything */
712  session->key.cs_proto = 0;
713  return;
714 }
715 
716 /**
717  * Create NAT sessions
718  */
719 
722  u8 rsession_flags)
723 {
724  cnat_client_t *cc;
726  cnat_session_t *rsession = (cnat_session_t *) & rkey;
728  clib_bihash_kv_40_48_t rvalue;
729  int rv;
730 
731  session->value.cs_ts_index = cnat_timestamp_new (ctx->now);
732  clib_bihash_add_del_40_48 (&cnat_session_db, bkey, 1);
733 
734  /* is this the first time we've seen this source address */
735  cc = (AF_IP4 == ctx->af ?
736  cnat_client_ip4_find (&session->value.cs_ip[VLIB_RX].ip4) :
737  cnat_client_ip6_find (&session->value.cs_ip[VLIB_RX].ip6));
738 
739  if (NULL == cc)
740  {
741  u64 r0 = 17;
742  if (AF_IP4 == ctx->af)
743  r0 = (u64) session->value.cs_ip[VLIB_RX].ip4.as_u32;
744  else
745  {
746  r0 = r0 * 31 + session->value.cs_ip[VLIB_RX].ip6.as_u64[0];
747  r0 = r0 * 31 + session->value.cs_ip[VLIB_RX].ip6.as_u64[1];
748  }
749 
750  /* Rate limit */
751  if (!throttle_check (&cnat_throttle, ctx->thread_index, r0, ctx->seed))
752  {
754  l.addr.version = ctx->af;
755  ip46_address_copy (&l.addr.ip, &session->value.cs_ip[VLIB_RX]);
756  /* fire client create to the main thread */
758  (u8 *) & l, sizeof (l));
759  }
760  else
761  {
762  /* Will still need to count those for session refcnt */
765  [ctx->thread_index]);
767  addr->version = ctx->af;
768  ip46_address_copy (&addr->ip, &session->value.cs_ip[VLIB_RX]);
770  [ctx->thread_index]);
771  }
772  }
773  else
774  {
775  /* Refcount reverse session */
777  }
778 
779  /* create the reverse flow key */
780  ip46_address_copy (&rsession->key.cs_ip[VLIB_RX],
781  &session->value.cs_ip[VLIB_TX]);
782  ip46_address_copy (&rsession->key.cs_ip[VLIB_TX],
783  &session->value.cs_ip[VLIB_RX]);
784  rsession->key.cs_proto = session->key.cs_proto;
785  rsession->key.__cs_pad[0] = 0;
786  rsession->key.__cs_pad[1] = 0;
787  rsession->key.cs_af = ctx->af;
788  rsession->key.cs_port[VLIB_RX] = session->value.cs_port[VLIB_TX];
789  rsession->key.cs_port[VLIB_TX] = session->value.cs_port[VLIB_RX];
790 
791  /* First search for existing reverse session */
792  rv = clib_bihash_search_inline_2_40_48 (&cnat_session_db, &rkey, &rvalue);
793  if (!rv)
794  {
795  /* Reverse session already exists
796  cleanup before creating for refcnts */
797  cnat_session_t *found_rsession = (cnat_session_t *) & rvalue;
798  cnat_session_free (found_rsession);
799  }
800  /* add the reverse flow */
801  ip46_address_copy (&rsession->value.cs_ip[VLIB_RX],
802  &session->key.cs_ip[VLIB_TX]);
803  ip46_address_copy (&rsession->value.cs_ip[VLIB_TX],
804  &session->key.cs_ip[VLIB_RX]);
805  rsession->value.cs_ts_index = session->value.cs_ts_index;
806  rsession->value.cs_lbi = INDEX_INVALID;
807  rsession->value.flags = rsession_flags;
808  rsession->value.cs_port[VLIB_TX] = session->key.cs_port[VLIB_RX];
809  rsession->value.cs_port[VLIB_RX] = session->key.cs_port[VLIB_TX];
810 
811  clib_bihash_add_del_40_48 (&cnat_session_db, &rkey, 1);
812 }
813 
818  cnat_node_sub_t cnat_sub,
819  ip_address_family_t af, u8 do_trace)
820 {
821  u32 n_left, *from, thread_index;
823  vlib_buffer_t **b = bufs;
824  u16 nexts[VLIB_FRAME_SIZE], *next;
825  f64 now;
826  u64 seed;
827 
828  thread_index = vm->thread_index;
829  from = vlib_frame_vector_args (frame);
830  n_left = frame->n_vectors;
831  next = nexts;
832  vlib_get_buffers (vm, from, bufs, n_left);
833  now = vlib_time_now (vm);
834  seed = throttle_seed (&cnat_throttle, thread_index, vlib_time_now (vm));
835  cnat_session_t *session[4];
836  clib_bihash_kv_40_48_t bkey[4], bvalue[4];
837  u64 hash[4];
838  int rv[4];
839 
840  cnat_node_ctx_t ctx = { now, seed, thread_index, af, do_trace };
841 
842  if (n_left >= 8)
843  {
844  /* Kickstart our state */
845  cnat_session_make_key (b[3], af, &bkey[3]);
846  cnat_session_make_key (b[2], af, &bkey[2]);
847  cnat_session_make_key (b[1], af, &bkey[1]);
848  cnat_session_make_key (b[0], af, &bkey[0]);
849 
850  hash[3] = clib_bihash_hash_40_48 (&bkey[3]);
851  hash[2] = clib_bihash_hash_40_48 (&bkey[2]);
852  hash[1] = clib_bihash_hash_40_48 (&bkey[1]);
853  hash[0] = clib_bihash_hash_40_48 (&bkey[0]);
854  }
855 
856  while (n_left >= 8)
857  {
858  if (n_left >= 12)
859  {
860  vlib_prefetch_buffer_header (b[11], LOAD);
861  vlib_prefetch_buffer_header (b[10], LOAD);
862  vlib_prefetch_buffer_header (b[9], LOAD);
863  vlib_prefetch_buffer_header (b[8], LOAD);
864  }
865 
866  rv[3] =
867  clib_bihash_search_inline_2_with_hash_40_48 (&cnat_session_db,
868  hash[3], &bkey[3],
869  &bvalue[3]);
870  session[3] = (cnat_session_t *) (rv[3] ? &bkey[3] : &bvalue[3]);
871  next[3] = cnat_sub (vm, node, b[3], &ctx, rv[3], session[3]);
872 
873  rv[2] =
874  clib_bihash_search_inline_2_with_hash_40_48 (&cnat_session_db,
875  hash[2], &bkey[2],
876  &bvalue[2]);
877  session[2] = (cnat_session_t *) (rv[2] ? &bkey[2] : &bvalue[2]);
878  next[2] = cnat_sub (vm, node, b[2], &ctx, rv[2], session[2]);
879 
880  rv[1] =
881  clib_bihash_search_inline_2_with_hash_40_48 (&cnat_session_db,
882  hash[1], &bkey[1],
883  &bvalue[1]);
884  session[1] = (cnat_session_t *) (rv[1] ? &bkey[1] : &bvalue[1]);
885  next[1] = cnat_sub (vm, node, b[1], &ctx, rv[1], session[1]);
886 
887  rv[0] =
888  clib_bihash_search_inline_2_with_hash_40_48 (&cnat_session_db,
889  hash[0], &bkey[0],
890  &bvalue[0]);
891  session[0] = (cnat_session_t *) (rv[0] ? &bkey[0] : &bvalue[0]);
892  next[0] = cnat_sub (vm, node, b[0], &ctx, rv[0], session[0]);
893 
894  cnat_session_make_key (b[7], af, &bkey[3]);
895  cnat_session_make_key (b[6], af, &bkey[2]);
896  cnat_session_make_key (b[5], af, &bkey[1]);
897  cnat_session_make_key (b[4], af, &bkey[0]);
898 
899  hash[3] = clib_bihash_hash_40_48 (&bkey[3]);
900  hash[2] = clib_bihash_hash_40_48 (&bkey[2]);
901  hash[1] = clib_bihash_hash_40_48 (&bkey[1]);
902  hash[0] = clib_bihash_hash_40_48 (&bkey[0]);
903 
904  clib_bihash_prefetch_bucket_40_48 (&cnat_session_db, hash[3]);
905  clib_bihash_prefetch_bucket_40_48 (&cnat_session_db, hash[2]);
906  clib_bihash_prefetch_bucket_40_48 (&cnat_session_db, hash[1]);
907  clib_bihash_prefetch_bucket_40_48 (&cnat_session_db, hash[0]);
908 
909  clib_bihash_prefetch_data_40_48 (&cnat_session_db, hash[3]);
910  clib_bihash_prefetch_data_40_48 (&cnat_session_db, hash[2]);
911  clib_bihash_prefetch_data_40_48 (&cnat_session_db, hash[1]);
912  clib_bihash_prefetch_data_40_48 (&cnat_session_db, hash[0]);
913 
914  b += 4;
915  next += 4;
916  n_left -= 4;
917  }
918 
919  while (n_left > 0)
920  {
921  cnat_session_make_key (b[0], af, &bkey[0]);
922  rv[0] = clib_bihash_search_inline_2_40_48 (&cnat_session_db,
923  &bkey[0], &bvalue[0]);
924 
925  session[0] = (cnat_session_t *) (rv[0] ? &bkey[0] : &bvalue[0]);
926  next[0] = cnat_sub (vm, node, b[0], &ctx, rv[0], session[0]);
927 
928  b++;
929  next++;
930  n_left--;
931  }
932 
933  vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
934 
935  return frame->n_vectors;
936 }
937 
938 /*
939  * fd.io coding-style-patch-verification: ON
940  *
941  * Local Variables:
942  * eval: (c-set-style "gnu")
943  * End:
944  */
945 
946 #endif
static_always_inline void cnat_translation_icmp6_echo(ip6_header_t *ip6, icmp46_header_t *icmp, ip6_address_t new_addr[VLIB_N_DIR], u16 new_port[VLIB_N_DIR])
Definition: cnat_node.h:413
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:121
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:82
ip_address_t ** throttle_pool
Definition: cnat_client.h:147
a
Definition: bitmap.h:544
ip4_address_t src_address
Definition: ip4_packet.h:125
#define tcp_rst(_th)
Definition: tcp_packet.h:81
static_always_inline u8 cmp_ip6_address(const ip6_address_t *a1, const ip6_address_t *a2)
Definition: cnat_node.h:84
u64 as_u64
Definition: bihash_doc.h:63
#define PREDICT_TRUE(x)
Definition: clib.h:122
unsigned long u64
Definition: types.h:89
struct cnat_session_t_::@632 key
this key sits in the same memory location a &#39;key&#39; in the bihash kvp
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:334
throttle_t cnat_throttle
Definition: cnat_types.c:21
uword(* cnat_node_sub_t)(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b, cnat_node_ctx_t *ctx, int rv, cnat_session_t *session)
Definition: cnat_node.h:24
u16 cs_port[VLIB_N_DIR]
ports in rx/tx
Definition: cnat_session.h:53
u32 thread_index
Definition: main.h:250
ip46_address_t ip
Definition: ip_types.h:81
static u64 clib_bihash_hash_40_48(const clib_bihash_kv_40_48_t *v)
Definition: bihash_40_48.h:55
static_always_inline void cnat_translation_icmp4_error(ip4_header_t *outer_ip4, icmp46_header_t *icmp, ip4_address_t outer_new_addr[VLIB_N_DIR], u16 outer_new_port[VLIB_N_DIR], u8 snat_outer_ip)
Definition: cnat_node.h:219
uword ip_csum_t
Definition: ip_packet.h:246
vlib_main_t * vm
Definition: in2out_ed.c:1580
static u32 cnat_timestamp_new(f64 t)
Definition: cnat_inline.h:23
#define tcp_fin(_th)
Definition: tcp_packet.h:79
static_always_inline void ip46_address_set_ip6(ip46_address_t *dst, const ip6_address_t *src)
Definition: ip46_address.h:130
static_always_inline void cnat_tcp_update_session_lifetime(tcp_header_t *tcp, u32 index)
Definition: cnat_node.h:178
void cnat_session_free(cnat_session_t *session)
Free a session & update refcounts.
Definition: cnat_session.c:127
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:251
struct _tcp_header tcp_header_t
vhost_vring_addr_t addr
Definition: vhost_user.h:111
clib_bihash_40_48_t cnat_session_db
The DB of sessions.
Definition: cnat_session.c:24
ip6_address_t src_address
Definition: ip6_packet.h:310
unsigned char u8
Definition: types.h:56
static_always_inline void cnat_ip6_translate_l4(ip6_header_t *ip6, udp_header_t *udp, ip_csum_t *sum, ip6_address_t new_addr[VLIB_N_DIR], u16 new_port[VLIB_N_DIR])
Definition: cnat_node.h:359
static_always_inline u8 icmp_type_is_error_message(u8 icmp_type)
Definition: cnat_node.h:31
double f64
Definition: types.h:142
static void cnat_timestamp_set_lifetime(u32 index, u16 lifetime)
Definition: cnat_inline.h:56
A session represents the memory of a translation.
Definition: cnat_session.h:38
u8 cs_af
The address family describing the IP addresses.
Definition: cnat_session.h:63
#define static_always_inline
Definition: clib.h:109
vl_api_ip6_address_t ip6
Definition: one.api:424
ip4_address_t dst_address
Definition: ip4_packet.h:125
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:207
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: vlib_api.c:619
const cJSON *const b
Definition: cJSON.h:255
unsigned int u32
Definition: types.h:88
static_always_inline void cnat_ip4_translate_l4(ip4_header_t *ip4, udp_header_t *udp, ip_csum_t *sum, ip4_address_t new_addr[VLIB_N_DIR], u16 new_port[VLIB_N_DIR])
Definition: cnat_node.h:101
#define VLIB_FRAME_SIZE
Definition: node.h:378
ip46_address_t cs_ip[VLIB_N_DIR]
IP 4/6 address in the rx/tx direction.
Definition: cnat_session.h:48
u32 cs_ts_index
Timestamp index this session was last used.
Definition: cnat_session.h:93
static_always_inline u32 cnat_client_cnt_session(cnat_client_t *cc)
Add a session refcnt to this client.
Definition: cnat_client.h:202
vnet_crypto_main_t * cm
Definition: quic_crypto.c:53
Definition: cJSON.c:84
static_always_inline void ip46_address_copy(ip46_address_t *dst, const ip46_address_t *src)
Definition: ip46_address.h:123
icmp
Definition: map.api:387
long ctx[MAX_CONNS]
Definition: main.c:144
unsigned short u16
Definition: types.h:57
ip_address_t addr
Definition: cnat_client.h:98
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:233
static u64 throttle_seed(throttle_t *t, u32 thread_index, f64 time_now)
Definition: throttle.h:41
#define PREDICT_FALSE(x)
Definition: clib.h:121
#define always_inline
Definition: ipsec.h:28
vl_api_ip4_address_t ip4
Definition: one.api:376
static_always_inline cnat_client_t * cnat_client_ip4_find(const ip4_address_t *ip)
Find a client from an IP4 address.
Definition: cnat_client.h:157
vl_api_address_union_t src_address
Definition: ip_types.api:122
static_always_inline void cnat_translation_ip6(const cnat_session_t *session, ip6_header_t *ip6, udp_header_t *udp)
Definition: cnat_node.h:562
static_always_inline u8 icmp6_type_is_error_message(u8 icmp_type)
Definition: cnat_node.h:71
static_always_inline u8 icmp6_type_is_echo(u8 icmp_type)
Definition: cnat_node.h:59
ip_address_family_t af
Definition: cnat_types.h:164
static_always_inline void cnat_session_make_key(vlib_buffer_t *b, ip_address_family_t af, clib_bihash_kv_40_48_t *bkey)
Definition: cnat_node.h:607
static_always_inline void cnat_ip6_translate_l3(ip6_header_t *ip6, ip6_address_t new_addr[VLIB_N_DIR])
Definition: cnat_node.h:350
u16 n_vectors
Definition: node.h:397
clib_spinlock_t * throttle_pool_lock
Definition: cnat_client.h:148
static_always_inline void vlib_buffer_enqueue_to_next(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, u16 *nexts, uword count)
Definition: buffer_node.h:339
static_always_inline void cnat_ip4_translate_l3(ip4_header_t *ip4, ip4_address_t new_addr[VLIB_N_DIR])
Definition: cnat_node.h:151
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1580
#define tcp_syn(_th)
Definition: tcp_packet.h:80
static_always_inline void cnat_translation_ip4(const cnat_session_t *session, ip4_header_t *ip4, udp_header_t *udp)
Definition: cnat_node.h:305
void cnat_client_learn(const cnat_learn_arg_t *l)
Called in the main thread by RPC from the workers to learn a new client.
Definition: cnat_client.c:202
#define CNAT_DEFAULT_TCP_RST_TIMEOUT
Definition: cnat_types.h:34
static ip_csum_t ip_csum_sub_even(ip_csum_t c, ip_csum_t x)
Definition: ip_packet.h:274
#define VLIB_N_DIR
Definition: defs.h:57
ip_address_family_t version
Definition: ip_types.h:82
char const int length
Definition: cJSON.h:163
static_always_inline u8 icmp_type_is_echo(u8 icmp_type)
Definition: cnat_node.h:47
static_always_inline cnat_client_t * cnat_client_ip6_find(const ip6_address_t *ip)
Find a client from an IP6 address.
Definition: cnat_client.h:186
enum ip_address_family_t_ ip_address_family_t
static_always_inline void cnat_translation_icmp6_error(ip6_header_t *outer_ip6, icmp46_header_t *icmp, ip6_address_t outer_new_addr[VLIB_N_DIR], u16 outer_new_port[VLIB_N_DIR], u8 snat_outer_ip)
Definition: cnat_node.h:453
static_always_inline void cnat_translation_icmp4_echo(ip4_header_t *ip4, icmp46_header_t *icmp, ip4_address_t new_addr[VLIB_N_DIR], u16 new_port[VLIB_N_DIR])
Definition: cnat_node.h:198
Definition: defs.h:47
ip_protocol_t cs_proto
The IP protocol TCP or UDP only supported.
Definition: cnat_session.h:58
#define INDEX_INVALID
Invalid index - used when no index is known blazoned capitals INVALID speak volumes where ~0 does not...
Definition: dpo.h:47
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1581
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:297
cnat_main_t cnat_main
Definition: cnat_types.c:18
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:296
u32 index
Definition: flow_types.api:221
static void ip6_address_copy(ip6_address_t *dst, const ip6_address_t *src)
Definition: ip6_packet.h:127
cnat_client_db_t cnat_client_db
Definition: cnat_client.c:24
u32 tcp_max_age
Definition: cnat_types.h:122
static_always_inline void cnat_session_create(cnat_session_t *session, cnat_node_ctx_t *ctx, u8 rsession_flags)
Create NAT sessions.
Definition: cnat_node.h:721
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 tcp_ack(_th)
Definition: tcp_packet.h:83
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:302
static void ip46_address_set_ip4(ip46_address_t *ip46, const ip4_address_t *ip)
Definition: ip46_address.h:67
static uword cnat_node_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, cnat_node_sub_t cnat_sub, ip_address_family_t af, u8 do_trace)
Definition: cnat_node.h:815
Definition: defs.h:46
static ip_csum_t ip_csum_add_even(ip_csum_t c, ip_csum_t x)
Definition: ip_packet.h:257
struct cnat_session_t_::@633 value
this value sits in the same memory location a &#39;value&#39; in the bihash kvp
ip6_address_t dst_address
Definition: ip6_packet.h:310
A client is a representation of an IP address behind the NAT.
Definition: cnat_client.h:35
static_always_inline u8 has_ip6_address(ip6_address_t *a)
Inline translation functions.
Definition: cnat_node.h:95
static int throttle_check(throttle_t *t, u32 thread_index, u64 hash, u64 seed)
Definition: throttle.h:54