X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fout2in.c;h=6bc25b8cc22f94a368a9141ded47b409707e402f;hb=17e5cfbe8d9b1f47b18eb1a43976fe322e3987a2;hp=15f6f556d73896820d2b1e2983927d1b8401df7c;hpb=51e759fd0655b6089360e1ccf2f5341704549fd4;p=vpp.git diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c index 15f6f556d73..6bc25b8cc22 100755 --- a/src/plugins/nat/out2in.c +++ b/src/plugins/nat/out2in.c @@ -107,6 +107,7 @@ vlib_node_registration_t nat44_out2in_reass_node; #define foreach_snat_out2in_error \ _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \ _(OUT2IN_PACKETS, "Good out2in packets processed") \ +_(OUT_OF_PORTS, "Out of ports") \ _(BAD_ICMP_TYPE, "unsupported ICMP type") \ _(NO_TRANSLATION, "No translation") \ _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded") \ @@ -132,6 +133,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; @@ -158,11 +160,8 @@ create_session_for_static_mapping (snat_main_t *sm, u32 thread_index) { snat_user_t *u; - snat_user_key_t user_key; snat_session_t *s; - clib_bihash_kv_8_8_t kv0, value0; - dlist_elt_t * per_user_translation_list_elt; - dlist_elt_t * per_user_list_head_elt; + clib_bihash_kv_8_8_t kv0; ip4_header_t *ip0; udp_header_t *udp0; @@ -175,68 +174,25 @@ create_session_for_static_mapping (snat_main_t *sm, ip0 = vlib_buffer_get_current (b0); udp0 = ip4_next_header (ip0); - user_key.addr = in2out.addr; - user_key.fib_index = in2out.fib_index; - kv0.key = user_key.as_u64; - - /* Ever heard of the "user" = inside ip4 address before? */ - if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].user_hash, - &kv0, &value0)) + u = nat_user_get_or_create (sm, &in2out.addr, in2out.fib_index, thread_index); + if (!u) { - /* no, make a new one */ - pool_get (sm->per_thread_data[thread_index].users, u); - memset (u, 0, sizeof (*u)); - u->addr = in2out.addr; - u->fib_index = in2out.fib_index; - - pool_get (sm->per_thread_data[thread_index].list_pool, - per_user_list_head_elt); - - u->sessions_per_user_list_head_index = per_user_list_head_elt - - sm->per_thread_data[thread_index].list_pool; - - clib_dlist_init (sm->per_thread_data[thread_index].list_pool, - u->sessions_per_user_list_head_index); - - kv0.value = u - sm->per_thread_data[thread_index].users; - - /* add user */ - clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].user_hash, - &kv0, 1 /* is_add */); + clib_warning ("create NAT user failed"); + return 0; } - else + + s = nat_session_alloc_or_recycle (sm, u, thread_index); + if (!s) { - u = pool_elt_at_index (sm->per_thread_data[thread_index].users, - value0.value); + clib_warning ("create NAT session failed"); + return 0; } - pool_get (sm->per_thread_data[thread_index].sessions, s); - memset (s, 0, sizeof (*s)); - s->outside_address_index = ~0; 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++; - - /* Create list elts */ - pool_get (sm->per_thread_data[thread_index].list_pool, - per_user_translation_list_elt); - clib_dlist_init (sm->per_thread_data[thread_index].list_pool, - per_user_translation_list_elt - - sm->per_thread_data[thread_index].list_pool); - - per_user_translation_list_elt->value = - s - sm->per_thread_data[thread_index].sessions; - s->per_user_index = - per_user_translation_list_elt - sm->per_thread_data[thread_index].list_pool; - s->per_user_list_head_index = u->sessions_per_user_list_head_index; - - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s->per_user_list_head_index, - per_user_translation_list_elt - - sm->per_thread_data[thread_index].list_pool); - + user_session_increment (sm, u, 1 /* static */); s->in2out = in2out; s->out2in = out2in; s->in2out.protocol = out2in.protocol; @@ -249,7 +205,6 @@ create_session_for_static_mapping (snat_main_t *sm, clib_warning ("in2out key add failed"); kv0.key = s->out2in.as_u64; - kv0.value = s - sm->per_thread_data[thread_index].sessions; if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0, 1 /* is_add */)) @@ -310,6 +265,160 @@ 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 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, u32 rx_fib_index, + u32 thread_index) +{ + nat_ed_ses_key_t key; + 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]; + + 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]; + + 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) + { + clib_warning ("create NAT user failed"); + return; + } + + s = nat_session_alloc_or_recycle (sm, u, thread_index); + if (!s) + { + clib_warning ("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)) + clib_warning ("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 (sm, s, tcp, thread_index)) + return; + } + /* 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); +} + /** * Get address and port values to be used for ICMP packet translation * and create session if needed @@ -364,18 +473,32 @@ 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)) + if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0, 0)) { - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0, - ip0->dst_address.as_u32))) + if (!sm->forwarding_enabled) + { + /* Don't NAT packet aimed at the intfc address */ + if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0, + ip0->dst_address.as_u32))) + { + dont_translate = 1; + goto out; + } + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + next0 = SNAT_OUT2IN_NEXT_DROP; + goto out; + } + else { 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; } - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; } if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply && @@ -407,8 +530,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: @@ -463,7 +612,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)) + 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)) @@ -545,6 +694,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; @@ -636,15 +788,12 @@ static inline u32 icmp_out2in_slow_path (snat_main_t *sm, s0->last_heard = now; s0->total_pkts++; s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - 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); - } + /* 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); } return next0; } @@ -668,9 +817,7 @@ snat_out2in_unknown_proto (snat_main_t *sm, nat_ed_ses_key_t key; snat_session_t * s; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; - snat_user_key_t u_key; snat_user_t *u; - dlist_elt_t *head, *elt; old_addr = ip->dst_address.as_u32; @@ -678,7 +825,7 @@ snat_out2in_unknown_proto (snat_main_t *sm, key.r_addr = ip->src_address; key.fib_index = rx_fib_index; key.proto = ip->protocol; - key.rsvd = 0; + key.r_port = 0; key.l_port = 0; s_kv.key[0] = key.as_u64[0]; s_kv.key[1] = key.as_u64[1]; @@ -711,58 +858,33 @@ snat_out2in_unknown_proto (snat_main_t *sm, new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32; - u_key.addr = ip->src_address; - u_key.fib_index = m->fib_index; - kv.key = u_key.as_u64; - - /* Ever heard of the "user" = src ip4 address before? */ - if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) - { - /* no, make a new one */ - pool_get (tsm->users, u); - memset (u, 0, sizeof (*u)); - u->addr = ip->src_address; - u->fib_index = rx_fib_index; - - pool_get (tsm->list_pool, head); - u->sessions_per_user_list_head_index = head - tsm->list_pool; - - clib_dlist_init (tsm->list_pool, - u->sessions_per_user_list_head_index); - - kv.value = u - tsm->users; - - /* add user */ - clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1); - } - else + u = nat_user_get_or_create (sm, &ip->src_address, m->fib_index, + thread_index); + if (!u) { - u = pool_elt_at_index (tsm->users, value.value); + clib_warning ("create NAT user failed"); + return 0; } /* Create a new session */ - pool_get (tsm->sessions, s); - memset (s, 0, sizeof (*s)); + s = nat_session_alloc_or_recycle (sm, u, thread_index); + if (!s) + { + clib_warning ("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++; - - /* Create list elts */ - pool_get (tsm->list_pool, elt); - clib_dlist_init (tsm->list_pool, elt - tsm->list_pool); - elt->value = s - tsm->sessions; - s->per_user_index = elt - tsm->list_pool; - s->per_user_list_head_index = u->sessions_per_user_list_head_index; - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); + user_session_increment (sm, u, 1 /* static */); /* Add to lookup tables */ s_kv.value = s - tsm->sessions; @@ -813,14 +935,15 @@ snat_out2in_lb (snat_main_t *sm, snat_session_t *s = 0; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; snat_session_key_t e_key, l_key; - clib_bihash_kv_8_8_t kv, value; u32 old_addr, new_addr; u32 proto = ip_proto_to_snat_proto (ip->protocol); u16 new_port, old_port; ip_csum_t sum; - snat_user_key_t u_key; snat_user_t *u; - dlist_elt_t *head, *elt; + u32 address_index; + snat_session_key_t eh_key; + twice_nat_type_t twice_nat; + u8 lb; old_addr = ip->dst_address.as_u32; @@ -828,7 +951,7 @@ snat_out2in_lb (snat_main_t *sm, key.r_addr = ip->src_address; key.fib_index = rx_fib_index; key.proto = ip->protocol; - key.rsvd = 0; + key.r_port = udp->src_port; key.l_port = udp->dst_port; s_kv.key[0] = key.as_u64[0]; s_kv.key[1] = key.as_u64[1]; @@ -849,65 +972,58 @@ 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)) + if (snat_static_mapping_match(sm, e_key, &l_key, 1, 0, &twice_nat, &lb)) return 0; - u_key.addr = l_key.addr; - u_key.fib_index = l_key.fib_index; - kv.key = u_key.as_u64; - - /* Ever heard of the "user" = src ip4 address before? */ - if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) - { - /* no, make a new one */ - pool_get (tsm->users, u); - memset (u, 0, sizeof (*u)); - u->addr = l_key.addr; - u->fib_index = l_key.fib_index; - - pool_get (tsm->list_pool, head); - u->sessions_per_user_list_head_index = head - tsm->list_pool; - - clib_dlist_init (tsm->list_pool, - u->sessions_per_user_list_head_index); - - kv.value = u - tsm->users; + u = nat_user_get_or_create (sm, &l_key.addr, l_key.fib_index, + thread_index); + if (!u) + { + clib_warning ("create NAT user failed"); + return 0; + } - /* add user */ - if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1)) - clib_warning ("user key add failed"); - } - else + s = nat_session_alloc_or_recycle (sm, u, thread_index); + if (!s) { - u = pool_elt_at_index (tsm->users, value.value); + clib_warning ("create NAT session failed"); + return 0; } - /* Create a new session */ - pool_get (tsm->sessions, s); - memset (s, 0, sizeof (*s)); - 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++; - - /* Create list elts */ - pool_get (tsm->list_pool, elt); - clib_dlist_init (tsm->list_pool, elt - tsm->list_pool); - elt->value = s - tsm->sessions; - s->per_user_index = elt - tsm->list_pool; - s->per_user_list_head_index = u->sessions_per_user_list_head_index; - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); + 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"); + 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, + thread_index, &eh_key, + &address_index, + sm->port_per_thread, + sm->per_thread_data[thread_index].snat_thread_index)) + { + b->error = node->errors[SNAT_OUT2IN_ERROR_OUT_OF_PORTS]; + return 0; + } + key.r_addr.as_u32 = s->ext_host_nat_addr.as_u32 = eh_key.addr.as_u32; + key.r_port = s->ext_host_nat_port = eh_key.port; + s->flags |= SNAT_SESSION_FLAG_TWICE_NAT; + } key.l_addr = l_key.addr; key.fib_index = l_key.fib_index; key.l_port = l_key.port; @@ -922,8 +1038,14 @@ snat_out2in_lb (snat_main_t *sm, /* Update IP checksum */ sum = ip->checksum; sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address); + if (is_twice_nat_session (s)) + sum = ip_csum_update (sum, ip->src_address.as_u32, + s->ext_host_nat_addr.as_u32, ip4_header_t, + 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; @@ -933,20 +1055,40 @@ snat_out2in_lb (snat_main_t *sm, sum = tcp->checksum; sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address); sum = ip_csum_update (sum, old_port, new_port, ip4_header_t, length); + if (is_twice_nat_session (s)) + { + sum = ip_csum_update (sum, ip->src_address.as_u32, + s->ext_host_nat_addr.as_u32, ip4_header_t, + dst_address); + sum = ip_csum_update (sum, tcp->src_port, s->ext_host_nat_port, + ip4_header_t, length); + tcp->src_port = s->ext_host_nat_port; + ip->src_address.as_u32 = s->ext_host_nat_addr.as_u32; + } tcp->checksum = ip_csum_fold(sum); + if (nat44_set_tcp_session_state (sm, s, tcp, thread_index)) + return s; } else { udp->dst_port = s->in2out.port; + if (is_twice_nat_session (s)) + { + udp->src_port = s->ext_host_nat_port; + ip->src_address.as_u32 = s->ext_host_nat_addr.as_u32; + } 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); + /* 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 s; } @@ -1048,8 +1190,9 @@ snat_out2in_node_fn (vlib_main_t * vm, { s0 = snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0, thread_index, now, vm, node); - if (!s0) - next0 = SNAT_OUT2IN_NEXT_DROP; + if (!sm->forwarding_enabled) + if (!s0) + next0 = SNAT_OUT2IN_NEXT_DROP; goto trace0; } @@ -1079,18 +1222,37 @@ 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)) + if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0)) { - 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 (proto0 != SNAT_PROTOCOL_UDP - || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) - next0 = SNAT_OUT2IN_NEXT_DROP; - goto trace0; + 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]; + next0 = SNAT_OUT2IN_NEXT_DROP; + goto trace0; + } + else + { + 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; + } } /* Create session initiated by host from external network */ @@ -1146,6 +1308,8 @@ snat_out2in_node_fn (vlib_main_t * vm, ip4_header_t /* cheat */, length /* changed member */); tcp0->checksum = ip_csum_fold(sum0); + if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index)) + goto trace0; } else { @@ -1158,15 +1322,12 @@ snat_out2in_node_fn (vlib_main_t * vm, s0->last_heard = now; s0->total_pkts++; s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - 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); - } + /* 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); trace0: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1209,8 +1370,9 @@ snat_out2in_node_fn (vlib_main_t * vm, { s1 = snat_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1, thread_index, now, vm, node); - if (!s1) - next1 = SNAT_OUT2IN_NEXT_DROP; + if (!sm->forwarding_enabled) + if (!s1) + next1 = SNAT_OUT2IN_NEXT_DROP; goto trace1; } @@ -1240,18 +1402,37 @@ 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)) + if (snat_static_mapping_match(sm, key1, &sm1, 1, 0, 0, 0)) { - 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 (proto1 != SNAT_PROTOCOL_UDP - || (udp1->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) - next1 = SNAT_OUT2IN_NEXT_DROP; - goto trace1; + 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]; + next1 = SNAT_OUT2IN_NEXT_DROP; + goto trace1; + } + else + { + 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; + } } /* Create session initiated by host from external network */ @@ -1307,6 +1488,8 @@ snat_out2in_node_fn (vlib_main_t * vm, ip4_header_t /* cheat */, length /* changed member */); tcp1->checksum = ip_csum_fold(sum1); + if (nat44_set_tcp_session_state (sm, s1, tcp1, thread_index)) + goto trace1; } else { @@ -1319,15 +1502,12 @@ snat_out2in_node_fn (vlib_main_t * vm, s1->last_heard = now; s1->total_pkts++; s1->total_bytes += vlib_buffer_length_in_chain (vm, b1); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s1)) - { - 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); - } + /* 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); trace1: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1396,8 +1576,9 @@ snat_out2in_node_fn (vlib_main_t * vm, { s0 = snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0, thread_index, now, vm, node); - if (!s0) - next0 = SNAT_OUT2IN_NEXT_DROP; + if (!sm->forwarding_enabled) + if (!s0) + next0 = SNAT_OUT2IN_NEXT_DROP; goto trace00; } @@ -1437,19 +1618,37 @@ 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)) + if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0)) { - 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 (proto0 != SNAT_PROTOCOL_UDP - || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) - - next0 = SNAT_OUT2IN_NEXT_DROP; - goto trace00; + 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]; + next0 = SNAT_OUT2IN_NEXT_DROP; + goto trace00; + } + else + { + 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; + } } /* Create session initiated by host from external network */ @@ -1505,6 +1704,8 @@ snat_out2in_node_fn (vlib_main_t * vm, ip4_header_t /* cheat */, length /* changed member */); tcp0->checksum = ip_csum_fold(sum0); + if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index)) + goto trace00; } else { @@ -1517,15 +1718,12 @@ snat_out2in_node_fn (vlib_main_t * vm, s0->last_heard = now; s0->total_pkts++; s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - 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); - } + /* 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); trace00: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1577,6 +1775,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); @@ -1676,19 +1875,38 @@ 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)) + if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0)) { - 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 (proto0 != SNAT_PROTOCOL_UDP - || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) - - next0 = SNAT_OUT2IN_NEXT_DROP; - goto trace0; + 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]; + next0 = SNAT_OUT2IN_NEXT_DROP; + goto trace0; + } + else + { + 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; + } } /* Create session initiated by host from external network */ @@ -1756,6 +1974,8 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm, ip4_header_t /* cheat */, length /* changed member */); tcp0->checksum = ip_csum_fold(sum0); + if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index)) + goto trace0; } else { @@ -1769,15 +1989,12 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm, s0->last_heard = now; s0->total_pkts++; s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); - /* Per-user LRU list maintenance for dynamic translation */ - if (!snat_is_session_static (s0)) - { - 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); - } + /* 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); trace0: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1860,6 +2077,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, @@ -2349,6 +2567,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); @@ -2739,7 +2958,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)) + if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0)) { b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace00; @@ -2842,6 +3061,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);