52 tag = t->
is_slow_path ?
"NAT44_IN2OUT_SLOW_PATH" :
"NAT44_IN2OUT_FAST_PATH";
54 s =
format (s,
"%s: sw_if_index %d, next index %d, session %d", tag,
66 s =
format (s,
"NAT44_IN2OUT_FAST: sw_if_index %d, next index %d",
80 m = t->
do_handoff ?
"next worker" :
"same worker";
98 #define foreach_snat_in2out_error \ 99 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \ 100 _(IN2OUT_PACKETS, "Good in2out packets processed") \ 101 _(OUT_OF_PORTS, "Out of ports") \ 102 _(BAD_OUTSIDE_FIB, "Outside VRF ID not found") \ 103 _(BAD_ICMP_TYPE, "unsupported ICMP type") \ 104 _(NO_TRANSLATION, "No translation") \ 105 _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded") 108 #define _(sym,str) SNAT_IN2OUT_ERROR_##sym, 115 #define _(sym,string) string, 174 if (sw_if_index == ~0)
184 if ((i->is_inside == 0) && (sw_if_index == i->sw_if_index))
195 u32 rx_fib_index0,
u32 thread_index)
227 snat_session_t ** sessionp,
236 u32 oldest_per_user_translation_list_index;
237 dlist_elt_t * oldest_per_user_translation_list_elt;
242 u32 address_index = ~0;
243 u32 outside_fib_index;
248 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
255 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_BAD_OUTSIDE_FIB];
258 outside_fib_index = p[0];
271 memset (u, 0,
sizeof (*u));
300 oldest_per_user_translation_list_index =
304 ASSERT (oldest_per_user_translation_list_index != ~0);
309 oldest_per_user_translation_list_index);
311 oldest_per_user_translation_list_elt =
313 oldest_per_user_translation_list_index);
316 session_index = oldest_per_user_translation_list_elt->
value;
329 key.
l_addr = s->in2out.addr;
330 key.
r_addr = s->ext_host_addr;
332 key.
proto = s->in2out.port;
337 if (clib_bihash_add_del_16_8 (&sm->
in2out_ed, &up_kv, 0))
340 key.
l_addr = s->out2in.addr;
344 if (clib_bihash_add_del_16_8 (&sm->
out2in_ed, &up_kv, 0))
350 kv0.
key = s->in2out.as_u64;
354 kv0.
key = s->out2in.as_u64;
361 s->out2in.addr.as_u32,
365 s->in2out.fib_index);
368 (sm, thread_index, &s->out2in, s->outside_address_index);
370 s->outside_address_index = ~0;
373 &key1, &address_index))
377 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
380 s->outside_address_index = address_index;
384 u8 static_mapping = 1;
395 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
402 memset (s, 0,
sizeof (*s));
404 s->outside_address_index = address_index;
418 per_user_translation_list_elt);
420 per_user_translation_list_elt -
423 per_user_translation_list_elt->
value =
425 s->per_user_index = per_user_translation_list_elt -
430 s->per_user_list_head_index,
431 per_user_translation_list_elt -
438 s->out2in.fib_index = outside_fib_index;
443 kv0.
key = s->in2out.as_u64;
449 kv0.
key = s->out2in.as_u64;
458 s->out2in.addr.as_u32,
462 s->in2out.fib_index);
470 icmp46_header_t *icmp0;
475 icmp46_header_t *inner_icmp0;
494 case SNAT_PROTOCOL_ICMP:
495 inner_icmp0 = (icmp46_header_t*)l4_header;
499 case SNAT_PROTOCOL_UDP:
500 case SNAT_PROTOCOL_TCP:
504 return SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL;
529 u8 *p_dont_translate,
void *d,
void *e)
531 icmp46_header_t *icmp0;
535 snat_session_t *s0 = 0;
536 u8 dont_translate = 0;
560 IP_PROTOCOL_ICMP, rx_fib_index0, thread_index) &&
569 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
574 next0 =
slow_path (sm, b0, ip0, rx_fib_index0, &key0,
575 &s0, node, next0, thread_index);
583 icmp0->type != ICMP4_echo_reply &&
586 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
598 *p_value = s0->out2in;
599 *p_dont_translate = dont_translate;
601 *(snat_session_t**)d = s0;
622 u8 *p_dont_translate,
void *d,
void *e)
624 icmp46_header_t *icmp0;
629 u8 dont_translate = 0;
650 IP_PROTOCOL_ICMP, rx_fib_index0)))
662 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
668 (icmp0->type != ICMP4_echo_reply || !is_addr_only) &&
671 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
680 *p_dont_translate = dont_translate;
687 icmp46_header_t * icmp0,
701 icmp46_header_t *inner_icmp0;
703 u32 new_addr0, old_addr0;
704 u16 old_id0, new_id0;
712 &protocol, &sm0, &dont_translate, d, e);
746 sum0 = icmp0->checksum;
767 sum0 = icmp0->checksum;
774 case SNAT_PROTOCOL_ICMP:
775 inner_icmp0 = (icmp46_header_t*)l4_header;
782 sum0 = icmp0->checksum;
787 case SNAT_PROTOCOL_UDP:
788 case SNAT_PROTOCOL_TCP:
793 sum0 = icmp0->checksum;
833 u32 new_dst_addr0 = 0, old_dst_addr0, ti = 0, si;
834 u16 new_dst_port0, old_dst_port0;
846 new_dst_port0 = sm0.
port;
862 new_dst_addr0 = s0->in2out.addr.as_u32;
863 new_dst_port0 = s0->in2out.port;
878 old_dst_port0 = tcp0->dst;
883 tcp0->dst = new_dst_port0;
884 sum0 = tcp0->checksum;
901 sum0 = tcp0->checksum;
914 icmp46_header_t * icmp0)
918 u32 new_dst_addr0 = 0, old_dst_addr0, si, ti = 0;
927 key0.
port = icmp_id0;
953 new_dst_addr0 = s0->in2out.addr.as_u32;
956 sum0 = icmp0->checksum;
979 icmp46_header_t * icmp0,
986 snat_session_t ** p_s0)
988 next0 =
icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
989 next0, thread_index, p_s0, 0);
990 snat_session_t * s0 = *p_s0;
997 s0->last_heard = now;
1004 s0->per_user_index);
1006 s0->per_user_list_head_index,
1007 s0->per_user_index);
1017 u32 old_addr, new_addr = 0, ti = 0;
1035 if (clib_bihash_search_16_8 (&sm->
out2in_ed, &s_kv, &s_value))
1067 static snat_session_t *
1081 u32 old_addr, new_addr = 0;
1087 u32 elt_index, head_index, ses_index, oldest_index;
1090 u32 address_index = ~0;
1105 if (!clib_bihash_search_16_8 (&sm->
in2out_ed, &s_kv, &s_value))
1114 b->
error = node->
errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
1123 if (clib_bihash_search_8_8 (&tsm->
user_hash, &kv, &value))
1127 memset (u, 0,
sizeof (*u));
1140 clib_bihash_add_del_8_8 (&tsm->
user_hash, &kv, 1);
1165 if (!clib_bihash_search_8_8 (&tsm->
user_hash, &kv, &value))
1169 elt_index = head->
next;
1171 ses_index = elt->
value;
1172 while (ses_index != ~0)
1175 elt_index = elt->
next;
1177 ses_index = elt->
value;
1182 address_index = s->outside_address_index;
1188 if (clib_bihash_search_16_8 (&sm->
out2in_ed, &s_kv, &s_value))
1201 if (clib_bihash_search_16_8 (&sm->
out2in_ed, &s_kv, &s_value))
1220 ASSERT (oldest_index != ~0);
1230 ses_index = oldest->
value;
1239 key.
l_addr = s->in2out.addr;
1240 key.
r_addr = s->ext_host_addr;
1242 key.
proto = s->in2out.port;
1245 if (clib_bihash_add_del_16_8 (&sm->
in2out_ed, &s_kv, 0))
1248 key.
l_addr = s->out2in.addr;
1252 if (clib_bihash_add_del_16_8 (&sm->
out2in_ed, &s_kv, 0))
1259 s->out2in.addr.as_u32,
1263 s->in2out.fib_index);
1266 s->outside_address_index);
1269 kv.
key = s->in2out.as_u64;
1270 if (clib_bihash_add_del_8_8 (
1273 kv.
key = s->out2in.as_u64;
1274 if (clib_bihash_add_del_8_8 (
1283 memset (s, 0,
sizeof (*s));
1289 s->per_user_index = elt - tsm->
list_pool;
1297 s->outside_address_index = address_index;
1298 s->out2in.addr.as_u32 = new_addr;
1300 s->in2out.addr.as_u32 = old_addr;
1301 s->in2out.fib_index = rx_fib_index;
1302 s->in2out.port = s->out2in.port = ip->
protocol;
1321 if (clib_bihash_add_del_16_8 (&sm->
in2out_ed, &s_kv, 1))
1328 if (clib_bihash_add_del_16_8 (&sm->
out2in_ed, &s_kv, 1))
1338 s->last_heard = now;
1356 static snat_session_t *
1370 snat_session_t *s = 0;
1372 u32 old_addr, new_addr;
1373 u16 new_port, old_port;
1393 if (!clib_bihash_search_16_8 (&sm->
in2out_ed, &s_kv, &s_value))
1401 b->
error = node->
errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
1417 if (clib_bihash_search_8_8 (&tsm->
user_hash, &kv, &value))
1421 memset (u, 0,
sizeof (*u));
1434 if (clib_bihash_add_del_8_8 (&tsm->
user_hash, &kv, 1))
1444 memset (s, 0,
sizeof (*s));
1449 s->outside_address_index = ~0;
1458 s->per_user_index = elt - tsm->
list_pool;
1465 if (clib_bihash_add_del_16_8 (&sm->
in2out_ed, &s_kv, 1))
1473 if (clib_bihash_add_del_16_8 (&sm->
out2in_ed, &s_kv, 1))
1486 old_port = tcp->src_port;
1487 tcp->src_port = s->out2in.port;
1488 new_port = tcp->src_port;
1490 sum = tcp->checksum;
1505 s->last_heard = now;
1515 int is_output_feature)
1517 u32 n_left_from, * from, * to_next;
1519 u32 pkts_processed = 0;
1522 u32 stats_node_index;
1532 while (n_left_from > 0)
1537 to_next, n_left_to_next);
1539 while (n_left_from >= 4 && n_left_to_next >= 2)
1544 u32 sw_if_index0, sw_if_index1;
1547 u32 new_addr0, old_addr0, new_addr1, old_addr1;
1548 u16 old_port0, new_port0, old_port1, new_port1;
1551 icmp46_header_t * icmp0, * icmp1;
1553 u32 rx_fib_index0, rx_fib_index1;
1555 snat_session_t * s0 = 0, * s1 = 0;
1557 u32 iph_offset0 = 0, iph_offset1 = 0;
1574 to_next[0] = bi0 = from[0];
1575 to_next[1] = bi1 = from[1];
1579 n_left_to_next -= 2;
1584 if (is_output_feature)
1585 iph_offset0 =
vnet_buffer (b0)->ip.save_rewrite_length;
1592 icmp0 = (icmp46_header_t *) udp0;
1604 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1618 thread_index, now, vm, node);
1627 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
1628 node, next0, now, thread_index, &s0);
1634 if (
PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP))
1654 ip0, proto0, rx_fib_index0, thread_index)) && !is_output_feature)
1657 next0 =
slow_path (sm, b0, ip0, rx_fib_index0, &key0,
1658 &s0, node, next0, thread_index);
1675 thread_index, now, vm, node);
1697 if (!is_output_feature)
1708 old_port0 = tcp0->src_port;
1709 tcp0->src_port = s0->out2in.port;
1710 new_port0 = tcp0->src_port;
1712 sum0 = tcp0->checksum;
1729 if (!is_output_feature)
1733 s0->last_heard = now;
1740 s0->per_user_index);
1742 s0->per_user_list_head_index,
1743 s0->per_user_index);
1762 if (is_output_feature)
1763 iph_offset1 =
vnet_buffer (b1)->ip.save_rewrite_length;
1770 icmp1 = (icmp46_header_t *) udp1;
1780 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1794 thread_index, now, vm, node);
1803 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1804 next1, now, thread_index, &s1);
1810 if (
PREDICT_FALSE (proto1 == ~0 || proto1 == SNAT_PROTOCOL_ICMP))
1830 ip1, proto1, rx_fib_index1, thread_index)) && !is_output_feature)
1833 next1 =
slow_path (sm, b1, ip1, rx_fib_index1, &key1,
1834 &s1, node, next1, thread_index);
1851 thread_index, now, vm, node);
1873 if (!is_output_feature)
1884 old_port1 = tcp1->src_port;
1885 tcp1->src_port = s1->out2in.port;
1886 new_port1 = tcp1->src_port;
1888 sum1 = tcp1->checksum;
1905 if (!is_output_feature)
1909 s1->last_heard = now;
1916 s1->per_user_index);
1918 s1->per_user_list_head_index,
1919 s1->per_user_index);
1939 to_next, n_left_to_next,
1940 bi0, bi1, next0, next1);
1943 while (n_left_from > 0 && n_left_to_next > 0)
1951 u32 new_addr0, old_addr0;
1952 u16 old_port0, new_port0;
1955 icmp46_header_t * icmp0;
1959 snat_session_t * s0 = 0;
1961 u32 iph_offset0 = 0;
1969 n_left_to_next -= 1;
1974 if (is_output_feature)
1975 iph_offset0 =
vnet_buffer (b0)->ip.save_rewrite_length;
1982 icmp0 = (icmp46_header_t *) udp0;
1992 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2006 thread_index, now, vm, node);
2015 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
2016 next0, now, thread_index, &s0);
2022 if (
PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP))
2042 ip0, proto0, rx_fib_index0, thread_index)) && !is_output_feature)
2045 next0 =
slow_path (sm, b0, ip0, rx_fib_index0, &key0,
2046 &s0, node, next0, thread_index);
2064 thread_index, now, vm, node);
2086 if (!is_output_feature)
2097 old_port0 = tcp0->src_port;
2098 tcp0->src_port = s0->out2in.port;
2099 new_port0 = tcp0->src_port;
2101 sum0 = tcp0->checksum;
2118 if (!is_output_feature)
2122 s0->last_heard = now;
2129 s0->per_user_index);
2131 s0->per_user_list_head_index,
2132 s0->per_user_index);
2153 to_next, n_left_to_next,
2161 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
2176 .name =
"nat44-in2out",
2177 .vector_size =
sizeof (
u32),
2209 .name =
"nat44-in2out-output",
2210 .vector_size =
sizeof (
u32),
2243 .name =
"nat44-in2out-slowpath",
2244 .vector_size =
sizeof (
u32),
2277 .name =
"nat44-in2out-output-slowpath",
2278 .vector_size =
sizeof (
u32),
2309 u32 n_left_from, * from, * to_next;
2311 u32 pkts_processed = 0;
2320 while (n_left_from > 0)
2325 to_next, n_left_to_next);
2327 while (n_left_from >= 4 && n_left_to_next >= 2)
2332 u32 sw_if_index0, sw_if_index1;
2336 u16 old_port0, new_port0, lo_port0, i0;
2337 u16 old_port1, new_port1, lo_port1, i1;
2344 u32 rx_fib_index0, rx_fib_index1;
2345 icmp46_header_t * icmp0, * icmp1;
2362 to_next[0] = bi0 = from[0];
2363 to_next[1] = bi1 = from[1];
2367 n_left_to_next -= 2;
2385 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2396 icmp0 = (icmp46_header_t *) udp0;
2398 next0 =
icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0,
2399 rx_fib_index0, node, next0, thread_index,
2410 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
2424 key0.
out_port = clib_host_to_net_u16 (lo_port0 +
2425 ((i0 + clib_net_to_host_u16 (tcp0->src)) % dm0->
ports_per_host));
2439 ICMP4_destination_unreachable_destination_unreachable_host,
2461 ses0->
state = SNAT_SESSION_TCP_SYN_SENT;
2462 else if (tcp0->flags &
TCP_FLAG_ACK && ses0->
state == SNAT_SESSION_TCP_SYN_SENT)
2463 ses0->
state = SNAT_SESSION_TCP_ESTABLISHED;
2464 else if (tcp0->flags &
TCP_FLAG_FIN && ses0->
state == SNAT_SESSION_TCP_ESTABLISHED)
2465 ses0->
state = SNAT_SESSION_TCP_FIN_WAIT;
2466 else if (tcp0->flags &
TCP_FLAG_ACK && ses0->
state == SNAT_SESSION_TCP_FIN_WAIT)
2468 else if (tcp0->flags &
TCP_FLAG_FIN && ses0->
state == SNAT_SESSION_TCP_CLOSE_WAIT)
2469 ses0->
state = SNAT_SESSION_TCP_LAST_ACK;
2470 else if (tcp0->flags == 0 && ses0->
state == SNAT_SESSION_UNKNOWN)
2471 ses0->
state = SNAT_SESSION_TCP_ESTABLISHED;
2473 old_port0 = tcp0->src;
2474 tcp0->src = new_port0;
2476 sum0 = tcp0->checksum;
2487 ses0->
state = SNAT_SESSION_UDP_ACTIVE;
2495 case SNAT_SESSION_UDP_ACTIVE:
2498 case SNAT_SESSION_TCP_SYN_SENT:
2499 case SNAT_SESSION_TCP_FIN_WAIT:
2500 case SNAT_SESSION_TCP_CLOSE_WAIT:
2501 case SNAT_SESSION_TCP_LAST_ACK:
2504 case SNAT_SESSION_TCP_ESTABLISHED:
2535 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2546 icmp1 = (icmp46_header_t *) udp1;
2548 next1 =
icmp_in2out(sm, b1, ip1, icmp1, sw_if_index1,
2549 rx_fib_index1, node, next1, thread_index,
2560 b1->
error = node->
errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
2574 key1.
out_port = clib_host_to_net_u16 (lo_port1 +
2575 ((i1 + clib_net_to_host_u16 (tcp1->src)) % dm1->
ports_per_host));
2589 ICMP4_destination_unreachable_destination_unreachable_host,
2596 new_port1 = ses1->out.out_port;
2611 ses1->state = SNAT_SESSION_TCP_SYN_SENT;
2612 else if (tcp1->flags &
TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_SYN_SENT)
2613 ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
2614 else if (tcp1->flags &
TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
2615 ses1->state = SNAT_SESSION_TCP_FIN_WAIT;
2616 else if (tcp1->flags &
TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_FIN_WAIT)
2618 else if (tcp1->flags &
TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_CLOSE_WAIT)
2619 ses1->state = SNAT_SESSION_TCP_LAST_ACK;
2620 else if (tcp1->flags == 0 && ses1->state == SNAT_SESSION_UNKNOWN)
2621 ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
2623 old_port1 = tcp1->src;
2624 tcp1->src = new_port1;
2626 sum1 = tcp1->checksum;
2637 ses1->state = SNAT_SESSION_UDP_ACTIVE;
2645 case SNAT_SESSION_UDP_ACTIVE:
2648 case SNAT_SESSION_TCP_SYN_SENT:
2649 case SNAT_SESSION_TCP_FIN_WAIT:
2650 case SNAT_SESSION_TCP_CLOSE_WAIT:
2651 case SNAT_SESSION_TCP_LAST_ACK:
2654 case SNAT_SESSION_TCP_ESTABLISHED:
2677 to_next, n_left_to_next,
2678 bi0, bi1, next0, next1);
2681 while (n_left_from > 0 && n_left_to_next > 0)
2690 u16 old_port0, new_port0, lo_port0, i0;
2698 icmp46_header_t * icmp0;
2706 n_left_to_next -= 1;
2721 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2732 icmp0 = (icmp46_header_t *) udp0;
2734 next0 =
icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0,
2735 rx_fib_index0, node, next0, thread_index,
2746 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
2760 key0.
out_port = clib_host_to_net_u16 (lo_port0 +
2761 ((i0 + clib_net_to_host_u16 (tcp0->src)) % dm0->
ports_per_host));
2775 ICMP4_destination_unreachable_destination_unreachable_host,
2797 ses0->
state = SNAT_SESSION_TCP_SYN_SENT;
2798 else if (tcp0->flags &
TCP_FLAG_ACK && ses0->
state == SNAT_SESSION_TCP_SYN_SENT)
2799 ses0->
state = SNAT_SESSION_TCP_ESTABLISHED;
2800 else if (tcp0->flags &
TCP_FLAG_FIN && ses0->
state == SNAT_SESSION_TCP_ESTABLISHED)
2801 ses0->
state = SNAT_SESSION_TCP_FIN_WAIT;
2802 else if (tcp0->flags &
TCP_FLAG_ACK && ses0->
state == SNAT_SESSION_TCP_FIN_WAIT)
2804 else if (tcp0->flags &
TCP_FLAG_FIN && ses0->
state == SNAT_SESSION_TCP_CLOSE_WAIT)
2805 ses0->
state = SNAT_SESSION_TCP_LAST_ACK;
2806 else if (tcp0->flags == 0 && ses0->
state == SNAT_SESSION_UNKNOWN)
2807 ses0->
state = SNAT_SESSION_TCP_ESTABLISHED;
2809 old_port0 = tcp0->src;
2810 tcp0->src = new_port0;
2812 sum0 = tcp0->checksum;
2823 ses0->
state = SNAT_SESSION_UDP_ACTIVE;
2831 case SNAT_SESSION_UDP_ACTIVE:
2834 case SNAT_SESSION_TCP_SYN_SENT:
2835 case SNAT_SESSION_TCP_FIN_WAIT:
2836 case SNAT_SESSION_TCP_CLOSE_WAIT:
2837 case SNAT_SESSION_TCP_LAST_ACK:
2840 case SNAT_SESSION_TCP_ESTABLISHED:
2863 to_next, n_left_to_next,
2871 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
2878 .name =
"nat44-det-in2out",
2879 .vector_size =
sizeof (
u32),
2918 u8 *p_dont_translate,
void *d,
void *e)
2920 icmp46_header_t *icmp0;
2925 u8 dont_translate = 0;
2929 void *l4_header = 0;
2930 icmp46_header_t *inner_icmp0;
2945 protocol = SNAT_PROTOCOL_ICMP;
2957 case SNAT_PROTOCOL_ICMP:
2958 inner_icmp0 = (icmp46_header_t*)l4_header;
2962 case SNAT_PROTOCOL_UDP:
2963 case SNAT_PROTOCOL_TCP:
2967 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
2979 IP_PROTOCOL_ICMP, rx_fib_index0)))
2985 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
2998 IP_PROTOCOL_ICMP, rx_fib_index0)))
3003 if (icmp0->type != ICMP4_echo_request)
3005 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
3011 key0.
out_port = clib_host_to_net_u16 (lo_port0 +
3023 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
3031 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
3038 ses0->
state = SNAT_SESSION_ICMP_ACTIVE;
3042 *p_proto = protocol;
3045 p_value->
addr = new_addr0;
3049 *p_dont_translate = dont_translate;
3068 u32 n_left_from, *from, *to_next = 0;
3075 u32 n_left_to_next_worker = 0, *to_next_worker = 0;
3076 u32 next_worker_index = 0;
3077 u32 current_worker_index = ~0;
3107 while (n_left_from > 0)
3133 if (next_worker_index != current_worker_index)
3140 handoff_queue_elt_by_worker_index);
3144 current_worker_index = next_worker_index;
3148 to_next_worker[0] = bi0;
3150 n_left_to_next_worker--;
3152 if (n_left_to_next_worker == 0)
3156 current_worker_index = ~0;
3157 handoff_queue_elt_by_worker_index[next_worker_index] = 0;
3193 for (i = 0; i <
vec_len (handoff_queue_elt_by_worker_index); i++)
3195 if (handoff_queue_elt_by_worker_index[i])
3197 hf = handoff_queue_elt_by_worker_index[
i];
3205 handoff_queue_elt_by_worker_index[
i] = 0;
3210 congested_handoff_queue_by_worker_index[
i] =
3214 current_worker_index = ~0;
3228 .name =
"nat44-in2out-worker-handoff",
3229 .vector_size =
sizeof (
u32),
3253 .name =
"nat44-in2out-output-worker-handoff",
3254 .vector_size =
sizeof (
u32),
3297 u32 n_left_from, * from, * to_next;
3299 u32 pkts_processed = 0;
3306 while (n_left_from > 0)
3311 to_next, n_left_to_next);
3313 while (n_left_from > 0 && n_left_to_next > 0)
3327 n_left_to_next -= 1;
3338 if (proto0 == SNAT_PROTOCOL_TCP || proto0 == SNAT_PROTOCOL_UDP)
3345 else if (proto0 == SNAT_PROTOCOL_ICMP)
3364 to_next, n_left_to_next,
3372 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
3379 .name =
"nat44-hairpin-dst",
3380 .vector_size =
sizeof (
u32),
3399 u32 n_left_from, * from, * to_next;
3401 u32 pkts_processed = 0;
3408 while (n_left_from > 0)
3413 to_next, n_left_to_next);
3415 while (n_left_from > 0 && n_left_to_next > 0)
3429 n_left_to_next -= 1;
3438 if ((i->is_inside == 1) && (sw_if_index0 == i->sw_if_index))
3440 if (PREDICT_FALSE ((vnet_buffer (b0)->snat.flags) &
3441 SNAT_FLAG_HAIRPINNING))
3443 if (PREDICT_TRUE (sm->num_workers > 1))
3444 next0 = SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH;
3446 next0 = SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT;
3456 to_next, n_left_to_next,
3464 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
3466 return frame->n_vectors;
3471 .name =
"nat44-hairpin-src",
3472 .vector_size =
sizeof (
u32),
3493 u32 n_left_from, * from, * to_next;
3495 u32 pkts_processed = 0;
3497 u32 stats_node_index;
3505 while (n_left_from > 0)
3510 to_next, n_left_to_next);
3512 while (n_left_from > 0 && n_left_to_next > 0)
3520 u32 new_addr0, old_addr0;
3521 u16 old_port0, new_port0;
3524 icmp46_header_t * icmp0;
3535 n_left_to_next -= 1;
3543 icmp0 = (icmp46_header_t *) udp0;
3552 ICMP4_time_exceeded_ttl_exceeded_in_transit,
3565 next0 =
icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0,
3566 rx_fib_index0, node, next0, ~0, 0, 0);
3577 b0->
error = node->
errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
3583 new_port0 = sm0.
port;
3598 old_port0 = tcp0->src_port;
3599 tcp0->src_port = new_port0;
3601 sum0 = tcp0->checksum;
3621 sum0 = tcp0->checksum;
3646 to_next, n_left_to_next,
3654 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
3662 .name =
"nat44-in2out-fast",
3663 .vector_size =
sizeof (
u32),
ip4_address_t external_addr
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
static snat_session_t * snat_in2out_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index, u32 thread_index, f64 now, vlib_main_t *vm, vlib_node_runtime_t *node)
fib_protocol_t fp_proto
protocol type
#define snat_is_session_static(s)
Check if SNAT session is created from static mapping.
u32 sessions_per_user_list_head_index
static u8 * format_snat_in2out_trace(u8 *s, va_list *args)
clib_bihash_16_8_t out2in_ed
sll srl srl sll sra u16x4 i
static uword snat_in2out_slow_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static void clib_dlist_init(dlist_elt_t *pool, u32 index)
u32 fq_in2out_output_index
static u8 * format_snat_in2out_fast_trace(u8 *s, va_list *args)
static uword snat_in2out_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_slow_path, int is_output_feature)
static int ip4_header_bytes(ip4_header_t *i)
static f64 vlib_time_now(vlib_main_t *vm)
static char * snat_in2out_error_strings[]
void snat_free_outside_address_and_port(snat_main_t *sm, u32 thread_index, snat_session_key_t *k, u32 address_index)
static uword snat_in2out_worker_handoff_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static void snat_icmp_hairpinning(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0)
static void snat_det_ses_close(snat_det_map_t *dm, snat_det_session_t *ses)
struct _vlib_node_registration vlib_node_registration_t
static snat_det_session_t * snat_det_find_ses_by_in(snat_det_map_t *dm, ip4_address_t *in_addr, u16 in_port, snat_det_out_key_t out_key)
static void snat_det_forward(snat_det_map_t *dm, ip4_address_t *in_addr, ip4_address_t *out_addr, u16 *lo_port)
u32 * fib_index_by_sw_if_index
Table index indexed by software interface.
clib_bihash_16_8_t in2out_ed
u32 buffer_index[VLIB_FRAME_SIZE]
vlib_error_t * errors
Vector of errors for this node.
int snat_static_mapping_match(snat_main_t *sm, snat_session_key_t match, snat_session_key_t *mapping, u8 by_external, u8 *is_addr_only)
Match NAT44 static mapping.
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
struct _tcp_header tcp_header_t
#define snat_is_unk_proto_session(s)
Check if SNAT session for unknown protocol.
VLIB_NODE_FUNCTION_MULTIARCH(snat_in2out_node, snat_in2out_fast_path_fn)
u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation.
static void snat_hairpinning(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, udp_header_t *udp0, tcp_header_t *tcp0, u32 proto0)
Hairpinning.
clib_bihash_8_8_t user_hash
vlib_node_registration_t snat_hairpin_dst_node
(constructor) VLIB_REGISTER_NODE (snat_hairpin_dst_node)
u32 max_translations_per_user
static uword snat_in2out_output_slow_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
vlib_node_registration_t snat_in2out_output_slowpath_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_output_slowpath_node)
u32 in2out_output_node_index
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
#define static_always_inline
static uword ip4_header_checksum_is_valid(ip4_header_t *i)
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
vlib_node_registration_t snat_in2out_output_worker_handoff_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_output_worker_handoff_node)
ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
vlib_node_registration_t snat_in2out_fast_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_fast_node)
static uword snat_in2out_output_worker_handoff_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
ip4_address_t ext_host_addr
static int snat_not_translate(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0, u32 thread_index)
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
static uword snat_det_in2out_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Aggregrate type for a prefix.
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
static u8 * format_snat_in2out_worker_handoff_trace(u8 *s, va_list *args)
static void * ip4_next_header(ip4_header_t *i)
static u32 slow_path(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, u32 rx_fib_index0, snat_session_key_t *key0, snat_session_t **sessionp, vlib_node_runtime_t *node, u32 next0, u32 thread_index)
vlib_node_registration_t snat_in2out_slowpath_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_slowpath_node)
static uword snat_in2out_worker_handoff_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, u8 is_output)
fib_node_index_t fib_table_lookup(u32 fib_index, const fib_prefix_t *prefix)
Perfom a longest prefix match in the non-forwarding table.
#define foreach_snat_in2out_error
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
uword * fib_index_by_table_id
Hash table mapping table id to fib index.
snat_det_session_t * sessions
static u32 icmp_in2out_slow_path(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0, f64 now, u32 thread_index, snat_session_t **p_s0)
static void clib_dlist_addtail(dlist_elt_t *pool, u32 head_index, u32 new_index)
snat_static_mapping_t * static_mappings
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
void snat_ipfix_logging_nat44_ses_delete(u32 src_ip, u32 nat_src_ip, snat_protocol_t snat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session delete event.
void snat_ipfix_logging_nat44_ses_create(u32 src_ip, u32 nat_src_ip, snat_protocol_t snat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session create event.
static vlib_frame_queue_elt_t * vlib_get_worker_handoff_queue_elt(u32 frame_queue_index, u32 vlib_worker_index, vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index)
clib_bihash_8_8_t static_mapping_by_external
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
#define SNAT_SESSION_FLAG_UNKNOWN_PROTO
#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.
#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).
vlib_error_t error
Error code for buffers to be enqueued to error handler.
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
u32 fib_entry_get_resolving_interface(fib_node_index_t entry_index)
snat_interface_t * output_feature_interfaces
static void snat_hairpinning_unknown_proto(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip)
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
static_always_inline int is_hairpinning(snat_main_t *sm, ip4_address_t *dst_addr)
static_always_inline uword vlib_get_thread_index(void)
#define CLIB_PREFETCH(addr, size, type)
static uword snat_in2out_output_fast_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
vlib_node_registration_t snat_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_node)
snat_get_worker_function_t * worker_in2out_cb
void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
deterministic NAT definitions
#define clib_warning(format, args...)
#define VLIB_BUFFER_IS_TRACED
static uword snat_in2out_fast_static_map_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
u32 fib_node_index_t
A typedef of a node index.
8 octet key, 8 octet key value pair
static_always_inline snat_in2out_error_t icmp_get_key(ip4_header_t *ip0, snat_session_key_t *p_key0)
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
u32 tcp_transitory_timeout
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
static snat_det_map_t * snat_det_map_by_user(snat_main_t *sm, ip4_address_t *user_addr)
snat_get_worker_function_t * worker_out2in_cb
static u32 ip_proto_to_snat_proto(u8 ip_proto)
#define VLIB_NODE_FLAG_TRACE
static void clib_dlist_remove(dlist_elt_t *pool, u32 index)
static int snat_not_translate_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0)
Check if packet should be translated.
vlib_node_registration_t snat_det_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_det_in2out_node)
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
#define vec_elt(v, i)
Get vector value at index i.
static uword snat_hairpin_src_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
#define FIB_NODE_INDEX_INVALID
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
vlib_node_registration_t snat_in2out_worker_handoff_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_worker_handoff_node)
static_always_inline u8 is_interface_addr(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, u32 ip4_addr)
snat_main_per_thread_data_t * per_thread_data
#define SNAT_FLAG_HAIRPINNING
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
#define ip_csum_update(sum, old, new, type, field)
vlib_node_registration_t snat_hairpin_src_node
(constructor) VLIB_REGISTER_NODE (snat_hairpin_src_node)
static snat_session_t * snat_in2out_lb(snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index, u32 thread_index, f64 now, vlib_main_t *vm, vlib_node_runtime_t *node)
snat_address_t * addresses
static void vlib_put_frame_queue_elt(vlib_frame_queue_elt_t *hf)
u32 icmp_match_in2out_det(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
static uword snat_in2out_fast_path_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static snat_det_session_t * snat_det_get_ses_by_out(snat_det_map_t *dm, ip4_address_t *in_addr, u64 out_key)
#define SNAT_SESSION_FLAG_STATIC_MAPPING
#define VLIB_REGISTER_NODE(x,...)
static vlib_thread_main_t * vlib_get_thread_main()
#define vec_foreach(var, vec)
Vector iterator.
vlib_node_registration_t snat_in2out_output_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_output_node)
u16 flags
Copy of main node flags.
int snat_alloc_outside_address_and_port(snat_main_t *sm, u32 fib_index, u32 thread_index, snat_session_key_t *k, u32 *address_indexp)
static uword snat_hairpin_dst_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
#define CLIB_CACHE_LINE_BYTES
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
static snat_det_session_t * snat_det_ses_create(snat_det_map_t *dm, ip4_address_t *in_addr, u16 in_port, snat_det_out_key_t *out)
static u8 maximum_sessions_exceeded(snat_main_t *sm, u32 thread_index)
snat_session_t * sessions
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
snat_icmp_match_function_t * icmp_match_in2out_cb
#define SNAT_SESSION_FLAG_LOAD_BALANCING
clib_bihash_8_8_t static_mapping_by_local
static u16 ip_csum_fold(ip_csum_t c)
snat_interface_t * interfaces
static_always_inline u8 icmp_is_error_message(icmp46_header_t *icmp)
static u32 clib_dlist_remove_head(dlist_elt_t *pool, u32 head_index)
u32 tcp_established_timeout
static u32 icmp_in2out(snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0, u32 thread_index, void *d, void *e)