X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fin2out.c;h=1659ed0fec3264bbde810d716217d987aeceb91b;hb=70a26ac05f2ab9d4cc0669599b09f654de580f36;hp=f009ce47d78088be8c959a0795b16b85abca5765;hpb=9691cf2d082727fb2f88e85050068dc6fd761bcd;p=vpp.git diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c index f009ce47d78..1659ed0fec3 100755 --- a/src/plugins/nat/in2out.c +++ b/src/plugins/nat/in2out.c @@ -239,7 +239,7 @@ snat_not_translate (snat_main_t * sm, vlib_node_runtime_t *node, &value0)) { /* or is static mappings */ - if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0)) + if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0)) return 0; } else @@ -254,21 +254,41 @@ snat_not_translate (snat_main_t * sm, vlib_node_runtime_t *node, static inline int nat_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip0, - u32 proto0, u32 thread_index) + u32 proto0, u16 src_port, u16 dst_port, + u32 thread_index, u32 sw_if_index) { - udp_header_t * udp0 = ip4_next_header (ip0); snat_session_key_t key0; clib_bihash_kv_8_8_t kv0, value0; + snat_interface_t *i; + /* src NAT check */ key0.addr = ip0->src_address; - key0.port = udp0->src_port; + key0.port = src_port; key0.protocol = proto0; key0.fib_index = sm->outside_fib_index; kv0.key = key0.as_u64; if (!clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0, - &value0)) + &value0)) + return 1; + + /* dst NAT check */ + key0.addr = ip0->dst_address; + key0.port = dst_port; + key0.protocol = proto0; + key0.fib_index = sm->inside_fib_index; + kv0.key = key0.as_u64; + if (!clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0, + &value0)) + { + /* hairpinning */ + pool_foreach (i, sm->output_feature_interfaces, + ({ + if ((nat_interface_is_inside(i)) && (sw_if_index == i->sw_if_index)) + return 0; + })); return 1; + } return 0; } @@ -290,6 +310,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, u32 outside_fib_index; uword * p; udp_header_t * udp0 = ip4_next_header (ip0); + u8 is_sm = 0; if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index))) { @@ -317,7 +338,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, } /* First try to match static mapping by local address and port */ - if (snat_static_mapping_match (sm, *key0, &key1, 0, 0, 0)) + if (snat_static_mapping_match (sm, *key0, &key1, 0, 0, 0, 0)) { /* Try to create dynamic translation */ if (snat_alloc_outside_address_and_port (sm->addresses, rx_fib_index0, @@ -329,12 +350,9 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS]; return SNAT_IN2OUT_NEXT_DROP; } - u->nsessions++; } else - { - u->nstaticsessions++; - } + is_sm = 1; s = nat_session_alloc_or_recycle (sm, u, thread_index); if (!s) @@ -343,8 +361,9 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, return SNAT_IN2OUT_NEXT_DROP; } - if (address_index == ~0) + if (is_sm) s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; + user_session_increment (sm, u, is_sm); s->outside_address_index = address_index; s->in2out = *key0; s->out2in = key1; @@ -471,11 +490,15 @@ icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0) } static inline int -nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip) +nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip, + u32 thread_index) { nat_ed_ses_key_t key; clib_bihash_kv_16_8_t kv, value; udp_header_t *udp; + 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 (!sm->forwarding_enabled) return 0; @@ -506,7 +529,28 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip) kv.key[1] = key.as_u64[1]; if (!clib_bihash_search_16_8 (&sm->in2out_ed, &kv, &value)) - return value.value == ~0ULL; + { + s = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value.value); + if (is_fwd_bypass_session (s)) + { + if (ip->protocol == IP_PROTOCOL_TCP) + { + tcp_header_t *tcp = ip4_next_header(ip); + if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index)) + return 1; + } + /* 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); + /* Accounting */ + s->last_heard = now; + s->total_pkts++; + return 1; + } + else + return 0; + } return 0; } @@ -562,7 +606,7 @@ u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, if (vnet_buffer(b0)->sw_if_index[VLIB_TX] != ~0) { if (PREDICT_FALSE(nat_not_translate_output_feature(sm, - ip0, IP_PROTOCOL_ICMP, thread_index))) + ip0, SNAT_PROTOCOL_ICMP, key0.port, key0.port, thread_index, sw_if_index0))) { dont_translate = 1; goto out; @@ -571,7 +615,7 @@ u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, else { if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0, - ip0, IP_PROTOCOL_ICMP, rx_fib_index0, thread_index))) + ip0, SNAT_PROTOCOL_ICMP, rx_fib_index0, thread_index))) { dont_translate = 1; goto out; @@ -684,7 +728,7 @@ u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, } key0.fib_index = rx_fib_index0; - if (snat_static_mapping_match(sm, key0, &sm0, 0, &is_addr_only, 0)) + if (snat_static_mapping_match(sm, key0, &sm0, 0, &is_addr_only, 0, 0)) { if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0, IP_PROTOCOL_ICMP, rx_fib_index0))) @@ -774,6 +818,9 @@ static inline u32 icmp_in2out (snat_main_t *sm, src_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; @@ -880,7 +927,7 @@ snat_hairpinning (snat_main_t *sm, kv0.key = key0.as_u64; /* Check if destination is static mappings */ - if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0)) + if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0)) { new_dst_addr0 = sm0.addr.as_u32; new_dst_port0 = sm0.port; @@ -981,7 +1028,7 @@ snat_icmp_hairpinning (snat_main_t *sm, &value0)) { /* or static mappings */ - if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0)) + if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0)) { new_dst_addr0 = sm0.addr.as_u32; vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index; @@ -1136,7 +1183,7 @@ snat_in2out_unknown_proto (snat_main_t *sm, key.fib_index = rx_fib_index; key.proto = ip->protocol; key.l_port = 0; - key.l_port = 0; + key.r_port = 0; s_kv.key[0] = key.as_u64[0]; s_kv.key[1] = key.as_u64[1]; @@ -1180,34 +1227,37 @@ snat_in2out_unknown_proto (snat_main_t *sm, else { /* Choose same out address as for TCP/UDP session to same destination */ - if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) + head_index = u->sessions_per_user_list_head_index; + head = pool_elt_at_index (tsm->list_pool, head_index); + elt_index = head->next; + if (PREDICT_FALSE (elt_index == ~0)) + ses_index = ~0; + else + { + elt = pool_elt_at_index (tsm->list_pool, elt_index); + ses_index = elt->value; + } + + while (ses_index != ~0) { - head_index = u->sessions_per_user_list_head_index; - head = pool_elt_at_index (tsm->list_pool, head_index); - elt_index = head->next; + s = pool_elt_at_index (tsm->sessions, ses_index); + elt_index = elt->next; elt = pool_elt_at_index (tsm->list_pool, elt_index); ses_index = elt->value; - while (ses_index != ~0) - { - s = pool_elt_at_index (tsm->sessions, ses_index); - elt_index = elt->next; - elt = pool_elt_at_index (tsm->list_pool, elt_index); - ses_index = elt->value; - if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32) - { - new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32; - address_index = s->outside_address_index; + if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32) + { + new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32; + address_index = s->outside_address_index; - key.fib_index = sm->outside_fib_index; - key.l_addr.as_u32 = new_addr; - s_kv.key[0] = key.as_u64[0]; - s_kv.key[1] = key.as_u64[1]; - if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value)) - break; + key.fib_index = sm->outside_fib_index; + key.l_addr.as_u32 = new_addr; + s_kv.key[0] = key.as_u64[0]; + s_kv.key[1] = key.as_u64[1]; + if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value)) + break; - goto create_ses; - } + goto create_ses; } } key.fib_index = sm->outside_fib_index; @@ -1236,6 +1286,7 @@ create_ses: s->ext_host_addr.as_u32 = ip->dst_address.as_u32; s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO; + s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT; s->outside_address_index = address_index; s->out2in.addr.as_u32 = new_addr; s->out2in.fib_index = sm->outside_fib_index; @@ -1243,14 +1294,8 @@ create_ses: s->in2out.fib_index = rx_fib_index; s->in2out.port = s->out2in.port = ip->protocol; if (is_sm) - { - u->nstaticsessions++; - s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; - } - else - { - u->nsessions++; - } + s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; + user_session_increment (sm, u, is_sm); /* Add to lookup tables */ key.l_addr.as_u32 = old_addr; @@ -1317,6 +1362,7 @@ snat_in2out_lb (snat_main_t *sm, u32 proto = ip_proto_to_snat_proto (ip->protocol); snat_session_key_t e_key, l_key; snat_user_t *u; + u8 lb; old_addr = ip->src_address.as_u32; @@ -1331,9 +1377,20 @@ snat_in2out_lb (snat_main_t *sm, if (!clib_bihash_search_16_8 (&sm->in2out_ed, &s_kv, &s_value)) { - if (s_value.value == ~0ULL) - return 0; s = pool_elt_at_index (tsm->sessions, s_value.value); + if (is_fwd_bypass_session (s)) + { + if (ip->protocol == IP_PROTOCOL_TCP) + { + if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index)) + return 0; + } + /* 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); + return 0; + } } else { @@ -1348,7 +1405,7 @@ snat_in2out_lb (snat_main_t *sm, l_key.port = udp->src_port; l_key.protocol = proto; l_key.fib_index = rx_fib_index; - if (snat_static_mapping_match(sm, l_key, &e_key, 0, 0, 0)) + if (snat_static_mapping_match(sm, l_key, &e_key, 0, 0, 0, &lb)) return 0; u = nat_user_get_or_create (sm, &ip->src_address, rx_fib_index, @@ -1368,12 +1425,14 @@ snat_in2out_lb (snat_main_t *sm, s->ext_host_addr.as_u32 = ip->dst_address.as_u32; 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->in2out = l_key; s->out2in = e_key; s->out2in.protocol = l_key.protocol; - u->nstaticsessions++; + user_session_increment (sm, u, 1 /* static */); /* Add to lookup tables */ s_kv.value = s - tsm->sessions; @@ -1399,6 +1458,9 @@ snat_in2out_lb (snat_main_t *sm, s->ext_host_addr.as_u32, ip4_header_t, dst_address); ip->checksum = ip_csum_fold (sum); + if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0) + vnet_buffer(b)->sw_if_index[VLIB_TX] = sm->outside_fib_index; + if (PREDICT_TRUE(proto == SNAT_PROTOCOL_TCP)) { old_port = tcp->src_port; @@ -1419,6 +1481,8 @@ snat_in2out_lb (snat_main_t *sm, ip->dst_address.as_u32 = s->ext_host_addr.as_u32; } tcp->checksum = ip_csum_fold(sum); + if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index)) + return s; } else { @@ -1431,9 +1495,6 @@ snat_in2out_lb (snat_main_t *sm, udp->checksum = 0; } - if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0) - vnet_buffer(b)->sw_if_index[VLIB_TX] = sm->outside_fib_index; - /* Accounting */ s->last_heard = now; s->total_pkts++; @@ -1570,7 +1631,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, { if (is_output_feature) { - if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip0))) + if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip0, thread_index))) goto trace00; } @@ -1602,7 +1663,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, if (is_output_feature) { if (PREDICT_FALSE(nat_not_translate_output_feature(sm, - ip0, proto0, thread_index))) + ip0, proto0, udp0->src_port, udp0->dst_port, thread_index, sw_if_index0))) goto trace00; } else @@ -1762,7 +1823,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, { if (is_output_feature) { - if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip1))) + if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip1, thread_index))) goto trace01; } @@ -1794,8 +1855,8 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, if (is_output_feature) { if (PREDICT_FALSE(nat_not_translate_output_feature(sm, - ip1, proto1, thread_index))) - goto trace00; + ip1, proto1, udp1->src_port, udp1->dst_port, thread_index, sw_if_index1))) + goto trace01; } else { @@ -1990,7 +2051,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, { if (is_output_feature) { - if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip0))) + if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip0, thread_index))) goto trace0; } @@ -2022,7 +2083,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, if (is_output_feature) { if (PREDICT_FALSE(nat_not_translate_output_feature(sm, - ip0, proto0, thread_index))) + ip0, proto0, udp0->src_port, udp0->dst_port, thread_index, sw_if_index0))) goto trace0; } else @@ -2404,7 +2465,7 @@ nat44_reass_hairpinning (snat_main_t *sm, udp0 = ip4_next_header (ip0); /* Check if destination is static mappings */ - if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0)) + if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0)) { new_dst_addr0 = sm0.addr.as_u32; new_dst_port0 = sm0.port; @@ -4013,7 +4074,7 @@ snat_in2out_fast_static_map_fn (vlib_main_t * vm, key0.port = udp0->src_port; key0.fib_index = rx_fib_index0; - if (snat_static_mapping_match(sm, key0, &sm0, 0, 0, 0)) + if (snat_static_mapping_match(sm, key0, &sm0, 0, 0, 0, 0)) { b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; next0= SNAT_IN2OUT_NEXT_DROP;