X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fin2out.c;h=8b565b1b6d39cb6904da42c063f6f88216bb60a8;hb=3f2dd30b0bf7cf3d82c720d5065178c1fa628c6b;hp=a453328c38fc475383675661caa6b88eaaf28125;hpb=87233b51bc4d088ff566cef09a7c96f1f0dac078;p=vpp.git diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c index a453328c38f..8b565b1b6d3 100755 --- a/src/plugins/nat/in2out.c +++ b/src/plugins/nat/in2out.c @@ -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, @@ -449,6 +490,47 @@ 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) +{ + nat_ed_ses_key_t key; + clib_bihash_kv_16_8_t kv, value; + udp_header_t *udp; + + 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)) + return value.value == ~0ULL; + + return 0; +} + /** * Get address and port values to be used for ICMP packet translation * and create session if needed @@ -497,12 +579,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))) @@ -701,6 +794,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; @@ -1063,7 +1159,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]; @@ -1258,6 +1354,8 @@ 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); } else @@ -1297,6 +1395,7 @@ snat_in2out_lb (snat_main_t *sm, s->outside_address_index = ~0; s->in2out = l_key; s->out2in = e_key; + s->out2in.protocol = l_key.protocol; u->nstaticsessions++; /* Add to lookup tables */ @@ -1492,6 +1591,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))) + goto trace00; + } + if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP)) { next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; @@ -1517,9 +1622,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 +1783,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))) + goto trace01; + } + if (PREDICT_FALSE (proto1 == ~0 || proto1 == SNAT_PROTOCOL_ICMP)) { next1 = SNAT_IN2OUT_NEXT_SLOW_PATH; @@ -1682,8 +1802,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 +1814,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 +1864,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 +2011,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))) + goto trace0; + } + if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP)) { next0 = SNAT_IN2OUT_NEXT_SLOW_PATH; @@ -1907,9 +2042,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);