X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fout2in.c;h=83e1426a413d7d183eeec3145fdcfd2a7aef88b2;hb=229c1aaf7501afa95c3768702bb1e76beb59384c;hp=f6d6a0a102d4ba5fdc0d5e92808c46c318f67b16;hpb=03f942a1cc4de3963507fc7075d91aff0cae7d58;p=vpp.git diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c index f6d6a0a102d..83e1426a413 100755 --- a/src/plugins/nat/out2in.c +++ b/src/plugins/nat/out2in.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -113,7 +114,8 @@ _(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") +_(MAX_FRAG, "Maximum fragments per reassembly exceeded")\ +_(FQ_CONGESTED, "Handoff frame queue congested") typedef enum { #define _(sym,str) SNAT_OUT2IN_ERROR_##sym, @@ -133,6 +135,7 @@ typedef enum { SNAT_OUT2IN_NEXT_LOOKUP, SNAT_OUT2IN_NEXT_ICMP_ERROR, SNAT_OUT2IN_NEXT_REASS, + SNAT_OUT2IN_NEXT_IN2OUT, SNAT_OUT2IN_N_NEXT, } snat_out2in_next_t; @@ -167,6 +170,7 @@ create_session_for_static_mapping (snat_main_t *sm, if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index))) { b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED]; + nat_log_notice ("maximum sessions exceeded"); return 0; } @@ -176,14 +180,14 @@ create_session_for_static_mapping (snat_main_t *sm, u = nat_user_get_or_create (sm, &in2out.addr, in2out.fib_index, thread_index); if (!u) { - clib_warning ("create NAT user failed"); + nat_log_warn ("create NAT user failed"); return 0; } s = nat_session_alloc_or_recycle (sm, u, thread_index); if (!s) { - clib_warning ("create NAT session failed"); + nat_log_warn ("create NAT session failed"); return 0; } @@ -191,7 +195,7 @@ create_session_for_static_mapping (snat_main_t *sm, s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; s->ext_host_addr.as_u32 = ip0->src_address.as_u32; s->ext_host_port = udp0->src_port; - u->nstaticsessions++; + user_session_increment (sm, u, 1 /* static */); s->in2out = in2out; s->out2in = out2in; s->in2out.protocol = out2in.protocol; @@ -201,13 +205,13 @@ create_session_for_static_mapping (snat_main_t *sm, kv0.value = s - sm->per_thread_data[thread_index].sessions; if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0, 1 /* is_add */)) - clib_warning ("in2out key add failed"); + nat_log_notice ("in2out key add failed"); kv0.key = s->out2in.as_u64; if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0, 1 /* is_add */)) - clib_warning ("out2in key add failed"); + nat_log_notice ("out2in key add failed"); /* log NAT event */ snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32, @@ -311,12 +315,37 @@ icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0) return 0; } +static int +next_src_nat (snat_main_t * sm, ip4_header_t * ip, u32 proto, u16 src_port, + u32 thread_index) +{ + snat_session_key_t key; + clib_bihash_kv_8_8_t kv, value; + + key.addr = ip->src_address; + key.port = src_port; + key.protocol = proto; + key.fib_index = sm->inside_fib_index; + kv.key = key.as_u64; + + if (!clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out, &kv, + &value)) + return 1; + + return 0; +} + static void -create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip) +create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index, + u32 thread_index) { nat_ed_ses_key_t key; - clib_bihash_kv_16_8_t kv; + clib_bihash_kv_16_8_t kv, value; udp_header_t *udp; + snat_user_t *u; + snat_session_t *s = 0; + snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; + f64 now = vlib_time_now (sm->vlib_main); if (ip->protocol == IP_PROTOCOL_ICMP) { @@ -342,10 +371,56 @@ create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip) key.fib_index = 0; kv.key[0] = key.as_u64[0]; kv.key[1] = key.as_u64[1]; - kv.value = ~0ULL; - if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &kv, 1)) - clib_warning ("in2out_ed key add failed"); + if (!clib_bihash_search_16_8 (&sm->in2out_ed, &kv, &value)) + { + s = pool_elt_at_index (tsm->sessions, value.value); + } + else + { + if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index))) + return; + + u = nat_user_get_or_create (sm, &ip->dst_address, sm->inside_fib_index, thread_index); + if (!u) + { + nat_log_warn ("create NAT user failed"); + return; + } + + s = nat_session_alloc_or_recycle (sm, u, thread_index); + if (!s) + { + nat_log_warn ("create NAT session failed"); + return; + } + + s->ext_host_addr = key.r_addr; + s->ext_host_port = key.r_port; + s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS; + s->outside_address_index = ~0; + s->out2in.addr = key.l_addr; + s->out2in.port = key.l_port; + s->out2in.protocol = ip_proto_to_snat_proto (key.proto); + s->out2in.fib_index = 0; + s->in2out = s->out2in; + user_session_increment (sm, u, 0); + + kv.value = s - tsm->sessions; + if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &kv, 1)) + nat_log_notice ("in2out_ed key add failed"); + } + + if (ip->protocol == IP_PROTOCOL_TCP) + { + tcp_header_t *tcp = ip4_next_header(ip); + if (nat44_set_tcp_session_state_o2i (sm, s, tcp, thread_index)) + return; + } + /* Per-user LRU list maintenance */ + nat44_session_update_lru (sm, s, thread_index); + /* Accounting */ + nat44_session_update_counters (s, now, 0); } /** @@ -402,7 +477,7 @@ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, { /* 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, &is_addr_only, 0)) + if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0, 0)) { if (!sm->forwarding_enabled) { @@ -419,8 +494,13 @@ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, } else { - create_bypass_for_fwd(sm, ip0); dont_translate = 1; + if (next_src_nat(sm, ip0, key0.protocol, key0.port, thread_index)) + { + next0 = SNAT_OUT2IN_NEXT_IN2OUT; + goto out; + } + create_bypass_for_fwd(sm, ip0, rx_fib_index0, thread_index); goto out; } } @@ -536,7 +616,7 @@ u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, } key0.fib_index = rx_fib_index0; - if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0)) + if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0, 0)) { /* Don't NAT packet aimed at the intfc address */ if (is_interface_addr(sm, node, sw_if_index0, ip0->dst_address.as_u32)) @@ -618,6 +698,9 @@ static inline u32 icmp_out2in (snat_main_t *sm, dst_address /* changed member */); ip0->checksum = ip_csum_fold (sum0); + if (icmp0->checksum == 0) + icmp0->checksum = 0xffff; + if (!icmp_is_error_message (icmp0)) { new_id0 = sm0.port; @@ -706,15 +789,10 @@ static inline u32 icmp_out2in_slow_path (snat_main_t *sm, if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0)) { /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0); + nat44_session_update_counters (s0, now, + vlib_buffer_length_in_chain (sm->vlib_main, b0)); /* Per-user LRU list maintenance */ - 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); + nat44_session_update_lru (sm, s0, thread_index); } return next0; } @@ -761,6 +839,7 @@ snat_out2in_unknown_proto (snat_main_t *sm, if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index))) { b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED]; + nat_log_notice ("maximum sessions exceeded"); return 0; } @@ -783,7 +862,7 @@ snat_out2in_unknown_proto (snat_main_t *sm, thread_index); if (!u) { - clib_warning ("create NAT user failed"); + nat_log_warn ("create NAT user failed"); return 0; } @@ -791,32 +870,33 @@ snat_out2in_unknown_proto (snat_main_t *sm, s = nat_session_alloc_or_recycle (sm, u, thread_index); if (!s) { - clib_warning ("create NAT session failed"); + nat_log_warn ("create NAT session failed"); return 0; } s->ext_host_addr.as_u32 = ip->src_address.as_u32; s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO; s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; + s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT; s->outside_address_index = ~0; s->out2in.addr.as_u32 = old_addr; s->out2in.fib_index = rx_fib_index; s->in2out.addr.as_u32 = new_addr; s->in2out.fib_index = m->fib_index; s->in2out.port = s->out2in.port = ip->protocol; - u->nstaticsessions++; + user_session_increment (sm, u, 1 /* static */); /* Add to lookup tables */ s_kv.value = s - tsm->sessions; if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1)) - clib_warning ("out2in key add failed"); + nat_log_notice ("out2in key add failed"); key.l_addr = ip->dst_address; key.fib_index = m->fib_index; s_kv.key[0] = key.as_u64[0]; s_kv.key[1] = key.as_u64[1]; if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1)) - clib_warning ("in2out key add failed"); + nat_log_notice ("in2out key add failed"); } /* Update IP checksum */ @@ -827,13 +907,10 @@ snat_out2in_unknown_proto (snat_main_t *sm, vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index; /* Accounting */ - s->last_heard = now; - s->total_pkts++; - s->total_bytes += vlib_buffer_length_in_chain (vm, b); + nat44_session_update_counters (s, now, + vlib_buffer_length_in_chain (vm, b)); /* Per-user LRU list maintenance */ - 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); + nat44_session_update_lru (sm, s, thread_index); return s; } @@ -862,7 +939,8 @@ snat_out2in_lb (snat_main_t *sm, snat_user_t *u; u32 address_index; snat_session_key_t eh_key; - u8 twice_nat; + twice_nat_type_t twice_nat; + u8 lb; old_addr = ip->dst_address.as_u32; @@ -884,6 +962,7 @@ snat_out2in_lb (snat_main_t *sm, if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index))) { b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED]; + nat_log_notice ("maximum sessions exceeded"); return 0; } @@ -891,39 +970,43 @@ snat_out2in_lb (snat_main_t *sm, 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, &twice_nat)) + if (snat_static_mapping_match(sm, e_key, &l_key, 1, 0, &twice_nat, &lb)) return 0; u = nat_user_get_or_create (sm, &l_key.addr, l_key.fib_index, thread_index); if (!u) { - clib_warning ("create NAT user failed"); + nat_log_warn ("create NAT user failed"); return 0; } s = nat_session_alloc_or_recycle (sm, u, thread_index); if (!s) { - clib_warning ("create NAT session failed"); + nat_log_warn ("create NAT session failed"); return 0; } s->ext_host_addr.as_u32 = ip->src_address.as_u32; s->ext_host_port = udp->src_port; s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; - s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING; + if (lb) + s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING; + s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT; s->outside_address_index = ~0; s->out2in = e_key; s->in2out = l_key; - u->nstaticsessions++; + user_session_increment (sm, u, 1 /* static */); /* Add to lookup tables */ s_kv.value = s - tsm->sessions; if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1)) - clib_warning ("out2in-ed key add failed"); + nat_log_notice ("out2in-ed key add failed"); - if (twice_nat) + if (twice_nat == TWICE_NAT || + (twice_nat == TWICE_NAT_SELF && + ip->src_address.as_u32 == l_key.addr.as_u32)) { eh_key.protocol = proto; if (snat_alloc_outside_address_and_port (sm->twice_nat_addresses, 0, @@ -945,7 +1028,7 @@ snat_out2in_lb (snat_main_t *sm, s_kv.key[0] = key.as_u64[0]; s_kv.key[1] = key.as_u64[1]; if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1)) - clib_warning ("in2out-ed key add failed"); + nat_log_notice ("in2out-ed key add failed"); } new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32; @@ -959,6 +1042,8 @@ snat_out2in_lb (snat_main_t *sm, src_address); ip->checksum = ip_csum_fold (sum); + vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index; + if (PREDICT_TRUE(proto == SNAT_PROTOCOL_TCP)) { old_port = tcp->dst_port; @@ -979,6 +1064,8 @@ snat_out2in_lb (snat_main_t *sm, ip->src_address.as_u32 = s->ext_host_nat_addr.as_u32; } tcp->checksum = ip_csum_fold(sum); + if (nat44_set_tcp_session_state_o2i (sm, s, tcp, thread_index)) + return s; } else { @@ -991,16 +1078,10 @@ snat_out2in_lb (snat_main_t *sm, udp->checksum = 0; } - vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index; - /* Accounting */ - s->last_heard = now; - s->total_pkts++; - s->total_bytes += vlib_buffer_length_in_chain (vm, b); + nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b)); /* Per-user LRU list maintenance */ - 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); + nat44_session_update_lru (sm, s, thread_index); return s; } @@ -1135,28 +1216,35 @@ snat_out2in_node_fn (vlib_main_t * vm, { /* 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, 0)) + if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0)) { + /* + * Send DHCP packets to the ipv4 stack, or we won't + * be able to use dhcp client on the outside interface + */ + if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP + && (udp0->dst_port == + clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))) + { + vnet_feature_next + (vnet_buffer (b0)->sw_if_index[VLIB_RX], &next0, b0); + goto trace0; + } + if (!sm->forwarding_enabled) { 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 (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP - || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))) - next0 = SNAT_OUT2IN_NEXT_DROP; - else - vnet_feature_next - (vnet_buffer (b0)->sw_if_index[VLIB_RX], - &next0, b0); + next0 = SNAT_OUT2IN_NEXT_DROP; goto trace0; } else { - create_bypass_for_fwd(sm, ip0); + if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index)) + { + next0 = SNAT_OUT2IN_NEXT_IN2OUT; + goto trace0; + } + create_bypass_for_fwd(sm, ip0, rx_fib_index0, thread_index); goto trace0; } } @@ -1223,15 +1311,10 @@ snat_out2in_node_fn (vlib_main_t * vm, } /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + nat44_session_update_counters (s0, now, + vlib_buffer_length_in_chain (vm, b0)); /* Per-user LRU list maintenance */ - 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); + nat44_session_update_lru (sm, s0, thread_index); trace0: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1306,28 +1389,35 @@ snat_out2in_node_fn (vlib_main_t * vm, { /* Try to match static mapping by external address and port, destination address and port in packet */ - if (snat_static_mapping_match(sm, key1, &sm1, 1, 0, 0)) + if (snat_static_mapping_match(sm, key1, &sm1, 1, 0, 0, 0)) { + /* + * Send DHCP packets to the ipv4 stack, or we won't + * be able to use dhcp client on the outside interface + */ + if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_UDP + && (udp1->dst_port == + clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))) + { + vnet_feature_next + (vnet_buffer (b1)->sw_if_index[VLIB_RX], &next1, b1); + goto trace1; + } + if (!sm->forwarding_enabled) { b1->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 (PREDICT_TRUE (proto1 != SNAT_PROTOCOL_UDP - || (udp1->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))) - next1 = SNAT_OUT2IN_NEXT_DROP; - else - vnet_feature_next - (vnet_buffer (b1)->sw_if_index[VLIB_RX], - &next1, b1); + next1 = SNAT_OUT2IN_NEXT_DROP; goto trace1; } else { - create_bypass_for_fwd(sm, ip1); + if (next_src_nat(sm, ip1, proto1, udp1->src_port, thread_index)) + { + next1 = SNAT_OUT2IN_NEXT_IN2OUT; + goto trace1; + } + create_bypass_for_fwd(sm, ip1, rx_fib_index1, thread_index); goto trace1; } } @@ -1394,15 +1484,10 @@ snat_out2in_node_fn (vlib_main_t * vm, } /* Accounting */ - s1->last_heard = now; - s1->total_pkts++; - s1->total_bytes += vlib_buffer_length_in_chain (vm, b1); + nat44_session_update_counters (s1, now, + vlib_buffer_length_in_chain (vm, b1)); /* Per-user LRU list maintenance */ - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s1->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s1->per_user_list_head_index, - s1->per_user_index); + nat44_session_update_lru (sm, s1, thread_index); trace1: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1513,28 +1598,35 @@ snat_out2in_node_fn (vlib_main_t * vm, { /* 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, 0)) + if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0)) { + /* + * Send DHCP packets to the ipv4 stack, or we won't + * be able to use dhcp client on the outside interface + */ + if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP + && (udp0->dst_port == + clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))) + { + vnet_feature_next + (vnet_buffer (b0)->sw_if_index[VLIB_RX], &next0, b0); + goto trace00; + } + if (!sm->forwarding_enabled) { 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 (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP - || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))) - next0 = SNAT_OUT2IN_NEXT_DROP; - else - vnet_feature_next - (vnet_buffer (b0)->sw_if_index[VLIB_RX], - &next0, b0); + next0 = SNAT_OUT2IN_NEXT_DROP; goto trace00; } else { - create_bypass_for_fwd(sm, ip0); + if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index)) + { + next0 = SNAT_OUT2IN_NEXT_IN2OUT; + goto trace00; + } + create_bypass_for_fwd(sm, ip0, rx_fib_index0, thread_index); goto trace00; } } @@ -1601,15 +1693,10 @@ snat_out2in_node_fn (vlib_main_t * vm, } /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + nat44_session_update_counters (s0, now, + vlib_buffer_length_in_chain (vm, b0)); /* Per-user LRU list maintenance */ - 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); + nat44_session_update_lru (sm, s0, thread_index); trace00: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1661,6 +1748,7 @@ VLIB_REGISTER_NODE (snat_out2in_node) = { [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass", + [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out", }, }; VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn); @@ -1745,6 +1833,7 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm, { next0 = SNAT_OUT2IN_NEXT_DROP; b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS]; + nat_log_notice ("maximum reassemblies exceeded"); goto trace0; } @@ -1760,28 +1849,36 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm, { /* 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, 0)) + if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0)) { + /* + * Send DHCP packets to the ipv4 stack, or we won't + * be able to use dhcp client on the outside interface + */ + if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP + && (udp0->dst_port + == clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))) + { + vnet_feature_next + (vnet_buffer (b0)->sw_if_index[VLIB_RX], + &next0, b0); + goto trace0; + } + if (!sm->forwarding_enabled) { 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 (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP - || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))) - next0 = SNAT_OUT2IN_NEXT_DROP; - else - vnet_feature_next - (vnet_buffer (b0)->sw_if_index[VLIB_RX], - &next0, b0); + next0 = SNAT_OUT2IN_NEXT_DROP; goto trace0; } else { - create_bypass_for_fwd(sm, ip0); + if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index)) + { + next0 = SNAT_OUT2IN_NEXT_IN2OUT; + goto trace0; + } + create_bypass_for_fwd(sm, ip0, rx_fib_index0, thread_index); goto trace0; } } @@ -1813,6 +1910,7 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm, if (nat_ip4_reass_add_fragment (reass0, bi0)) { b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG]; + nat_log_notice ("maximum fragments per reassembly exceeded"); next0 = SNAT_OUT2IN_NEXT_DROP; goto trace0; } @@ -1861,15 +1959,10 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm, } /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + nat44_session_update_counters (s0, now, + vlib_buffer_length_in_chain (vm, b0)); /* Per-user LRU list maintenance */ - 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); + nat44_session_update_lru (sm, s0, thread_index); trace0: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1952,6 +2045,7 @@ VLIB_REGISTER_NODE (nat44_out2in_reass_node) = { [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass", + [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out", }, }; VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node, @@ -2063,8 +2157,8 @@ snat_det_out2in_node_fn (vlib_main_t * vm, dm0 = snat_det_map_by_out(sm, &ip0->dst_address); if (PREDICT_FALSE(!dm0)) { - clib_warning("unknown dst address: %U", - format_ip4_address, &ip0->dst_address); + nat_log_info ("unknown dst address: %U", + format_ip4_address, &ip0->dst_address); next0 = SNAT_OUT2IN_NEXT_DROP; b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace0; @@ -2076,12 +2170,12 @@ snat_det_out2in_node_fn (vlib_main_t * vm, ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64); if (PREDICT_FALSE(!ses0)) { - clib_warning("no match src %U:%d dst %U:%d for user %U", - format_ip4_address, &ip0->src_address, - clib_net_to_host_u16 (tcp0->src), - format_ip4_address, &ip0->dst_address, - clib_net_to_host_u16 (tcp0->dst), - format_ip4_address, &new_addr0); + nat_log_info ("no match src %U:%d dst %U:%d for user %U", + format_ip4_address, &ip0->src_address, + clib_net_to_host_u16 (tcp0->src), + format_ip4_address, &ip0->dst_address, + clib_net_to_host_u16 (tcp0->dst), + format_ip4_address, &new_addr0); next0 = SNAT_OUT2IN_NEXT_DROP; b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace0; @@ -2179,8 +2273,8 @@ snat_det_out2in_node_fn (vlib_main_t * vm, dm1 = snat_det_map_by_out(sm, &ip1->dst_address); if (PREDICT_FALSE(!dm1)) { - clib_warning("unknown dst address: %U", - format_ip4_address, &ip1->dst_address); + nat_log_info ("unknown dst address: %U", + format_ip4_address, &ip1->dst_address); next1 = SNAT_OUT2IN_NEXT_DROP; b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace1; @@ -2192,12 +2286,12 @@ snat_det_out2in_node_fn (vlib_main_t * vm, ses1 = snat_det_get_ses_by_out (dm1, &new_addr1, key1.as_u64); if (PREDICT_FALSE(!ses1)) { - clib_warning("no match src %U:%d dst %U:%d for user %U", - format_ip4_address, &ip1->src_address, - clib_net_to_host_u16 (tcp1->src), - format_ip4_address, &ip1->dst_address, - clib_net_to_host_u16 (tcp1->dst), - format_ip4_address, &new_addr1); + nat_log_info ("no match src %U:%d dst %U:%d for user %U", + format_ip4_address, &ip1->src_address, + clib_net_to_host_u16 (tcp1->src), + format_ip4_address, &ip1->dst_address, + clib_net_to_host_u16 (tcp1->dst), + format_ip4_address, &new_addr1); next1 = SNAT_OUT2IN_NEXT_DROP; b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace1; @@ -2328,8 +2422,8 @@ snat_det_out2in_node_fn (vlib_main_t * vm, dm0 = snat_det_map_by_out(sm, &ip0->dst_address); if (PREDICT_FALSE(!dm0)) { - clib_warning("unknown dst address: %U", - format_ip4_address, &ip0->dst_address); + nat_log_info ("unknown dst address: %U", + format_ip4_address, &ip0->dst_address); next0 = SNAT_OUT2IN_NEXT_DROP; b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace00; @@ -2341,12 +2435,12 @@ snat_det_out2in_node_fn (vlib_main_t * vm, ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64); if (PREDICT_FALSE(!ses0)) { - clib_warning("no match src %U:%d dst %U:%d for user %U", - format_ip4_address, &ip0->src_address, - clib_net_to_host_u16 (tcp0->src), - format_ip4_address, &ip0->dst_address, - clib_net_to_host_u16 (tcp0->dst), - format_ip4_address, &new_addr0); + nat_log_info ("no match src %U:%d dst %U:%d for user %U", + format_ip4_address, &ip0->src_address, + clib_net_to_host_u16 (tcp0->src), + format_ip4_address, &ip0->dst_address, + clib_net_to_host_u16 (tcp0->dst), + format_ip4_address, &new_addr0); next0 = SNAT_OUT2IN_NEXT_DROP; b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace00; @@ -2441,6 +2535,7 @@ VLIB_REGISTER_NODE (snat_det_out2in_node) = { [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass", + [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out", }, }; VLIB_NODE_FUNCTION_MULTIARCH (snat_det_out2in_node, snat_det_out2in_node_fn); @@ -2529,8 +2624,8 @@ u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, dont_translate = 1; goto out; } - clib_warning("unknown dst address: %U", - format_ip4_address, &ip0->dst_address); + nat_log_info ("unknown dst address: %U", + format_ip4_address, &ip0->dst_address); goto out; } @@ -2547,12 +2642,12 @@ u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, dont_translate = 1; goto out; } - clib_warning("no match src %U:%d dst %U:%d for user %U", - format_ip4_address, &key0.ext_host_addr, - clib_net_to_host_u16 (key0.ext_host_port), - format_ip4_address, &out_addr, - clib_net_to_host_u16 (key0.out_port), - format_ip4_address, &new_addr0); + nat_log_info ("no match src %U:%d dst %U:%d for user %U", + format_ip4_address, &key0.ext_host_addr, + clib_net_to_host_u16 (key0.ext_host_port), + format_ip4_address, &out_addr, + clib_net_to_host_u16 (key0.out_port), + format_ip4_address, &new_addr0); b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; next0 = SNAT_OUT2IN_NEXT_DROP; goto out; @@ -2594,17 +2689,19 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, { snat_main_t *sm = &snat_main; vlib_thread_main_t *tm = vlib_get_thread_main (); - u32 n_left_from, *from, *to_next = 0; + u32 n_left_from, *from, *to_next = 0, *to_next_drop = 0; static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index; static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index = 0; vlib_frame_queue_elt_t *hf = 0; + vlib_frame_queue_t *fq; vlib_frame_t *f = 0; int i; u32 n_left_to_next_worker = 0, *to_next_worker = 0; u32 next_worker_index = 0; u32 current_worker_index = ~0; u32 thread_index = vlib_get_thread_index (); + vlib_frame_t *d = 0; ASSERT (vec_len (sm->workers)); @@ -2613,7 +2710,7 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1); vec_validate_init_empty (congested_handoff_queue_by_worker_index, - sm->first_worker_index + sm->num_workers - 1, + tm->n_vlib_mains - 1, (vlib_frame_queue_t *) (~0)); } @@ -2648,6 +2745,26 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, if (next_worker_index != current_worker_index) { + fq = is_vlib_frame_queue_congested ( + sm->fq_out2in_index, next_worker_index, NAT_FQ_NELTS - 2, + congested_handoff_queue_by_worker_index); + + if (fq) + { + /* if this is 1st frame */ + if (!d) + { + d = vlib_get_frame_to_node (vm, sm->error_node_index); + to_next_drop = vlib_frame_vector_args (d); + } + + to_next_drop[0] = bi0; + to_next_drop += 1; + d->n_vectors++; + b0->error = node->errors[SNAT_OUT2IN_ERROR_FQ_CONGESTED]; + goto trace0; + } + if (hf) hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; @@ -2689,6 +2806,7 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, f->n_vectors++; } +trace0: if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED))) { @@ -2702,6 +2820,9 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, if (f) vlib_put_frame_to_node (vm, sm->out2in_node_index, f); + if (d) + vlib_put_frame_to_node (vm, sm->error_node_index, d); + if (hf) hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; @@ -2738,6 +2859,9 @@ VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node) = { .format_trace = format_snat_out2in_worker_handoff_trace, .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(snat_out2in_error_strings), + .error_strings = snat_out2in_error_strings, + .n_next_nodes = 1, .next_nodes = { @@ -2831,7 +2955,7 @@ snat_out2in_fast_node_fn (vlib_main_t * vm, key0.port = udp0->dst_port; key0.fib_index = rx_fib_index0; - if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0)) + if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0)) { b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace00; @@ -2934,6 +3058,7 @@ VLIB_REGISTER_NODE (snat_out2in_fast_node) = { [SNAT_OUT2IN_NEXT_DROP] = "error-drop", [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass", + [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out", }, }; VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node, snat_out2in_fast_node_fn);