X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fout2in.c;h=489afadb4a258c5934d2a578e874e9f38ef88ad0;hb=efcd1e9e1d7dda4e4ea3db5750925cd8f6894f4d;hp=55a750e41879d7cd8861944e43e05ff96ae91545;hpb=704018cf117b6667f08b09d6db5fbec105bf6d57;p=vpp.git diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c old mode 100644 new mode 100755 index 55a750e4187..489afadb4a2 --- a/src/plugins/nat/out2in.c +++ b/src/plugins/nat/out2in.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -78,16 +79,40 @@ static u8 * format_snat_out2in_worker_handoff_trace (u8 * s, va_list * args) return s; } +typedef struct { + u32 sw_if_index; + u32 next_index; + u8 cached; +} nat44_out2in_reass_trace_t; + +static u8 * format_nat44_out2in_reass_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + nat44_out2in_reass_trace_t * t = va_arg (*args, nat44_out2in_reass_trace_t *); + + s = format (s, "NAT44_OUT2IN_REASS: sw_if_index %d, next index %d, status %s", + t->sw_if_index, t->next_index, + t->cached ? "cached" : "translated"); + + return s; +} + vlib_node_registration_t snat_out2in_node; vlib_node_registration_t snat_out2in_fast_node; vlib_node_registration_t snat_out2in_worker_handoff_node; vlib_node_registration_t snat_det_out2in_node; +vlib_node_registration_t nat44_out2in_reass_node; #define foreach_snat_out2in_error \ _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \ _(OUT2IN_PACKETS, "Good out2in packets processed") \ _(BAD_ICMP_TYPE, "unsupported ICMP type") \ -_(NO_TRANSLATION, "No translation") +_(NO_TRANSLATION, "No translation") \ +_(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded") \ +_(DROP_FRAGMENT, "Drop fragment") \ +_(MAX_REASS, "Maximum reassemblies exceeded") \ +_(MAX_FRAG, "Maximum fragments per reassembly exceeded") typedef enum { #define _(sym,str) SNAT_OUT2IN_ERROR_##sym, @@ -106,6 +131,7 @@ typedef enum { SNAT_OUT2IN_NEXT_DROP, SNAT_OUT2IN_NEXT_LOOKUP, SNAT_OUT2IN_NEXT_ICMP_ERROR, + SNAT_OUT2IN_NEXT_REASS, SNAT_OUT2IN_N_NEXT, } snat_out2in_next_t; @@ -138,15 +164,24 @@ create_session_for_static_mapping (snat_main_t *sm, dlist_elt_t * per_user_translation_list_elt; dlist_elt_t * per_user_list_head_elt; ip4_header_t *ip0; + udp_header_t *udp0; + + if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index))) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED]; + return 0; + } ip0 = vlib_buffer_get_current (b0); + udp0 = ip4_next_header (ip0); user_key.addr = in2out.addr; user_key.fib_index = in2out.fib_index; kv0.key = user_key.as_u64; /* Ever heard of the "user" = inside ip4 address before? */ - if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0)) + if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].user_hash, + &kv0, &value0)) { /* no, make a new one */ pool_get (sm->per_thread_data[thread_index].users, u); @@ -166,11 +201,8 @@ create_session_for_static_mapping (snat_main_t *sm, kv0.value = u - sm->per_thread_data[thread_index].users; /* add user */ - clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */); - - /* add non-traslated packets worker lookup */ - kv0.value = thread_index; - clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1); + clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].user_hash, + &kv0, 1 /* is_add */); } else { @@ -183,7 +215,8 @@ create_session_for_static_mapping (snat_main_t *sm, s->outside_address_index = ~0; s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; - s->ext_host_addr.as_u32 = ip0->dst_address.as_u32; + s->ext_host_addr.as_u32 = ip0->src_address.as_u32; + s->ext_host_port = udp0->src_port; u->nstaticsessions++; /* Create list elts */ @@ -211,13 +244,15 @@ create_session_for_static_mapping (snat_main_t *sm, /* Add to translation hashes */ kv0.key = s->in2out.as_u64; kv0.value = s - sm->per_thread_data[thread_index].sessions; - if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */)) + if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0, + 1 /* is_add */)) clib_warning ("in2out key add failed"); kv0.key = s->out2in.as_u64; kv0.value = s - sm->per_thread_data[thread_index].sessions; - if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */)) + if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0, + 1 /* is_add */)) clib_warning ("out2in key add failed"); /* log NAT event */ @@ -290,11 +325,11 @@ snat_out2in_error_t icmp_get_key(ip4_header_t *ip0, * @param e optional parameter */ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, + 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) { - ip4_header_t *ip0; icmp46_header_t *icmp0; u32 sw_if_index0; u32 rx_fib_index0; @@ -307,7 +342,6 @@ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 next0 = ~0; int err; - ip0 = vlib_buffer_get_current (b0); icmp0 = (icmp46_header_t *) ip4_next_header (ip0); sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0); @@ -325,7 +359,8 @@ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, kv0.key = key0.as_u64; - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) + if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0, + &value0)) { /* Try to match static mapping by external address and port, destination address and port in packet */ @@ -400,11 +435,11 @@ out: * @param e optional parameter */ u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, + 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) { - ip4_header_t *ip0; icmp46_header_t *icmp0; u32 sw_if_index0; u32 rx_fib_index0; @@ -415,7 +450,6 @@ u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 next0 = ~0; int err; - ip0 = vlib_buffer_get_current (b0); icmp0 = (icmp46_header_t *) ip4_next_header (ip0); sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0); @@ -486,7 +520,7 @@ static inline u32 icmp_out2in (snat_main_t *sm, echo0 = (icmp_echo_header_t *)(icmp0+1); - next0_tmp = sm->icmp_match_out2in_cb(sm, node, thread_index, b0, + next0_tmp = sm->icmp_match_out2in_cb(sm, node, thread_index, b0, ip0, &protocol, &sm0, &dont_translate, d, e); if (next0_tmp != ~0) next0 = next0_tmp; @@ -615,14 +649,15 @@ static inline u32 icmp_out2in_slow_path (snat_main_t *sm, return next0; } -static void +static snat_session_t * snat_out2in_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_main_t * vm, + vlib_node_runtime_t * node) { clib_bihash_kv_8_8_t kv, value; clib_bihash_kv_16_8_t s_kv, s_value; @@ -655,13 +690,22 @@ snat_out2in_unknown_proto (snat_main_t *sm, } else { + if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index))) + { + b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED]; + return 0; + } + m_key.addr = ip->dst_address; m_key.port = 0; m_key.protocol = 0; m_key.fib_index = rx_fib_index; kv.key = m_key.as_u64; if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) - return; + { + b->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + return 0; + } m = pool_elt_at_index (sm->static_mappings, value.value); @@ -672,7 +716,7 @@ snat_out2in_unknown_proto (snat_main_t *sm, kv.key = u_key.as_u64; /* Ever heard of the "user" = src ip4 address before? */ - if (clib_bihash_search_8_8 (&sm->user_hash, &kv, &value)) + if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) { /* no, make a new one */ pool_get (tsm->users, u); @@ -689,7 +733,7 @@ snat_out2in_unknown_proto (snat_main_t *sm, kv.value = u - tsm->users; /* add user */ - clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 1); + clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1); } else { @@ -748,16 +792,19 @@ snat_out2in_unknown_proto (snat_main_t *sm, clib_dlist_remove (tsm->list_pool, s->per_user_index); clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, s->per_user_index); + + return s; } -static void +static snat_session_t * snat_out2in_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_main_t * vm, + vlib_node_runtime_t * node) { nat_ed_ses_key_t key; clib_bihash_kv_16_8_t s_kv, s_value; @@ -792,19 +839,25 @@ snat_out2in_lb (snat_main_t *sm, } else { + if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index))) + { + b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED]; + return 0; + } + e_key.addr = ip->dst_address; e_key.port = udp->dst_port; e_key.protocol = proto; e_key.fib_index = rx_fib_index; if (snat_static_mapping_match(sm, e_key, &l_key, 1, 0)) - return; + return 0; u_key.addr = l_key.addr; u_key.fib_index = l_key.fib_index; kv.key = u_key.as_u64; /* Ever heard of the "user" = src ip4 address before? */ - if (clib_bihash_search_8_8 (&sm->user_hash, &kv, &value)) + if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) { /* no, make a new one */ pool_get (tsm->users, u); @@ -821,7 +874,7 @@ snat_out2in_lb (snat_main_t *sm, kv.value = u - tsm->users; /* add user */ - if (clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 1)) + if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1)) clib_warning ("user key add failed"); } else @@ -894,6 +947,7 @@ snat_out2in_lb (snat_main_t *sm, s->last_heard = now; s->total_pkts++; s->total_bytes += vlib_buffer_length_in_chain (vm, b); + return s; } static uword @@ -992,8 +1046,10 @@ snat_out2in_node_fn (vlib_main_t * vm, if (PREDICT_FALSE (proto0 == ~0)) { - snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0, - thread_index, now, vm); + s0 = snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0, + thread_index, now, vm, node); + if (!s0) + next0 = SNAT_OUT2IN_NEXT_DROP; goto trace0; } @@ -1005,6 +1061,12 @@ snat_out2in_node_fn (vlib_main_t * vm, goto trace0; } + if (PREDICT_FALSE (ip4_is_fragment (ip0))) + { + next0 = SNAT_OUT2IN_NEXT_REASS; + goto trace0; + } + key0.addr = ip0->dst_address; key0.port = udp0->dst_port; key0.protocol = proto0; @@ -1012,7 +1074,8 @@ snat_out2in_node_fn (vlib_main_t * vm, kv0.key = key0.as_u64; - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) + if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, + &kv0, &value0)) { /* Try to match static mapping by external address and port, destination address and port in packet */ @@ -1035,7 +1098,6 @@ snat_out2in_node_fn (vlib_main_t * vm, thread_index); if (!s0) { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; next0 = SNAT_OUT2IN_NEXT_DROP; goto trace0; } @@ -1044,8 +1106,10 @@ snat_out2in_node_fn (vlib_main_t * vm, { if (PREDICT_FALSE (value0.value == ~0ULL)) { - snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index, now, - vm); + s0 = snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index, + now, vm, node); + if (!s0) + next0 = SNAT_OUT2IN_NEXT_DROP; goto trace0; } else @@ -1143,8 +1207,10 @@ snat_out2in_node_fn (vlib_main_t * vm, if (PREDICT_FALSE (proto1 == ~0)) { - snat_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1, - thread_index, now, vm); + s1 = snat_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1, + thread_index, now, vm, node); + if (!s1) + next1 = SNAT_OUT2IN_NEXT_DROP; goto trace1; } @@ -1156,6 +1222,12 @@ snat_out2in_node_fn (vlib_main_t * vm, goto trace1; } + if (PREDICT_FALSE (ip4_is_fragment (ip1))) + { + next1 = SNAT_OUT2IN_NEXT_REASS; + goto trace1; + } + key1.addr = ip1->dst_address; key1.port = udp1->dst_port; key1.protocol = proto1; @@ -1163,7 +1235,8 @@ snat_out2in_node_fn (vlib_main_t * vm, kv1.key = key1.as_u64; - if (clib_bihash_search_8_8 (&sm->out2in, &kv1, &value1)) + if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, + &kv1, &value1)) { /* Try to match static mapping by external address and port, destination address and port in packet */ @@ -1186,7 +1259,6 @@ snat_out2in_node_fn (vlib_main_t * vm, thread_index); if (!s1) { - b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; next1 = SNAT_OUT2IN_NEXT_DROP; goto trace1; } @@ -1195,8 +1267,10 @@ snat_out2in_node_fn (vlib_main_t * vm, { if (PREDICT_FALSE (value1.value == ~0ULL)) { - snat_out2in_lb(sm, b1, ip1, rx_fib_index1, thread_index, now, - vm); + s1 = snat_out2in_lb(sm, b1, ip1, rx_fib_index1, thread_index, + now, vm, node); + if (!s1) + next1 = SNAT_OUT2IN_NEXT_DROP; goto trace1; } else @@ -1320,8 +1394,10 @@ snat_out2in_node_fn (vlib_main_t * vm, if (PREDICT_FALSE (proto0 == ~0)) { - snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0, - thread_index, now, vm); + s0 = snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0, + thread_index, now, vm, node); + if (!s0) + next0 = SNAT_OUT2IN_NEXT_DROP; goto trace00; } @@ -1343,6 +1419,12 @@ snat_out2in_node_fn (vlib_main_t * vm, goto trace00; } + if (PREDICT_FALSE (ip4_is_fragment (ip0))) + { + next0 = SNAT_OUT2IN_NEXT_REASS; + goto trace00; + } + key0.addr = ip0->dst_address; key0.port = udp0->dst_port; key0.protocol = proto0; @@ -1350,7 +1432,8 @@ snat_out2in_node_fn (vlib_main_t * vm, kv0.key = key0.as_u64; - if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0)) + if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, + &kv0, &value0)) { /* Try to match static mapping by external address and port, destination address and port in packet */ @@ -1374,8 +1457,7 @@ snat_out2in_node_fn (vlib_main_t * vm, thread_index); if (!s0) { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - next0 = SNAT_OUT2IN_NEXT_DROP; + next0 = SNAT_OUT2IN_NEXT_DROP; goto trace00; } } @@ -1383,8 +1465,10 @@ snat_out2in_node_fn (vlib_main_t * vm, { if (PREDICT_FALSE (value0.value == ~0ULL)) { - snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index, now, - vm); + s0 = snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index, + now, vm, node); + if (!s0) + next0 = SNAT_OUT2IN_NEXT_DROP; goto trace00; } else @@ -1492,10 +1576,294 @@ VLIB_REGISTER_NODE (snat_out2in_node) = { [SNAT_OUT2IN_NEXT_DROP] = "error-drop", [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", + [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass", }, }; VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn); +static uword +nat44_out2in_reass_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + snat_out2in_next_t next_index; + u32 pkts_processed = 0; + snat_main_t *sm = &snat_main; + f64 now = vlib_time_now (vm); + u32 thread_index = vlib_get_thread_index (); + snat_main_per_thread_data_t *per_thread_data = + &sm->per_thread_data[thread_index]; + u32 *fragments_to_drop = 0; + u32 *fragments_to_loopback = 0; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0; + vlib_buffer_t *b0; + u32 next0; + u8 cached0 = 0; + ip4_header_t *ip0; + nat_reass_ip4_t *reass0; + udp_header_t * udp0; + tcp_header_t * tcp0; + snat_session_key_t key0, sm0; + clib_bihash_kv_8_8_t kv0, value0; + snat_session_t * s0 = 0; + u16 old_port0, new_port0; + ip_csum_t sum0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + next0 = SNAT_OUT2IN_NEXT_LOOKUP; + + sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, + sw_if_index0); + + if (PREDICT_FALSE (nat_reass_is_drop_frag(0))) + { + next0 = SNAT_OUT2IN_NEXT_DROP; + b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT]; + goto trace0; + } + + ip0 = (ip4_header_t *) vlib_buffer_get_current (b0); + udp0 = ip4_next_header (ip0); + tcp0 = (tcp_header_t *) udp0; + proto0 = ip_proto_to_snat_proto (ip0->protocol); + + reass0 = nat_ip4_reass_find_or_create (ip0->src_address, + ip0->dst_address, + ip0->fragment_id, + ip0->protocol, + 1, + &fragments_to_drop); + + if (PREDICT_FALSE (!reass0)) + { + next0 = SNAT_OUT2IN_NEXT_DROP; + b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS]; + goto trace0; + } + + if (PREDICT_FALSE (ip4_is_first_fragment (ip0))) + { + key0.addr = ip0->dst_address; + key0.port = udp0->dst_port; + key0.protocol = proto0; + key0.fib_index = rx_fib_index0; + kv0.key = key0.as_u64; + + if (clib_bihash_search_8_8 (&per_thread_data->out2in, &kv0, &value0)) + { + /* Try to match static mapping by external address and port, + destination address and port in packet */ + if (snat_static_mapping_match(sm, key0, &sm0, 1, 0)) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + /* + * Send DHCP packets to the ipv4 stack, or we won't + * be able to use dhcp client on the outside interface + */ + if (proto0 != SNAT_PROTOCOL_UDP + || (udp0->dst_port + != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) + + next0 = SNAT_OUT2IN_NEXT_DROP; + goto trace0; + } + + /* Create session initiated by host from external network */ + s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node, + thread_index); + if (!s0) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + next0 = SNAT_OUT2IN_NEXT_DROP; + goto trace0; + } + reass0->sess_index = s0 - per_thread_data->sessions; + } + else + { + s0 = pool_elt_at_index (per_thread_data->sessions, + value0.value); + reass0->sess_index = value0.value; + } + nat_ip4_reass_get_frags (reass0, &fragments_to_loopback); + } + else + { + if (PREDICT_FALSE (reass0->sess_index == (u32) ~0)) + { + if (nat_ip4_reass_add_fragment (reass0, bi0)) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG]; + next0 = SNAT_OUT2IN_NEXT_DROP; + goto trace0; + } + cached0 = 1; + goto trace0; + } + s0 = pool_elt_at_index (per_thread_data->sessions, + reass0->sess_index); + } + + old_addr0 = ip0->dst_address.as_u32; + ip0->dst_address = s0->in2out.addr; + new_addr0 = ip0->dst_address.as_u32; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; + + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + if (PREDICT_FALSE (ip4_is_first_fragment (ip0))) + { + if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) + { + old_port0 = tcp0->dst_port; + tcp0->dst_port = s0->in2out.port; + new_port0 = tcp0->dst_port; + + sum0 = tcp0->checksum; + sum0 = ip_csum_update (sum0, old_addr0, new_addr0, + ip4_header_t, + dst_address /* changed member */); + + sum0 = ip_csum_update (sum0, old_port0, new_port0, + ip4_header_t /* cheat */, + length /* changed member */); + tcp0->checksum = ip_csum_fold(sum0); + } + else + { + old_port0 = udp0->dst_port; + udp0->dst_port = s0->in2out.port; + udp0->checksum = 0; + } + } + + /* Accounting */ + s0->last_heard = now; + s0->total_pkts++; + s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + /* Per-user LRU list maintenance for dynamic translation */ + if (!snat_is_session_static (s0)) + { + clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, + s0->per_user_index); + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, + s0->per_user_list_head_index, + s0->per_user_index); + } + + trace0: + if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + nat44_out2in_reass_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->cached = cached0; + t->sw_if_index = sw_if_index0; + t->next_index = next0; + } + + if (cached0) + { + n_left_to_next++; + to_next--; + } + else + { + pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + if (n_left_from == 0 && vec_len (fragments_to_loopback)) + { + from = vlib_frame_vector_args (frame); + u32 len = vec_len (fragments_to_loopback); + if (len <= VLIB_FRAME_SIZE) + { + clib_memcpy (from, fragments_to_loopback, sizeof (u32) * len); + n_left_from = len; + vec_reset_length (fragments_to_loopback); + } + else + { + clib_memcpy (from, + fragments_to_loopback + (len - VLIB_FRAME_SIZE), + sizeof (u32) * VLIB_FRAME_SIZE); + n_left_from = VLIB_FRAME_SIZE; + _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE; + } + } + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, nat44_out2in_reass_node.index, + SNAT_OUT2IN_ERROR_OUT2IN_PACKETS, + pkts_processed); + + nat_send_all_to_node (vm, fragments_to_drop, node, + &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT], + SNAT_OUT2IN_NEXT_DROP); + + vec_free (fragments_to_drop); + vec_free (fragments_to_loopback); + return frame->n_vectors; +} + +VLIB_REGISTER_NODE (nat44_out2in_reass_node) = { + .function = nat44_out2in_reass_node_fn, + .name = "nat44-out2in-reass", + .vector_size = sizeof (u32), + .format_trace = format_nat44_out2in_reass_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(snat_out2in_error_strings), + .error_strings = snat_out2in_error_strings, + + .n_next_nodes = SNAT_OUT2IN_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [SNAT_OUT2IN_NEXT_DROP] = "error-drop", + [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", + [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", + [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass", + }, +}; +VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node, + nat44_out2in_reass_node_fn); + /**************************/ /*** deterministic mode ***/ /**************************/ @@ -1979,6 +2347,7 @@ VLIB_REGISTER_NODE (snat_det_out2in_node) = { [SNAT_OUT2IN_NEXT_DROP] = "error-drop", [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", + [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass", }, }; VLIB_NODE_FUNCTION_MULTIARCH (snat_det_out2in_node, snat_det_out2in_node_fn); @@ -1998,11 +2367,11 @@ VLIB_NODE_FUNCTION_MULTIARCH (snat_det_out2in_node, snat_det_out2in_node_fn); * @param e optional parameter */ u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, - u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, + 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) { - ip4_header_t *ip0; icmp46_header_t *icmp0; u32 sw_if_index0; u8 protocol; @@ -2018,7 +2387,6 @@ u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, snat_det_session_t * ses0 = 0; ip4_address_t out_addr; - ip0 = vlib_buffer_get_current (b0); icmp0 = (icmp46_header_t *) ip4_next_header (ip0); echo0 = (icmp_echo_header_t *)(icmp0+1); sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; @@ -2472,6 +2840,7 @@ VLIB_REGISTER_NODE (snat_out2in_fast_node) = { [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", [SNAT_OUT2IN_NEXT_DROP] = "error-drop", [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", + [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass", }, }; VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node, snat_out2in_fast_node_fn);