From 770178e365b5c37ecdecfecb424003cca7343ede Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Fri, 17 Apr 2020 18:42:28 +0000 Subject: nat: improve perf - long read after short write Type: improvement Signed-off-by: Klement Sekera Change-Id: Idbbad246161d28f595c25e10d7282c8b33fa9876 --- src/plugins/nat/in2out_ed.c | 204 +++++++++++++++++++++++--------------------- 1 file changed, 105 insertions(+), 99 deletions(-) (limited to 'src/plugins/nat/in2out_ed.c') diff --git a/src/plugins/nat/in2out_ed.c b/src/plugins/nat/in2out_ed.c index 95f80a4ff2b..d78e552d3ba 100644 --- a/src/plugins/nat/in2out_ed.c +++ b/src/plugins/nat/in2out_ed.c @@ -72,7 +72,10 @@ nat44_i2o_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg) nat44_is_idle_session_ctx_t *ctx = arg; snat_session_t *s; u64 sess_timeout_time; - nat_ed_ses_key_t ed_key; + u8 proto; + u16 r_port, l_port; + ip4_address_t *l_addr, *r_addr; + u32 fib_index; clib_bihash_kv_16_8_t ed_kv; int i; snat_address_t *a; @@ -87,23 +90,23 @@ nat44_i2o_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg) if (is_fwd_bypass_session (s)) goto delete; - ed_key.l_addr = s->out2in.addr; - ed_key.r_addr = s->ext_host_addr; - ed_key.fib_index = s->out2in.fib_index; + l_addr = &s->out2in.addr; + r_addr = &s->ext_host_addr; + fib_index = s->out2in.fib_index; if (snat_is_unk_proto_session (s)) { - ed_key.proto = s->in2out.port; - ed_key.r_port = 0; - ed_key.l_port = 0; + proto = s->in2out.port; + r_port = 0; + l_port = 0; } else { - ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol); - ed_key.l_port = s->out2in.port; - ed_key.r_port = s->ext_host_port; + proto = snat_proto_to_ip_proto (s->in2out.protocol); + l_port = s->out2in.port; + r_port = s->ext_host_port; } - ed_kv.key[0] = ed_key.as_u64[0]; - ed_kv.key[1] = ed_key.as_u64[1]; + make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL, + &ed_kv); if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0)) nat_elog_warn ("out2in_ed key del failed"); @@ -191,11 +194,13 @@ snat_random_port (u16 min, u16 max) } static int -nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 fib_index, - u32 thread_index, nat_ed_ses_key_t * key, - snat_session_key_t * key1, u16 port_per_thread, - u32 snat_thread_index, +nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 rx_fib_index, + u32 snat_proto, u32 thread_index, + ip4_address_t r_addr, u16 r_port, u8 proto, + u16 port_per_thread, u32 snat_thread_index, snat_session_t * s, + ip4_address_t * allocated_addr, + u16 * allocated_port, clib_bihash_kv_16_8_t * out2in_ed_kv) { int i; @@ -208,11 +213,11 @@ nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 fib_index, for (i = 0; i < vec_len (sm->addresses); i++) { a = sm->addresses + i; - switch (key1->protocol) + switch (snat_proto) { #define _(N, j, n, unused) \ case SNAT_PROTOCOL_##N: \ - if (a->fib_index == fib_index) \ + if (a->fib_index == rx_fib_index) \ { \ u16 port = snat_random_port (1, port_per_thread); \ u16 attempts = port_per_thread; \ @@ -220,10 +225,9 @@ nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 fib_index, { \ --attempts; \ portnum = port_thread_offset + port; \ - make_ed_kv (out2in_ed_kv, &a->addr, &key->r_addr, key->proto, \ - s->out2in.fib_index, clib_host_to_net_u16 (portnum), \ - key->r_port); \ - out2in_ed_kv->value = s - tsm->sessions; \ + make_ed_kv (&a->addr, &r_addr, proto, s->out2in.fib_index, \ + clib_host_to_net_u16 (portnum), r_port, \ + s - tsm->sessions, out2in_ed_kv); \ int rv = clib_bihash_add_del_16_8 (&tsm->out2in_ed, out2in_ed_kv, \ 2 /* is_add */); \ if (0 == rv) \ @@ -231,8 +235,8 @@ nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 fib_index, ++a->busy_##n##_port_refcounts[portnum]; \ a->busy_##n##_ports_per_thread[thread_index]++; \ a->busy_##n##_ports++; \ - key1->addr = a->addr; \ - key1->port = clib_host_to_net_u16 (portnum); \ + *allocated_addr = a->addr; \ + *allocated_port = clib_host_to_net_u16 (portnum); \ return 0; \ } \ port = (port + 1) % port_per_thread; \ @@ -254,9 +258,9 @@ nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 fib_index, if (ga) { /* fake fib_index to reuse macro */ - fib_index = ~0; + rx_fib_index = ~0; a = ga; - switch (key1->protocol) + switch (snat_proto) { foreach_snat_protocol; default: @@ -275,8 +279,12 @@ nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 fib_index, static u32 slow_path_ed (snat_main_t * sm, vlib_buffer_t * b, + ip4_address_t l_addr, + ip4_address_t r_addr, + u16 l_port, + u16 r_port, + u8 proto, u32 rx_fib_index, - clib_bihash_kv_16_8_t * kv, snat_session_t ** sessionp, vlib_node_runtime_t * node, u32 next, u32 thread_index, f64 now) { @@ -284,23 +292,22 @@ slow_path_ed (snat_main_t * sm, snat_session_key_t key0, key1; lb_nat_type_t lb = 0; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; - nat_ed_ses_key_t *key = (nat_ed_ses_key_t *) kv->key; - u32 proto = ip_proto_to_snat_proto (key->proto); + u32 snat_proto = ip_proto_to_snat_proto (proto); nat_outside_fib_t *outside_fib; fib_node_index_t fei = FIB_NODE_INDEX_INVALID; clib_bihash_kv_16_8_t out2in_ed_kv; bool out2in_ed_inserted = false; + ip4_address_t allocated_addr; + u16 allocated_port; u8 identity_nat; fib_prefix_t pfx = { .fp_proto = FIB_PROTOCOL_IP4, .fp_len = 32, - .fp_addr = { - .ip4.as_u32 = key->r_addr.as_u32, - }, + .fp_addr = {.ip4.as_u32 = r_addr.as_u32,}, }; nat44_is_idle_session_ctx_t ctx; - if (PREDICT_TRUE (proto == SNAT_PROTOCOL_TCP)) + if (PREDICT_TRUE (snat_proto == SNAT_PROTOCOL_TCP)) { if (PREDICT_FALSE (!tcp_flags_is_init @@ -322,9 +329,9 @@ slow_path_ed (snat_main_t * sm, } } - key0.addr = key->l_addr; - key0.port = key->l_port; - key1.protocol = key0.protocol = proto; + key0.addr = l_addr; + key0.port = l_port; + key1.protocol = key0.protocol = snat_proto; key0.fib_index = rx_fib_index; key1.fib_index = sm->outside_fib_index; @@ -366,11 +373,12 @@ slow_path_ed (snat_main_t * sm, } /* Try to create dynamic translation */ - if (nat_ed_alloc_addr_and_port (sm, rx_fib_index, - thread_index, key, &key1, + if (nat_ed_alloc_addr_and_port (sm, rx_fib_index, snat_proto, + thread_index, r_addr, r_port, proto, sm->port_per_thread, tsm->snat_thread_index, s, - &out2in_ed_kv)) + &allocated_addr, + &allocated_port, &out2in_ed_kv)) { nat_elog_notice ("addresses exhausted"); b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS]; @@ -378,6 +386,8 @@ slow_path_ed (snat_main_t * sm, } out2in_ed_inserted = true; + key1.addr = allocated_addr; + key1.port = allocated_port; } else { @@ -422,9 +432,9 @@ slow_path_ed (snat_main_t * sm, s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; - make_ed_kv (&out2in_ed_kv, &key1.addr, &key->r_addr, key->proto, - s->out2in.fib_index, key1.port, key->r_port); - out2in_ed_kv.value = s - tsm->sessions; + make_ed_kv (&key1.addr, &r_addr, proto, + s->out2in.fib_index, key1.port, r_port, s - tsm->sessions, + &out2in_ed_kv); if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->out2in_ed, &out2in_ed_kv, nat44_o2i_ed_is_idle_session_cb, &ctx)) @@ -435,16 +445,18 @@ slow_path_ed (snat_main_t * sm, if (lb) s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING; s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT; - s->ext_host_addr = key->r_addr; - s->ext_host_port = key->r_port; + s->ext_host_addr = r_addr; + s->ext_host_port = r_port; s->in2out = key0; s->out2in = key1; s->out2in.protocol = key0.protocol; - kv->value = s - tsm->sessions; + clib_bihash_kv_16_8_t in2out_ed_kv; + make_ed_kv (&l_addr, &r_addr, proto, rx_fib_index, l_port, r_port, + s - tsm->sessions, &in2out_ed_kv); ctx.now = now; ctx.thread_index = thread_index; - if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, kv, + if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, &in2out_ed_kv, nat44_i2o_ed_is_idle_session_cb, &ctx)) nat_elog_notice ("in2out-ed key add failed"); @@ -497,11 +509,11 @@ nat44_ed_not_translate (snat_main_t * sm, vlib_node_runtime_t * node, clib_bihash_kv_16_8_t kv, value; snat_session_key_t key0, key1; - make_ed_kv (&kv, &ip->dst_address, &ip->src_address, ip->protocol, - sm->outside_fib_index, udp->dst_port, udp->src_port); + make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol, + sm->outside_fib_index, udp->dst_port, udp->src_port, ~0ULL, + &kv); - /* NAT packet aimed at external address if */ - /* has active sessions */ + /* NAT packet aimed at external address if has active sessions */ if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value)) { key0.addr = ip->dst_address; @@ -527,7 +539,6 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip, u32 thread_index, f64 now, vlib_main_t * vm, vlib_buffer_t * b) { - nat_ed_ses_key_t key; clib_bihash_kv_16_8_t kv, value; snat_session_t *s = 0; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; @@ -537,23 +548,19 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip, if (ip->protocol == IP_PROTOCOL_ICMP) { - key.as_u64[0] = key.as_u64[1] = 0; - if (get_icmp_i2o_ed_key (b, ip, &key)) + if (get_icmp_i2o_ed_key (b, ip, 0, ~0ULL, 0, 0, 0, &kv)) return 0; - key.fib_index = 0; - kv.key[0] = key.as_u64[0]; - kv.key[1] = key.as_u64[1]; } else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP) { - make_ed_kv (&kv, &ip->src_address, &ip->dst_address, ip->protocol, 0, + make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol, 0, vnet_buffer (b)->ip.reass.l4_src_port, - vnet_buffer (b)->ip.reass.l4_dst_port); + vnet_buffer (b)->ip.reass.l4_dst_port, ~0ULL, &kv); } else { - make_ed_kv (&kv, &ip->src_address, &ip->dst_address, ip->protocol, 0, 0, - 0); + make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol, 0, 0, + 0, ~0ULL, &kv); } if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value)) @@ -584,7 +591,7 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip, static_always_inline int nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip, - u8 proto, u16 src_port, u16 dst_port, + u16 src_port, u16 dst_port, u32 thread_index, u32 rx_sw_if_index, u32 tx_sw_if_index) { @@ -596,8 +603,8 @@ nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip, u32 tx_fib_index = ip4_fib_table_get_index_for_sw_if_index (tx_sw_if_index); /* src NAT check */ - make_ed_kv (&kv, &ip->src_address, &ip->dst_address, proto, tx_fib_index, - src_port, dst_port); + make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol, + tx_fib_index, src_port, dst_port, ~0ULL, &kv); if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value)) { s = pool_elt_at_index (tsm->sessions, value.value); @@ -612,8 +619,8 @@ nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip, } /* dst NAT check */ - make_ed_kv (&kv, &ip->dst_address, &ip->src_address, proto, rx_fib_index, - dst_port, src_port); + make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol, + rx_fib_index, dst_port, src_port, ~0ULL, &kv); if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value)) { s = pool_elt_at_index (tsm->sessions, value.value); @@ -643,29 +650,26 @@ icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node, { u32 sw_if_index; u32 rx_fib_index; - nat_ed_ses_key_t key; snat_session_t *s = 0; u8 dont_translate = 0; clib_bihash_kv_16_8_t kv, value; u32 next = ~0; int err; + u16 l_port = 0, r_port = 0; // initialize to workaround gcc warning snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX]; rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index); - key.as_u64[0] = key.as_u64[1] = 0; - err = get_icmp_i2o_ed_key (b, ip, &key); + err = + get_icmp_i2o_ed_key (b, ip, rx_fib_index, ~0ULL, p_proto, &l_port, + &r_port, &kv); if (err != 0) { b->error = node->errors[err]; next = NAT_NEXT_DROP; goto out; } - key.fib_index = rx_fib_index; - - kv.key[0] = key.as_u64[0]; - kv.key[1] = key.as_u64[1]; if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value)) { @@ -673,7 +677,7 @@ icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node, { if (PREDICT_FALSE (nat44_ed_not_translate_output_feature - (sm, ip, key.proto, key.l_port, key.r_port, thread_index, + (sm, ip, l_port, r_port, thread_index, sw_if_index, vnet_buffer (b)->sw_if_index[VLIB_TX]))) { dont_translate = 1; @@ -701,8 +705,10 @@ icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node, goto out; } - next = slow_path_ed (sm, b, rx_fib_index, &kv, &s, node, next, - thread_index, vlib_time_now (sm->vlib_main)); + next = + slow_path_ed (sm, b, ip->src_address, ip->dst_address, l_port, r_port, + ip->protocol, rx_fib_index, &s, node, next, + thread_index, vlib_time_now (sm->vlib_main)); if (PREDICT_FALSE (next == NAT_NEXT_DROP)) goto out; @@ -730,8 +736,6 @@ icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node, s = pool_elt_at_index (tsm->sessions, value.value); } - - *p_proto = ip_proto_to_snat_proto (key.proto); out: if (s) *p_value = s->out2in; @@ -798,8 +802,8 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm, } old_addr = ip->src_address.as_u32; - make_ed_kv (&s_kv, &ip->src_address, &ip->dst_address, ip->protocol, - rx_fib_index, 0, 0); + make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol, + rx_fib_index, 0, 0, ~0ULL, &s_kv); if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &s_kv, &s_value)) { @@ -834,8 +838,8 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm, { new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32; - make_ed_kv (&s_kv, &s->out2in.addr, &ip->dst_address, ip->protocol, - outside_fib_index, 0, 0); + make_ed_kv (&s->out2in.addr, &ip->dst_address, ip->protocol, + outside_fib_index, 0, 0, ~0ULL, &s_kv); if (clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value)) goto create_ses; @@ -846,8 +850,9 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm, for (i = 0; i < vec_len (sm->addresses); i++) { - make_ed_kv (&s_kv, &sm->addresses[i].addr, &ip->dst_address, - ip->protocol, outside_fib_index, 0, 0); + make_ed_kv (&sm->addresses[i].addr, &ip->dst_address, + ip->protocol, outside_fib_index, 0, 0, ~0ULL, + &s_kv); if (clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value)) { new_addr = ip->src_address.as_u32 = @@ -879,15 +884,13 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm, s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; /* Add to lookup tables */ - make_ed_kv (&s_kv, &s->in2out.addr, &ip->dst_address, ip->protocol, - rx_fib_index, 0, 0); - s_kv.value = s - tsm->sessions; + make_ed_kv (&s->in2out.addr, &ip->dst_address, ip->protocol, + rx_fib_index, 0, 0, s - tsm->sessions, &s_kv); if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1)) nat_elog_notice ("in2out key add failed"); - make_ed_kv (&s_kv, &s->out2in.addr, &ip->dst_address, ip->protocol, - outside_fib_index, 0, 0); - s_kv.value = s - tsm->sessions; + make_ed_kv (&s->out2in.addr, &ip->dst_address, ip->protocol, + outside_fib_index, 0, 0, s - tsm->sessions, &s_kv); if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1)) nat_elog_notice ("out2in key add failed"); } @@ -1016,10 +1019,10 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm, goto trace0; } - make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address, + make_ed_kv (&ip0->src_address, &ip0->dst_address, ip0->protocol, rx_fib_index0, vnet_buffer (b0)->ip.reass.l4_src_port, - vnet_buffer (b0)->ip.reass.l4_dst_port); + vnet_buffer (b0)->ip.reass.l4_dst_port, ~0ULL, &kv0); // lookup for session if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0)) @@ -1302,10 +1305,10 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm, } // move down - make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address, + make_ed_kv (&ip0->src_address, &ip0->dst_address, ip0->protocol, rx_fib_index0, vnet_buffer (b0)->ip.reass.l4_src_port, - vnet_buffer (b0)->ip.reass.l4_dst_port); + vnet_buffer (b0)->ip.reass.l4_dst_port, ~0ULL, &kv0); if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0)) { @@ -1325,10 +1328,9 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm, { if (PREDICT_FALSE (nat44_ed_not_translate_output_feature - (sm, ip0, ip0->protocol, - vnet_buffer (b0)->ip.reass.l4_src_port, - vnet_buffer (b0)->ip.reass.l4_dst_port, - thread_index, sw_if_index0, + (sm, ip0, vnet_buffer (b0)->ip.reass.l4_src_port, + vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index, + sw_if_index0, vnet_buffer (b0)->sw_if_index[VLIB_TX]))) goto trace0; @@ -1352,8 +1354,12 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm, goto trace0; } - next0 = slow_path_ed (sm, b0, rx_fib_index0, &kv0, &s0, node, - next0, thread_index, now); + next0 = + slow_path_ed (sm, b0, ip0->src_address, ip0->dst_address, + vnet_buffer (b0)->ip.reass.l4_src_port, + vnet_buffer (b0)->ip.reass.l4_dst_port, + ip0->protocol, rx_fib_index0, &s0, node, next0, + thread_index, now); if (PREDICT_FALSE (next0 == NAT_NEXT_DROP)) goto trace0; -- cgit 1.2.3-korg