X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fin2out.c;h=1659ed0fec3264bbde810d716217d987aeceb91b;hb=70a26ac05f2ab9d4cc0669599b09f654de580f36;hp=a453328c38fc475383675661caa6b88eaaf28125;hpb=87233b51bc4d088ff566cef09a7c96f1f0dac078;p=vpp.git diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c index a453328c38f..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 @@ -252,6 +252,47 @@ snat_not_translate (snat_main_t * sm, vlib_node_runtime_t *node, rx_fib_index0); } +static inline int +nat_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip0, + u32 proto0, u16 src_port, u16 dst_port, + u32 thread_index, u32 sw_if_index) +{ + 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 = 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)) + 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; +} + static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t * ip0, u32 rx_fib_index0, @@ -269,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))) { @@ -296,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, @@ -308,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) @@ -322,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; @@ -449,6 +489,72 @@ icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0) return 0; } +static inline int +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; + + if (ip->protocol == IP_PROTOCOL_ICMP) + { + if (icmp_get_ed_key (ip, &key)) + return 0; + } + else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP) + { + udp = ip4_next_header(ip); + key.l_addr = ip->src_address; + key.r_addr = ip->dst_address; + key.proto = ip->protocol; + key.r_port = udp->dst_port; + key.l_port = udp->src_port; + } + else + { + key.l_addr = ip->src_address; + key.r_addr = ip->dst_address; + key.proto = ip->protocol; + key.l_port = key.r_port = 0; + } + key.fib_index = 0; + kv.key[0] = key.as_u64[0]; + kv.key[1] = key.as_u64[1]; + + if (!clib_bihash_search_16_8 (&sm->in2out_ed, &kv, &value)) + { + 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; +} + /** * Get address and port values to be used for ICMP packet translation * and create session if needed @@ -497,12 +603,23 @@ u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0, &value0)) { - if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0, ip0, - IP_PROTOCOL_ICMP, rx_fib_index0, thread_index) && - vnet_buffer(b0)->sw_if_index[VLIB_TX] == ~0)) + if (vnet_buffer(b0)->sw_if_index[VLIB_TX] != ~0) { - dont_translate = 1; - goto out; + if (PREDICT_FALSE(nat_not_translate_output_feature(sm, + ip0, SNAT_PROTOCOL_ICMP, key0.port, key0.port, thread_index, sw_if_index0))) + { + dont_translate = 1; + goto out; + } + } + else + { + if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0, + ip0, SNAT_PROTOCOL_ICMP, rx_fib_index0, thread_index))) + { + dont_translate = 1; + goto out; + } } if (PREDICT_FALSE(icmp_is_error_message (icmp0))) @@ -611,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))) @@ -701,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; @@ -807,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; @@ -908,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; @@ -1063,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]; @@ -1107,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; @@ -1163,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; @@ -1170,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; @@ -1244,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; @@ -1259,6 +1378,19 @@ snat_in2out_lb (snat_main_t *sm, if (!clib_bihash_search_16_8 (&sm->in2out_ed, &s_kv, &s_value)) { 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 { @@ -1273,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, @@ -1293,11 +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; - u->nstaticsessions++; + s->out2in.protocol = l_key.protocol; + user_session_increment (sm, u, 1 /* static */); /* Add to lookup tables */ s_kv.value = s - tsm->sessions; @@ -1323,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; @@ -1343,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 { @@ -1355,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++; @@ -1492,6 +1629,12 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, } else { + if (is_output_feature) + { + if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip0, thread_index))) + goto trace00; + } + if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP)) { next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; @@ -1517,9 +1660,18 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, { if (is_slow_path) { - if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0, - ip0, proto0, rx_fib_index0, thread_index)) && !is_output_feature) - goto trace00; + if (is_output_feature) + { + if (PREDICT_FALSE(nat_not_translate_output_feature(sm, + ip0, proto0, udp0->src_port, udp0->dst_port, thread_index, sw_if_index0))) + goto trace00; + } + else + { + if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0, + ip0, proto0, rx_fib_index0, thread_index))) + goto trace00; + } next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, &s0, node, next0, thread_index); @@ -1669,6 +1821,12 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, } else { + if (is_output_feature) + { + if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip1, thread_index))) + goto trace01; + } + if (PREDICT_FALSE (proto1 == ~0 || proto1 == SNAT_PROTOCOL_ICMP)) { next1 = SNAT_IN2OUT_NEXT_SLOW_PATH; @@ -1682,8 +1840,6 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, } } - b1->flags |= VNET_BUFFER_F_IS_NATED; - key1.addr = ip1->src_address; key1.port = udp1->src_port; key1.protocol = proto1; @@ -1696,9 +1852,18 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, { if (is_slow_path) { - if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index1, - ip1, proto1, rx_fib_index1, thread_index)) && !is_output_feature) - goto trace01; + if (is_output_feature) + { + if (PREDICT_FALSE(nat_not_translate_output_feature(sm, + ip1, proto1, udp1->src_port, udp1->dst_port, thread_index, sw_if_index1))) + goto trace01; + } + else + { + if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index1, + ip1, proto1, rx_fib_index1, thread_index))) + goto trace01; + } next1 = slow_path (sm, b1, ip1, rx_fib_index1, &key1, &s1, node, next1, thread_index); @@ -1737,6 +1902,8 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, } } + b1->flags |= VNET_BUFFER_F_IS_NATED; + old_addr1 = ip1->src_address.as_u32; ip1->src_address = s1->out2in.addr; new_addr1 = ip1->src_address.as_u32; @@ -1882,6 +2049,12 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, } else { + if (is_output_feature) + { + if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip0, thread_index))) + goto trace0; + } + if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP)) { next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; @@ -1907,9 +2080,18 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, { if (is_slow_path) { - if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0, - ip0, proto0, rx_fib_index0, thread_index)) && !is_output_feature) - goto trace0; + if (is_output_feature) + { + if (PREDICT_FALSE(nat_not_translate_output_feature(sm, + ip0, proto0, udp0->src_port, udp0->dst_port, thread_index, sw_if_index0))) + goto trace0; + } + else + { + if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0, + ip0, proto0, rx_fib_index0, thread_index))) + goto trace0; + } next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, &s0, node, next0, thread_index); @@ -2283,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; @@ -3892,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;