diff options
author | Matus Fabian <matfabia@cisco.com> | 2017-09-04 02:17:18 -0700 |
---|---|---|
committer | Ole Trøan <otroan@employees.org> | 2017-09-06 08:49:25 +0000 |
commit | 704018cf117b6667f08b09d6db5fbec105bf6d57 (patch) | |
tree | 27a52337f4b5f35092a422290998f7c37b4071f7 /src/plugins/nat/out2in.c | |
parent | 030ab4815f777d6a0fdbfbc457e0f55fc32df8d3 (diff) |
NAT: Destination NAT44 with load-balancing (VPP-954)
added load-balancing static mappings with unequal load support
Change-Id: Ie505e41f24d46f812b94dd28bdafe3dc170a6060
Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'src/plugins/nat/out2in.c')
-rw-r--r-- | src/plugins/nat/out2in.c | 205 |
1 files changed, 194 insertions, 11 deletions
diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c index 679500668c5..55a750e4187 100644 --- a/src/plugins/nat/out2in.c +++ b/src/plugins/nat/out2in.c @@ -630,7 +630,7 @@ snat_out2in_unknown_proto (snat_main_t *sm, snat_session_key_t m_key; u32 old_addr, new_addr; ip_csum_t sum; - snat_unk_proto_ses_key_t key; + 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; @@ -643,11 +643,12 @@ 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.rsvd[1] = key.rsvd[2] = 0; + key.rsvd = 0; + key.l_port = 0; s_kv.key[0] = key.as_u64[0]; s_kv.key[1] = key.as_u64[1]; - if (!clib_bihash_search_16_8 (&sm->out2in_unk_proto, &s_kv, &s_value)) + if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value)) { s = pool_elt_at_index (tsm->sessions, s_value.value); new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32; @@ -721,14 +722,14 @@ snat_out2in_unknown_proto (snat_main_t *sm, /* Add to lookup tables */ s_kv.value = s - tsm->sessions; - if (clib_bihash_add_del_16_8 (&sm->out2in_unk_proto, &s_kv, 1)) + if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1)) clib_warning ("out2in key add failed"); key.l_addr = ip->dst_address; key.fib_index = m->fib_index; s_kv.key[0] = key.as_u64[0]; s_kv.key[1] = key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->in2out_unk_proto, &s_kv, 1)) + if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1)) clib_warning ("in2out key add failed"); } @@ -749,6 +750,152 @@ snat_out2in_unknown_proto (snat_main_t *sm, s->per_user_index); } +static void +snat_out2in_lb (snat_main_t *sm, + vlib_buffer_t * b, + ip4_header_t * ip, + u32 rx_fib_index, + u32 thread_index, + f64 now, + vlib_main_t * vm) +{ + nat_ed_ses_key_t key; + clib_bihash_kv_16_8_t s_kv, s_value; + udp_header_t *udp = ip4_next_header (ip); + tcp_header_t *tcp = (tcp_header_t *) udp; + 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; + + old_addr = ip->dst_address.as_u32; + + key.l_addr = ip->dst_address; + key.r_addr = ip->src_address; + key.fib_index = rx_fib_index; + key.proto = ip->protocol; + key.rsvd = 0; + key.l_port = udp->dst_port; + 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)) + { + s = pool_elt_at_index (tsm->sessions, s_value.value); + } + else + { + e_key.addr = ip->dst_address; + 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)) + return; + + 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 (&sm->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; + + /* add user */ + if (clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 1)) + clib_warning ("user key add failed"); + } + else + { + u = pool_elt_at_index (tsm->users, value.value); + } + + /* 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->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; + s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING; + 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); + + /* 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"); + + key.l_addr = l_key.addr; + key.fib_index = l_key.fib_index; + key.l_port = l_key.port; + s_kv.key[0] = key.as_u64[0]; + s_kv.key[1] = key.as_u64[1]; + if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1)) + clib_warning ("in2out-ed key add failed"); + } + + new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32; + + /* Update IP checksum */ + sum = ip->checksum; + sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address); + ip->checksum = ip_csum_fold (sum); + + if (PREDICT_TRUE(proto == SNAT_PROTOCOL_TCP)) + { + old_port = tcp->dst_port; + tcp->dst_port = s->in2out.port; + new_port = tcp->dst_port; + + 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); + tcp->checksum = ip_csum_fold(sum); + } + else + { + udp->dst_port = s->in2out.port; + 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); +} + static uword snat_out2in_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -894,8 +1041,20 @@ snat_out2in_node_fn (vlib_main_t * vm, } } else - s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value0.value); + { + if (PREDICT_FALSE (value0.value == ~0ULL)) + { + snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index, now, + vm); + goto trace0; + } + else + { + s0 = pool_elt_at_index ( + sm->per_thread_data[thread_index].sessions, + value0.value); + } + } old_addr0 = ip0->dst_address.as_u32; ip0->dst_address = s0->in2out.addr; @@ -1033,8 +1192,20 @@ snat_out2in_node_fn (vlib_main_t * vm, } } else - s1 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value1.value); + { + if (PREDICT_FALSE (value1.value == ~0ULL)) + { + snat_out2in_lb(sm, b1, ip1, rx_fib_index1, thread_index, now, + vm); + goto trace1; + } + else + { + s1 = pool_elt_at_index ( + sm->per_thread_data[thread_index].sessions, + value1.value); + } + } old_addr1 = ip1->dst_address.as_u32; ip1->dst_address = s1->in2out.addr; @@ -1209,8 +1380,20 @@ snat_out2in_node_fn (vlib_main_t * vm, } } else - s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value0.value); + { + if (PREDICT_FALSE (value0.value == ~0ULL)) + { + snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index, now, + vm); + goto trace00; + } + else + { + s0 = pool_elt_at_index ( + sm->per_thread_data[thread_index].sessions, + value0.value); + } + } old_addr0 = ip0->dst_address.as_u32; ip0->dst_address = s0->in2out.addr; |