X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fout2in.c;h=4589c48aef6463deadcb86a5d81474f7c3a266f5;hb=204591d1bd754f6086edcf8b27a95beab929a78f;hp=d548ab31fc5b95ad5ec8c7eb733291e8c239f8df;hpb=7b929793feba7d966c34b1ddb31dc818174f3a57;p=vpp.git diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c index d548ab31fc5..4589c48aef6 100755 --- a/src/plugins/nat/out2in.c +++ b/src/plugins/nat/out2in.c @@ -264,6 +264,90 @@ snat_out2in_error_t icmp_get_key(ip4_header_t *ip0, return -1; /* success */ } +static_always_inline int +icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0) +{ + icmp46_header_t *icmp0; + nat_ed_ses_key_t key0; + icmp_echo_header_t *echo0, *inner_echo0 = 0; + ip4_header_t *inner_ip0; + void *l4_header = 0; + icmp46_header_t *inner_icmp0; + + icmp0 = (icmp46_header_t *) ip4_next_header (ip0); + echo0 = (icmp_echo_header_t *)(icmp0+1); + + if (!icmp_is_error_message (icmp0)) + { + key0.proto = IP_PROTOCOL_ICMP; + key0.l_addr = ip0->dst_address; + key0.r_addr = ip0->src_address; + key0.l_port = key0.r_port = echo0->identifier; + } + else + { + inner_ip0 = (ip4_header_t *)(echo0+1); + l4_header = ip4_next_header (inner_ip0); + key0.proto = inner_ip0->protocol; + key0.l_addr = inner_ip0->src_address; + key0.r_addr = inner_ip0->dst_address; + switch (ip_proto_to_snat_proto (inner_ip0->protocol)) + { + case SNAT_PROTOCOL_ICMP: + inner_icmp0 = (icmp46_header_t*)l4_header; + inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1); + key0.l_port = key0.r_port = inner_echo0->identifier; + break; + case SNAT_PROTOCOL_UDP: + case SNAT_PROTOCOL_TCP: + key0.l_port = ((tcp_udp_header_t*)l4_header)->src_port; + key0.r_port = ((tcp_udp_header_t*)l4_header)->dst_port; + break; + default: + return -1; + } + } + *p_key0 = key0; + return 0; +} + +static void +create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip) +{ + nat_ed_ses_key_t key; + clib_bihash_kv_16_8_t kv; + udp_header_t *udp; + + if (ip->protocol == IP_PROTOCOL_ICMP) + { + if (icmp_get_ed_key (ip, &key)) + return; + } + else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP) + { + udp = ip4_next_header(ip); + key.r_addr = ip->src_address; + key.l_addr = ip->dst_address; + key.proto = ip->protocol; + key.l_port = udp->dst_port; + key.r_port = udp->src_port; + } + else + { + key.r_addr = ip->src_address; + key.l_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]; + kv.value = ~0ULL; + + if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &kv, 1)) + clib_warning ("in2out_ed key add failed"); +} + /** * Get address and port values to be used for ICMP packet translation * and create session if needed @@ -335,6 +419,7 @@ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, } else { + create_bypass_for_fwd(sm, ip0); dont_translate = 1; goto out; } @@ -369,8 +454,34 @@ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, goto out; } - s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value0.value); + if (PREDICT_FALSE (value0.value == ~0ULL)) + { + nat_ed_ses_key_t key; + clib_bihash_kv_16_8_t s_kv, s_value; + + key.as_u64[0] = 0; + key.as_u64[1] = 0; + if (icmp_get_ed_key (ip0, &key)) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL]; + next0 = SNAT_OUT2IN_NEXT_DROP; + goto out; + } + key.fib_index = rx_fib_index0; + 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)) + s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, + s_value.value); + else + { + next0 = SNAT_OUT2IN_NEXT_DROP; + goto out; + } + } + else + s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, + value0.value); } out: @@ -1032,14 +1143,21 @@ snat_out2in_node_fn (vlib_main_t * vm, * 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 + if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) + != 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); goto trace0; } else - goto trace0; + { + create_bypass_for_fwd(sm, ip0); + goto trace0; + } } /* Create session initiated by host from external network */ @@ -1195,14 +1313,21 @@ snat_out2in_node_fn (vlib_main_t * vm, * Send DHCP packets to the ipv4 stack, or we won't * be able to use dhcp client on the outside interface */ - if (proto1 != SNAT_PROTOCOL_UDP + if (PREDICT_TRUE (proto1 != SNAT_PROTOCOL_UDP || (udp1->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) + != 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); goto trace1; } else - goto trace1; + { + create_bypass_for_fwd(sm, ip1); + goto trace1; + } } /* Create session initiated by host from external network */ @@ -1394,14 +1519,21 @@ snat_out2in_node_fn (vlib_main_t * vm, * 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 + if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) + != 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); goto trace00; } else - goto trace00; + { + create_bypass_for_fwd(sm, ip0); + goto trace00; + } } /* Create session initiated by host from external network */ @@ -1634,14 +1766,21 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm, * 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 + if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) + != 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); goto trace0; } else - goto trace0; + { + create_bypass_for_fwd(sm, ip0); + goto trace0; + } } /* Create session initiated by host from external network */