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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #ifndef __CNAT_NODE_H__
17 #define __CNAT_NODE_H__
19 #include <vlibmemory/api.h>
20 #include <cnat/cnat_session.h>
21 #include <cnat/cnat_client.h>
23 typedef uword (*cnat_node_sub_t) (vlib_main_t * vm,
24 vlib_node_runtime_t * node,
26 cnat_node_ctx_t * ctx, int rv,
27 cnat_session_t * session);
29 static_always_inline u8
30 icmp_type_is_error_message (u8 icmp_type)
34 case ICMP4_destination_unreachable:
35 case ICMP4_time_exceeded:
36 case ICMP4_parameter_problem:
37 case ICMP4_source_quench:
39 case ICMP4_alternate_host_address:
45 static_always_inline u8
46 icmp6_type_is_error_message (u8 icmp_type)
50 case ICMP6_destination_unreachable:
51 case ICMP6_time_exceeded:
52 case ICMP6_parameter_problem:
58 static_always_inline u8
59 cmp_ip6_address (const ip6_address_t * a1, const ip6_address_t * a2)
61 return ((a1->as_u64[0] == a2->as_u64[0])
62 && (a1->as_u64[1] == a2->as_u64[1]));
66 * Inline translation functions
69 static_always_inline u8
70 has_ip6_address (ip6_address_t * a)
72 return ((0 != a->as_u64[0]) || (0 != a->as_u64[1]));
75 static_always_inline void
76 cnat_ip4_translate_l4 (ip4_header_t * ip4, udp_header_t * udp,
78 ip4_address_t new_addr[VLIB_N_DIR],
79 u16 new_port[VLIB_N_DIR])
81 u16 old_port[VLIB_N_DIR];
82 ip4_address_t old_addr[VLIB_N_DIR];
84 /* Fastpath no checksum */
85 if (PREDICT_TRUE (0 == *sum))
87 udp->dst_port = new_port[VLIB_TX];
88 udp->src_port = new_port[VLIB_RX];
92 old_port[VLIB_TX] = udp->dst_port;
93 old_port[VLIB_RX] = udp->src_port;
94 old_addr[VLIB_TX] = ip4->dst_address;
95 old_addr[VLIB_RX] = ip4->src_address;
97 if (new_addr[VLIB_TX].as_u32)
100 ip_csum_update (*sum, old_addr[VLIB_TX].as_u32,
101 new_addr[VLIB_TX].as_u32, ip4_header_t, dst_address);
103 if (new_port[VLIB_TX])
105 udp->dst_port = new_port[VLIB_TX];
106 *sum = ip_csum_update (*sum, old_port[VLIB_TX], new_port[VLIB_TX],
107 ip4_header_t /* cheat */ ,
108 length /* changed member */ );
110 if (new_addr[VLIB_RX].as_u32)
113 ip_csum_update (*sum, old_addr[VLIB_RX].as_u32,
114 new_addr[VLIB_RX].as_u32, ip4_header_t, src_address);
116 if (new_port[VLIB_RX])
118 udp->src_port = new_port[VLIB_RX];
119 *sum = ip_csum_update (*sum, old_port[VLIB_RX], new_port[VLIB_RX],
120 ip4_header_t /* cheat */ ,
121 length /* changed member */ );
125 static_always_inline void
126 cnat_ip4_translate_l3 (ip4_header_t * ip4, ip4_address_t new_addr[VLIB_N_DIR])
128 ip4_address_t old_addr[VLIB_N_DIR];
131 old_addr[VLIB_TX] = ip4->dst_address;
132 old_addr[VLIB_RX] = ip4->src_address;
135 if (new_addr[VLIB_TX].as_u32)
137 ip4->dst_address = new_addr[VLIB_TX];
139 ip_csum_update (sum, old_addr[VLIB_TX].as_u32,
140 new_addr[VLIB_TX].as_u32, ip4_header_t, dst_address);
142 if (new_addr[VLIB_RX].as_u32)
144 ip4->src_address = new_addr[VLIB_RX];
146 ip_csum_update (sum, old_addr[VLIB_RX].as_u32,
147 new_addr[VLIB_RX].as_u32, ip4_header_t, src_address);
149 ip4->checksum = ip_csum_fold (sum);
152 static_always_inline void
153 cnat_tcp_update_session_lifetime (tcp_header_t * tcp, u32 index)
155 cnat_main_t *cm = &cnat_main;
156 if (PREDICT_FALSE (tcp_fin (tcp)))
158 cnat_timestamp_set_lifetime (index, CNAT_DEFAULT_TCP_RST_TIMEOUT);
161 if (PREDICT_FALSE (tcp_rst (tcp)))
163 cnat_timestamp_set_lifetime (index, CNAT_DEFAULT_TCP_RST_TIMEOUT);
166 if (PREDICT_FALSE (tcp_syn (tcp) && tcp_ack (tcp)))
168 cnat_timestamp_set_lifetime (index, cm->tcp_max_age);
172 static_always_inline void
173 cnat_translation_icmp4 (ip4_header_t * outer_ip4, udp_header_t * outer_udp,
174 ip4_address_t outer_new_addr[VLIB_N_DIR],
175 u16 outer_new_port[VLIB_N_DIR], u8 snat_outer_ip)
177 icmp46_header_t *icmp = (icmp46_header_t *) outer_udp;
178 ip4_address_t new_addr[VLIB_N_DIR];
179 ip4_address_t old_addr[VLIB_N_DIR];
180 u16 new_port[VLIB_N_DIR];
181 u16 old_port[VLIB_N_DIR];
182 ip_csum_t sum, old_ip_sum, inner_l4_sum, inner_l4_old_sum;
184 if (!icmp_type_is_error_message (icmp->type))
187 ip4_header_t *ip4 = (ip4_header_t *) (icmp + 2);
188 udp_header_t *udp = (udp_header_t *) (ip4 + 1);
189 tcp_header_t *tcp = (tcp_header_t *) udp;
191 /* Swap inner ports */
192 new_addr[VLIB_TX] = outer_new_addr[VLIB_RX];
193 new_addr[VLIB_RX] = outer_new_addr[VLIB_TX];
194 new_port[VLIB_TX] = outer_new_port[VLIB_RX];
195 new_port[VLIB_RX] = outer_new_port[VLIB_TX];
197 old_addr[VLIB_TX] = ip4->dst_address;
198 old_addr[VLIB_RX] = ip4->src_address;
199 old_port[VLIB_RX] = udp->src_port;
200 old_port[VLIB_TX] = udp->dst_port;
202 sum = icmp->checksum;
203 old_ip_sum = ip4->checksum;
205 /* translate outer ip. */
207 outer_new_addr[VLIB_RX] = outer_ip4->src_address;
208 cnat_ip4_translate_l3 (outer_ip4, outer_new_addr);
210 if (ip4->protocol == IP_PROTOCOL_TCP)
212 inner_l4_old_sum = inner_l4_sum = tcp->checksum;
213 cnat_ip4_translate_l4 (ip4, udp, &inner_l4_sum, new_addr, new_port);
214 tcp->checksum = ip_csum_fold (inner_l4_sum);
216 else if (ip4->protocol == IP_PROTOCOL_UDP)
218 inner_l4_old_sum = inner_l4_sum = udp->checksum;
219 cnat_ip4_translate_l4 (ip4, udp, &inner_l4_sum, new_addr, new_port);
220 udp->checksum = ip_csum_fold (inner_l4_sum);
225 /* UDP/TCP checksum changed */
226 sum = ip_csum_update (sum, inner_l4_old_sum, inner_l4_sum,
227 ip4_header_t, checksum);
229 /* UDP/TCP Ports changed */
230 if (old_port[VLIB_TX] && new_port[VLIB_TX])
231 sum = ip_csum_update (sum, old_port[VLIB_TX], new_port[VLIB_TX],
232 ip4_header_t /* cheat */ ,
233 length /* changed member */ );
235 if (old_port[VLIB_RX] && new_port[VLIB_RX])
236 sum = ip_csum_update (sum, old_port[VLIB_RX], new_port[VLIB_RX],
237 ip4_header_t /* cheat */ ,
238 length /* changed member */ );
241 cnat_ip4_translate_l3 (ip4, new_addr);
242 ip_csum_t new_ip_sum = ip4->checksum;
243 /* IP checksum changed */
244 sum = ip_csum_update (sum, old_ip_sum, new_ip_sum, ip4_header_t, checksum);
246 /* IP src/dst addr changed */
247 if (new_addr[VLIB_TX].as_u32)
249 ip_csum_update (sum, old_addr[VLIB_TX].as_u32, new_addr[VLIB_TX].as_u32,
250 ip4_header_t, dst_address);
252 if (new_addr[VLIB_RX].as_u32)
254 ip_csum_update (sum, old_addr[VLIB_RX].as_u32, new_addr[VLIB_RX].as_u32,
255 ip4_header_t, src_address);
257 icmp->checksum = ip_csum_fold (sum);
260 static_always_inline void
261 cnat_translation_ip4 (const cnat_session_t * session,
262 ip4_header_t * ip4, udp_header_t * udp)
264 tcp_header_t *tcp = (tcp_header_t *) udp;
265 ip4_address_t new_addr[VLIB_N_DIR];
266 u16 new_port[VLIB_N_DIR];
268 new_addr[VLIB_TX] = session->value.cs_ip[VLIB_TX].ip4;
269 new_addr[VLIB_RX] = session->value.cs_ip[VLIB_RX].ip4;
270 new_port[VLIB_TX] = session->value.cs_port[VLIB_TX];
271 new_port[VLIB_RX] = session->value.cs_port[VLIB_RX];
273 if (ip4->protocol == IP_PROTOCOL_TCP)
275 ip_csum_t sum = tcp->checksum;
276 cnat_ip4_translate_l4 (ip4, udp, &sum, new_addr, new_port);
277 tcp->checksum = ip_csum_fold (sum);
278 cnat_ip4_translate_l3 (ip4, new_addr);
279 cnat_tcp_update_session_lifetime (tcp, session->value.cs_ts_index);
281 else if (ip4->protocol == IP_PROTOCOL_UDP)
283 ip_csum_t sum = udp->checksum;
284 cnat_ip4_translate_l4 (ip4, udp, &sum, new_addr, new_port);
285 udp->checksum = ip_csum_fold (sum);
286 cnat_ip4_translate_l3 (ip4, new_addr);
288 else if (ip4->protocol == IP_PROTOCOL_ICMP)
290 /* SNAT only if src_addr was translated */
292 (ip4->src_address.as_u32 == session->key.cs_ip[VLIB_RX].ip4.as_u32);
293 cnat_translation_icmp4 (ip4, udp, new_addr, new_port, snat_outer_ip);
297 static_always_inline void
298 cnat_ip6_translate_l3 (ip6_header_t * ip6, ip6_address_t new_addr[VLIB_N_DIR])
300 if (has_ip6_address (&new_addr[VLIB_TX]))
301 ip6_address_copy (&ip6->dst_address, &new_addr[VLIB_TX]);
302 if (has_ip6_address (&new_addr[VLIB_RX]))
303 ip6_address_copy (&ip6->src_address, &new_addr[VLIB_RX]);
306 static_always_inline void
307 cnat_ip6_translate_l4 (ip6_header_t * ip6, udp_header_t * udp,
309 ip6_address_t new_addr[VLIB_N_DIR],
310 u16 new_port[VLIB_N_DIR])
312 u16 old_port[VLIB_N_DIR];
313 ip6_address_t old_addr[VLIB_N_DIR];
315 /* Fastpath no checksum */
316 if (PREDICT_TRUE (0 == *sum))
318 udp->dst_port = new_port[VLIB_TX];
319 udp->src_port = new_port[VLIB_RX];
323 old_port[VLIB_TX] = udp->dst_port;
324 old_port[VLIB_RX] = udp->src_port;
325 ip6_address_copy (&old_addr[VLIB_TX], &ip6->dst_address);
326 ip6_address_copy (&old_addr[VLIB_RX], &ip6->src_address);
328 if (has_ip6_address (&new_addr[VLIB_TX]))
330 *sum = ip_csum_add_even (*sum, new_addr[VLIB_TX].as_u64[0]);
331 *sum = ip_csum_add_even (*sum, new_addr[VLIB_TX].as_u64[1]);
332 *sum = ip_csum_sub_even (*sum, old_addr[VLIB_TX].as_u64[0]);
333 *sum = ip_csum_sub_even (*sum, old_addr[VLIB_TX].as_u64[1]);
336 if (new_port[VLIB_TX])
338 udp->dst_port = new_port[VLIB_TX];
339 *sum = ip_csum_update (*sum, old_port[VLIB_TX], new_port[VLIB_TX],
340 ip4_header_t /* cheat */ ,
341 length /* changed member */ );
343 if (has_ip6_address (&new_addr[VLIB_RX]))
345 *sum = ip_csum_add_even (*sum, new_addr[VLIB_RX].as_u64[0]);
346 *sum = ip_csum_add_even (*sum, new_addr[VLIB_RX].as_u64[1]);
347 *sum = ip_csum_sub_even (*sum, old_addr[VLIB_RX].as_u64[0]);
348 *sum = ip_csum_sub_even (*sum, old_addr[VLIB_RX].as_u64[1]);
351 if (new_port[VLIB_RX])
353 udp->src_port = new_port[VLIB_RX];
354 *sum = ip_csum_update (*sum, old_port[VLIB_RX], new_port[VLIB_RX],
355 ip4_header_t /* cheat */ ,
356 length /* changed member */ );
360 static_always_inline void
361 cnat_translation_icmp6 (ip6_header_t * outer_ip6, udp_header_t * outer_udp,
362 ip6_address_t outer_new_addr[VLIB_N_DIR],
363 u16 outer_new_port[VLIB_N_DIR], u8 snat_outer_ip)
365 icmp46_header_t *icmp = (icmp46_header_t *) outer_udp;
366 ip6_address_t new_addr[VLIB_N_DIR];
367 ip6_address_t old_addr[VLIB_N_DIR];
368 ip6_address_t outer_old_addr[VLIB_N_DIR];
369 u16 new_port[VLIB_N_DIR];
370 u16 old_port[VLIB_N_DIR];
371 ip_csum_t sum, inner_l4_sum, inner_l4_old_sum;
373 if (!icmp6_type_is_error_message (icmp->type))
376 ip6_header_t *ip6 = (ip6_header_t *) (icmp + 2);
377 udp_header_t *udp = (udp_header_t *) (ip6 + 1);
378 tcp_header_t *tcp = (tcp_header_t *) udp;
380 /* Swap inner ports */
381 ip6_address_copy (&new_addr[VLIB_RX], &outer_new_addr[VLIB_TX]);
382 ip6_address_copy (&new_addr[VLIB_TX], &outer_new_addr[VLIB_RX]);
383 new_port[VLIB_TX] = outer_new_port[VLIB_RX];
384 new_port[VLIB_RX] = outer_new_port[VLIB_TX];
386 ip6_address_copy (&old_addr[VLIB_TX], &ip6->dst_address);
387 ip6_address_copy (&old_addr[VLIB_RX], &ip6->src_address);
388 old_port[VLIB_RX] = udp->src_port;
389 old_port[VLIB_TX] = udp->dst_port;
391 sum = icmp->checksum;
392 /* Translate outer ip */
393 ip6_address_copy (&outer_old_addr[VLIB_TX], &outer_ip6->dst_address);
394 ip6_address_copy (&outer_old_addr[VLIB_RX], &outer_ip6->src_address);
396 ip6_address_copy (&outer_new_addr[VLIB_RX], &outer_ip6->src_address);
397 cnat_ip6_translate_l3 (outer_ip6, outer_new_addr);
398 if (has_ip6_address (&outer_new_addr[VLIB_TX]))
400 sum = ip_csum_add_even (sum, outer_new_addr[VLIB_TX].as_u64[0]);
401 sum = ip_csum_add_even (sum, outer_new_addr[VLIB_TX].as_u64[1]);
402 sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_TX].as_u64[0]);
403 sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_TX].as_u64[1]);
406 if (has_ip6_address (&outer_new_addr[VLIB_RX]))
408 sum = ip_csum_add_even (sum, outer_new_addr[VLIB_RX].as_u64[0]);
409 sum = ip_csum_add_even (sum, outer_new_addr[VLIB_RX].as_u64[1]);
410 sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_RX].as_u64[0]);
411 sum = ip_csum_sub_even (sum, outer_old_addr[VLIB_RX].as_u64[1]);
414 if (ip6->protocol == IP_PROTOCOL_TCP)
416 inner_l4_old_sum = inner_l4_sum = tcp->checksum;
417 cnat_ip6_translate_l4 (ip6, udp, &inner_l4_sum, new_addr, new_port);
418 tcp->checksum = ip_csum_fold (inner_l4_sum);
420 else if (ip6->protocol == IP_PROTOCOL_UDP)
422 inner_l4_old_sum = inner_l4_sum = udp->checksum;
423 cnat_ip6_translate_l4 (ip6, udp, &inner_l4_sum, new_addr, new_port);
424 udp->checksum = ip_csum_fold (inner_l4_sum);
429 /* UDP/TCP checksum changed */
430 sum = ip_csum_update (sum, inner_l4_old_sum, inner_l4_sum,
431 ip4_header_t /* cheat */ ,
434 /* UDP/TCP Ports changed */
435 if (old_port[VLIB_TX] && new_port[VLIB_TX])
436 sum = ip_csum_update (sum, old_port[VLIB_TX], new_port[VLIB_TX],
437 ip4_header_t /* cheat */ ,
438 length /* changed member */ );
440 if (old_port[VLIB_RX] && new_port[VLIB_RX])
441 sum = ip_csum_update (sum, old_port[VLIB_RX], new_port[VLIB_RX],
442 ip4_header_t /* cheat */ ,
443 length /* changed member */ );
446 cnat_ip6_translate_l3 (ip6, new_addr);
447 /* IP src/dst addr changed */
448 if (has_ip6_address (&new_addr[VLIB_TX]))
450 sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[0]);
451 sum = ip_csum_add_even (sum, new_addr[VLIB_TX].as_u64[1]);
452 sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[0]);
453 sum = ip_csum_sub_even (sum, old_addr[VLIB_TX].as_u64[1]);
456 if (has_ip6_address (&new_addr[VLIB_RX]))
458 sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[0]);
459 sum = ip_csum_add_even (sum, new_addr[VLIB_RX].as_u64[1]);
460 sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[0]);
461 sum = ip_csum_sub_even (sum, old_addr[VLIB_RX].as_u64[1]);
464 icmp->checksum = ip_csum_fold (sum);
467 static_always_inline void
468 cnat_translation_ip6 (const cnat_session_t * session,
469 ip6_header_t * ip6, udp_header_t * udp)
471 tcp_header_t *tcp = (tcp_header_t *) udp;
472 ip6_address_t new_addr[VLIB_N_DIR];
473 u16 new_port[VLIB_N_DIR];
475 ip6_address_copy (&new_addr[VLIB_TX], &session->value.cs_ip[VLIB_TX].ip6);
476 ip6_address_copy (&new_addr[VLIB_RX], &session->value.cs_ip[VLIB_RX].ip6);
477 new_port[VLIB_TX] = session->value.cs_port[VLIB_TX];
478 new_port[VLIB_RX] = session->value.cs_port[VLIB_RX];
480 if (ip6->protocol == IP_PROTOCOL_TCP)
482 ip_csum_t sum = tcp->checksum;
483 cnat_ip6_translate_l4 (ip6, udp, &sum, new_addr, new_port);
484 tcp->checksum = ip_csum_fold (sum);
485 cnat_ip6_translate_l3 (ip6, new_addr);
486 cnat_tcp_update_session_lifetime (tcp, session->value.cs_ts_index);
488 else if (ip6->protocol == IP_PROTOCOL_UDP)
490 ip_csum_t sum = udp->checksum;
491 cnat_ip6_translate_l4 (ip6, udp, &sum, new_addr, new_port);
492 udp->checksum = ip_csum_fold (sum);
493 cnat_ip6_translate_l3 (ip6, new_addr);
495 else if (ip6->protocol == IP_PROTOCOL_ICMP6)
497 /* SNAT only if src_addr was translated */
498 u8 snat_outer_ip = cmp_ip6_address (&ip6->src_address,
499 &session->key.cs_ip[VLIB_RX].ip6);
500 cnat_translation_icmp6 (ip6, udp, new_addr, new_port, snat_outer_ip);
504 static_always_inline void
505 cnat_session_make_key (vlib_buffer_t * b, ip_address_family_t af,
506 clib_bihash_kv_40_48_t * bkey)
509 cnat_session_t *session = (cnat_session_t *) bkey;
510 session->key.cs_af = af;
511 session->key.__cs_pad[0] = 0;
512 session->key.__cs_pad[1] = 0;
516 ip4 = vlib_buffer_get_current (b);
517 if (PREDICT_FALSE (ip4->protocol == IP_PROTOCOL_ICMP))
519 icmp46_header_t *icmp = (icmp46_header_t *) (ip4 + 1);
520 if (!icmp_type_is_error_message (icmp->type))
522 ip4 = (ip4_header_t *) (icmp + 2); /* Use inner packet */
523 udp = (udp_header_t *) (ip4 + 1);
524 /* Swap dst & src for search as ICMP payload is reversed */
525 ip46_address_set_ip4 (&session->key.cs_ip[VLIB_RX],
527 ip46_address_set_ip4 (&session->key.cs_ip[VLIB_TX],
529 session->key.cs_proto = ip4->protocol;
530 session->key.cs_port[VLIB_TX] = udp->src_port;
531 session->key.cs_port[VLIB_RX] = udp->dst_port;
535 udp = (udp_header_t *) (ip4 + 1);
536 ip46_address_set_ip4 (&session->key.cs_ip[VLIB_TX],
538 ip46_address_set_ip4 (&session->key.cs_ip[VLIB_RX],
540 session->key.cs_proto = ip4->protocol;
541 session->key.cs_port[VLIB_RX] = udp->src_port;
542 session->key.cs_port[VLIB_TX] = udp->dst_port;
549 ip6 = vlib_buffer_get_current (b);
550 if (PREDICT_FALSE (ip6->protocol == IP_PROTOCOL_ICMP6))
552 icmp46_header_t *icmp = (icmp46_header_t *) (ip6 + 1);
553 if (!icmp6_type_is_error_message (icmp->type))
555 ip6 = (ip6_header_t *) (icmp + 2); /* Use inner packet */
556 udp = (udp_header_t *) (ip6 + 1);
557 /* Swap dst & src for search as ICMP payload is reversed */
558 ip46_address_set_ip6 (&session->key.cs_ip[VLIB_RX],
560 ip46_address_set_ip6 (&session->key.cs_ip[VLIB_TX],
562 session->key.cs_proto = ip6->protocol;
563 session->key.cs_port[VLIB_TX] = udp->src_port;
564 session->key.cs_port[VLIB_RX] = udp->dst_port;
568 udp = (udp_header_t *) (ip6 + 1);
569 ip46_address_set_ip6 (&session->key.cs_ip[VLIB_TX],
571 ip46_address_set_ip6 (&session->key.cs_ip[VLIB_RX],
573 session->key.cs_port[VLIB_RX] = udp->src_port;
574 session->key.cs_port[VLIB_TX] = udp->dst_port;
575 session->key.cs_proto = ip6->protocol;
581 /* Ensure we dont find anything */
582 session->key.cs_proto = 0;
587 * Create NAT sessions
590 static_always_inline void
591 cnat_session_create (cnat_session_t * session, cnat_node_ctx_t * ctx,
595 clib_bihash_kv_40_48_t rkey;
596 cnat_session_t *rsession = (cnat_session_t *) & rkey;
597 clib_bihash_kv_40_48_t *bkey = (clib_bihash_kv_40_48_t *) session;
598 clib_bihash_kv_40_48_t rvalue;
601 session->value.cs_ts_index = cnat_timestamp_new (ctx->now);
602 clib_bihash_add_del_40_48 (&cnat_session_db, bkey, 1);
604 /* is this the first time we've seen this source address */
605 cc = (AF_IP4 == ctx->af ?
606 cnat_client_ip4_find (&session->value.cs_ip[VLIB_RX].ip4) :
607 cnat_client_ip6_find (&session->value.cs_ip[VLIB_RX].ip6));
612 if (AF_IP4 == ctx->af)
613 r0 = (u64) session->value.cs_ip[VLIB_RX].ip4.as_u32;
616 r0 = r0 * 31 + session->value.cs_ip[VLIB_RX].ip6.as_u64[0];
617 r0 = r0 * 31 + session->value.cs_ip[VLIB_RX].ip6.as_u64[1];
621 if (!throttle_check (&cnat_throttle, ctx->thread_index, r0, ctx->seed))
624 l.addr.version = ctx->af;
625 ip46_address_copy (&l.addr.ip, &session->value.cs_ip[VLIB_RX]);
626 /* fire client create to the main thread */
627 vl_api_rpc_call_main_thread (cnat_client_learn,
628 (u8 *) & l, sizeof (l));
632 /* Will still need to count those for session refcnt */
634 clib_spinlock_lock (&cnat_client_db.throttle_pool_lock
635 [ctx->thread_index]);
636 pool_get (cnat_client_db.throttle_pool[ctx->thread_index], addr);
637 addr->version = ctx->af;
638 ip46_address_copy (&addr->ip, &session->value.cs_ip[VLIB_RX]);
639 clib_spinlock_unlock (&cnat_client_db.throttle_pool_lock
640 [ctx->thread_index]);
645 /* Refcount reverse session */
646 cnat_client_cnt_session (cc);
649 /* create the reverse flow key */
650 ip46_address_copy (&rsession->key.cs_ip[VLIB_RX],
651 &session->value.cs_ip[VLIB_TX]);
652 ip46_address_copy (&rsession->key.cs_ip[VLIB_TX],
653 &session->value.cs_ip[VLIB_RX]);
654 rsession->key.cs_proto = session->key.cs_proto;
655 rsession->key.__cs_pad[0] = 0;
656 rsession->key.__cs_pad[1] = 0;
657 rsession->key.cs_af = ctx->af;
658 rsession->key.cs_port[VLIB_RX] = session->value.cs_port[VLIB_TX];
659 rsession->key.cs_port[VLIB_TX] = session->value.cs_port[VLIB_RX];
661 /* First search for existing reverse session */
662 rv = clib_bihash_search_inline_2_40_48 (&cnat_session_db, &rkey, &rvalue);
665 /* Reverse session already exists
666 cleanup before creating for refcnts */
667 cnat_session_t *found_rsession = (cnat_session_t *) & rvalue;
668 cnat_session_free (found_rsession);
670 /* add the reverse flow */
671 ip46_address_copy (&rsession->value.cs_ip[VLIB_RX],
672 &session->key.cs_ip[VLIB_TX]);
673 ip46_address_copy (&rsession->value.cs_ip[VLIB_TX],
674 &session->key.cs_ip[VLIB_RX]);
675 rsession->value.cs_ts_index = session->value.cs_ts_index;
676 rsession->value.cs_lbi = INDEX_INVALID;
677 rsession->value.flags = rsession_flags;
678 rsession->value.cs_port[VLIB_TX] = session->key.cs_port[VLIB_RX];
679 rsession->value.cs_port[VLIB_RX] = session->key.cs_port[VLIB_TX];
681 clib_bihash_add_del_40_48 (&cnat_session_db, &rkey, 1);
685 cnat_node_inline (vlib_main_t * vm,
686 vlib_node_runtime_t * node,
687 vlib_frame_t * frame,
688 cnat_node_sub_t cnat_sub,
689 ip_address_family_t af, u8 do_trace)
691 u32 n_left, *from, thread_index;
692 vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
693 vlib_buffer_t **b = bufs;
694 u16 nexts[VLIB_FRAME_SIZE], *next;
698 thread_index = vm->thread_index;
699 from = vlib_frame_vector_args (frame);
700 n_left = frame->n_vectors;
702 vlib_get_buffers (vm, from, bufs, n_left);
703 now = vlib_time_now (vm);
704 seed = throttle_seed (&cnat_throttle, thread_index, vlib_time_now (vm));
705 cnat_session_t *session[4];
706 clib_bihash_kv_40_48_t bkey[4], bvalue[4];
710 cnat_node_ctx_t ctx = { now, seed, thread_index, af, do_trace };
714 /* Kickstart our state */
715 cnat_session_make_key (b[3], af, &bkey[3]);
716 cnat_session_make_key (b[2], af, &bkey[2]);
717 cnat_session_make_key (b[1], af, &bkey[1]);
718 cnat_session_make_key (b[0], af, &bkey[0]);
720 hash[3] = clib_bihash_hash_40_48 (&bkey[3]);
721 hash[2] = clib_bihash_hash_40_48 (&bkey[2]);
722 hash[1] = clib_bihash_hash_40_48 (&bkey[1]);
723 hash[0] = clib_bihash_hash_40_48 (&bkey[0]);
730 vlib_prefetch_buffer_header (b[11], LOAD);
731 vlib_prefetch_buffer_header (b[10], LOAD);
732 vlib_prefetch_buffer_header (b[9], LOAD);
733 vlib_prefetch_buffer_header (b[8], LOAD);
737 clib_bihash_search_inline_2_with_hash_40_48 (&cnat_session_db,
740 session[3] = (cnat_session_t *) (rv[3] ? &bkey[3] : &bvalue[3]);
741 next[3] = cnat_sub (vm, node, b[3], &ctx, rv[3], session[3]);
744 clib_bihash_search_inline_2_with_hash_40_48 (&cnat_session_db,
747 session[2] = (cnat_session_t *) (rv[2] ? &bkey[2] : &bvalue[2]);
748 next[2] = cnat_sub (vm, node, b[2], &ctx, rv[2], session[2]);
751 clib_bihash_search_inline_2_with_hash_40_48 (&cnat_session_db,
754 session[1] = (cnat_session_t *) (rv[1] ? &bkey[1] : &bvalue[1]);
755 next[1] = cnat_sub (vm, node, b[1], &ctx, rv[1], session[1]);
758 clib_bihash_search_inline_2_with_hash_40_48 (&cnat_session_db,
761 session[0] = (cnat_session_t *) (rv[0] ? &bkey[0] : &bvalue[0]);
762 next[0] = cnat_sub (vm, node, b[0], &ctx, rv[0], session[0]);
764 cnat_session_make_key (b[7], af, &bkey[3]);
765 cnat_session_make_key (b[6], af, &bkey[2]);
766 cnat_session_make_key (b[5], af, &bkey[1]);
767 cnat_session_make_key (b[4], af, &bkey[0]);
769 hash[3] = clib_bihash_hash_40_48 (&bkey[3]);
770 hash[2] = clib_bihash_hash_40_48 (&bkey[2]);
771 hash[1] = clib_bihash_hash_40_48 (&bkey[1]);
772 hash[0] = clib_bihash_hash_40_48 (&bkey[0]);
774 clib_bihash_prefetch_bucket_40_48 (&cnat_session_db, hash[3]);
775 clib_bihash_prefetch_bucket_40_48 (&cnat_session_db, hash[2]);
776 clib_bihash_prefetch_bucket_40_48 (&cnat_session_db, hash[1]);
777 clib_bihash_prefetch_bucket_40_48 (&cnat_session_db, hash[0]);
779 clib_bihash_prefetch_data_40_48 (&cnat_session_db, hash[3]);
780 clib_bihash_prefetch_data_40_48 (&cnat_session_db, hash[2]);
781 clib_bihash_prefetch_data_40_48 (&cnat_session_db, hash[1]);
782 clib_bihash_prefetch_data_40_48 (&cnat_session_db, hash[0]);
791 cnat_session_make_key (b[0], af, &bkey[0]);
792 rv[0] = clib_bihash_search_inline_2_40_48 (&cnat_session_db,
793 &bkey[0], &bvalue[0]);
795 session[0] = (cnat_session_t *) (rv[0] ? &bkey[0] : &bvalue[0]);
796 next[0] = cnat_sub (vm, node, b[0], &ctx, rv[0], session[0]);
803 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
805 return frame->n_vectors;
809 * fd.io coding-style-patch-verification: ON
812 * eval: (c-set-style "gnu")