From: Klement Sekera Date: Fri, 17 Apr 2020 18:42:28 +0000 (+0000) Subject: nat: improve perf - long read after short write X-Git-Tag: v20.09-rc0~131 X-Git-Url: https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commitdiff_plain;h=770178e365b5c37ecdecfecb424003cca7343ede nat: improve perf - long read after short write Type: improvement Signed-off-by: Klement Sekera Change-Id: Idbbad246161d28f595c25e10d7282c8b33fa9876 --- 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; diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index b0c30d636af..ba682f9325b 100755 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -199,7 +199,10 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index, { snat_session_key_t key; clib_bihash_kv_8_8_t kv; - nat_ed_ses_key_t ed_key; + u8 proto; + u16 r_port, l_port; + ip4_address_t *l_addr, *r_addr; + u32 fib_index = 0; clib_bihash_kv_16_8_t ed_kv; snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data, thread_index); @@ -208,21 +211,20 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index, { if (snat_is_unk_proto_session (s)) { - ed_key.proto = s->in2out.port; - ed_key.r_port = 0; - ed_key.l_port = 0; + make_ed_kv (&s->in2out.addr, &s->ext_host_addr, s->in2out.port, 0, + 0, 0, ~0ULL, &ed_kv); } else { - ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol); - ed_key.l_port = s->in2out.port; - ed_key.r_port = s->ext_host_port; + proto = snat_proto_to_ip_proto (s->in2out.protocol); + l_port = s->in2out.port; + r_port = s->ext_host_port; + l_addr = &s->in2out.addr; + r_addr = &s->ext_host_addr; + proto = snat_proto_to_ip_proto (s->in2out.protocol); + make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL, + &ed_kv); } - ed_key.l_addr = s->in2out.addr; - ed_key.r_addr = s->ext_host_addr; - ed_key.fib_index = 0; - ed_kv.key[0] = ed_key.as_u64[0]; - ed_kv.key[1] = ed_key.as_u64[1]; if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)) nat_elog_warn ("in2out_ed key del failed"); return; @@ -234,36 +236,36 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index, if (is_affinity_sessions (s)) nat_affinity_unlock (s->ext_host_addr, s->out2in.addr, s->in2out.protocol, s->out2in.port); - 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"); - ed_key.l_addr = s->in2out.addr; - ed_key.fib_index = s->in2out.fib_index; + l_addr = &s->in2out.addr; + fib_index = s->in2out.fib_index; if (!snat_is_unk_proto_session (s)) - ed_key.l_port = s->in2out.port; + l_port = s->in2out.port; if (is_twice_nat_session (s)) { - ed_key.r_addr = s->ext_host_nat_addr; - ed_key.r_port = s->ext_host_nat_port; + r_addr = &s->ext_host_nat_addr; + r_port = s->ext_host_nat_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->in2out_ed, &ed_kv, 0)) nat_elog_warn ("in2out_ed key del failed"); @@ -332,7 +334,10 @@ nat44_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index, u8 is_ha) { snat_session_key_t key; - 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; snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data, thread_index); @@ -341,22 +346,22 @@ nat44_free_session_data (snat_main_t * sm, snat_session_t * s, { 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->in2out.port; - ed_key.r_port = s->ext_host_port; + proto = snat_proto_to_ip_proto (s->in2out.protocol); + l_port = s->in2out.port; + r_port = s->ext_host_port; } - ed_key.l_addr = s->in2out.addr; - ed_key.r_addr = s->ext_host_addr; - ed_key.fib_index = 0; - ed_kv.key[0] = ed_key.as_u64[0]; - ed_kv.key[1] = ed_key.as_u64[1]; + l_addr = &s->in2out.addr; + r_addr = &s->ext_host_addr; + fib_index = 0; + make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL, + &ed_kv); if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))) @@ -368,41 +373,40 @@ nat44_free_session_data (snat_main_t * sm, snat_session_t * s, if (is_affinity_sessions (s)) nat_affinity_unlock (s->ext_host_addr, s->out2in.addr, s->in2out.protocol, s->out2in.port); - 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 (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))) nat_elog_warn ("out2in_ed key del failed"); - ed_key.l_addr = s->in2out.addr; - ed_key.fib_index = s->in2out.fib_index; + l_addr = &s->in2out.addr; + fib_index = s->in2out.fib_index; if (!snat_is_unk_proto_session (s)) - ed_key.l_port = s->in2out.port; + l_port = s->in2out.port; if (is_twice_nat_session (s)) { - ed_key.r_addr = s->ext_host_nat_addr; - ed_key.r_port = s->ext_host_nat_port; + r_addr = &s->ext_host_nat_addr; + r_port = s->ext_host_nat_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 (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))) nat_elog_warn ("in2out_ed key del failed"); @@ -2487,6 +2491,46 @@ nat_alloc_addr_and_port_default (snat_address_t * addresses, snat_session_key_t * k, u16 port_per_thread, u32 snat_thread_index); +void +test_ed_make_split () +{ + ip4_address_t l_addr; + l_addr.as_u8[0] = 1; + l_addr.as_u8[1] = 1; + l_addr.as_u8[2] = 1; + l_addr.as_u8[3] = 1; + ip4_address_t r_addr; + r_addr.as_u8[0] = 2; + r_addr.as_u8[1] = 2; + r_addr.as_u8[2] = 2; + r_addr.as_u8[3] = 2; + u16 l_port = 40001; + u16 r_port = 40301; + u8 proto = 9; + u32 fib_index = 9000001; + u64 value = ~0ULL; + clib_bihash_kv_16_8_t kv; + make_ed_kv (&l_addr, &r_addr, proto, fib_index, l_port, r_port, value, &kv); + ip4_address_t l_addr2; + ip4_address_t r_addr2; + clib_memset (&l_addr2, 0, sizeof (l_addr2)); + clib_memset (&r_addr2, 0, sizeof (r_addr2)); + u16 l_port2 = 0; + u16 r_port2 = 0; + u8 proto2 = 0; + u32 fib_index2 = 0; + split_ed_kv (&kv, &l_addr2, &r_addr2, &proto2, &fib_index2, &l_port2, + &r_port2); + u64 value2 = kv.value; + ASSERT (l_addr.as_u32 == l_addr2.as_u32); + ASSERT (r_addr.as_u32 == r_addr2.as_u32); + ASSERT (l_port == l_port2); + ASSERT (r_port == r_port2); + ASSERT (proto == proto2); + ASSERT (fib_index == fib_index2); + ASSERT (value == value2); +} + static clib_error_t * snat_init (vlib_main_t * vm) { @@ -2656,6 +2700,7 @@ snat_init (vlib_main_t * vm) FIB_SOURCE_PRIORITY_LOW, FIB_SOURCE_BH_SIMPLE); + test_ed_make_split (); return error; } @@ -3159,16 +3204,18 @@ u8 * format_ed_session_kvp (u8 * s, va_list * args) { clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *); - nat_ed_ses_key_t k; - k.as_u64[0] = v->key[0]; - k.as_u64[1] = v->key[1]; + u8 proto; + u16 r_port, l_port; + ip4_address_t l_addr, r_addr; + u32 fib_index; + split_ed_kv (v, &l_addr, &r_addr, &proto, &fib_index, &l_port, &r_port); s = format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu", - format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port), - format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port), - format_ip_protocol, k.proto, k.fib_index, v->value); + format_ip4_address, &l_addr, clib_net_to_host_u16 (l_port), + format_ip4_address, &r_addr, clib_net_to_host_u16 (r_port), + format_ip_protocol, proto, fib_index, v->value); return s; } @@ -3340,8 +3387,9 @@ nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index, break; } - make_ed_kv (&kv16, &ip->src_address, &ip->dst_address, - ip->protocol, fib_index, udp->src_port, udp->dst_port); + make_ed_kv (&ip->src_address, &ip->dst_address, + ip->protocol, fib_index, udp->src_port, udp->dst_port, + ~0ULL, &kv16); /* *INDENT-OFF* */ vec_foreach (tsm, sm->per_thread_data) @@ -3410,8 +3458,9 @@ nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip, { udp = ip4_next_header (ip); - make_ed_kv (&kv16, &ip->dst_address, &ip->src_address, - ip->protocol, rx_fib_index, udp->dst_port, udp->src_port); + make_ed_kv (&ip->dst_address, &ip->src_address, + ip->protocol, rx_fib_index, udp->dst_port, udp->src_port, + ~0ULL, &kv16); /* *INDENT-OFF* */ vec_foreach (tsm, sm->per_thread_data) @@ -3431,15 +3480,8 @@ nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip, } else if (proto == SNAT_PROTOCOL_ICMP) { - nat_ed_ses_key_t key; - - if (!get_icmp_o2i_ed_key (b, ip, &key)) + if (!get_icmp_o2i_ed_key (b, ip, rx_fib_index, ~0ULL, 0, 0, 0, &kv16)) { - - key.fib_index = rx_fib_index; - kv16.key[0] = key.as_u64[0]; - kv16.key[1] = key.as_u64[1]; - /* *INDENT-OFF* */ vec_foreach (tsm, sm->per_thread_data) { @@ -3796,14 +3838,14 @@ nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port, key.fib_index = fib_index; s->in2out = key; - make_ed_kv (&kv, in_addr, &s->ext_host_nat_addr, + make_ed_kv (in_addr, &s->ext_host_nat_addr, snat_proto_to_ip_proto (proto), fib_index, in_port, - s->ext_host_nat_port); + s->ext_host_nat_port, s - tsm->sessions, &kv); if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1)) nat_elog_warn ("in2out key add failed"); - make_ed_kv (&kv, out_addr, eh_addr, snat_proto_to_ip_proto (proto), - s->out2in.fib_index, out_port, eh_port); + make_ed_kv (out_addr, eh_addr, snat_proto_to_ip_proto (proto), + s->out2in.fib_index, out_port, eh_port, s - tsm->sessions, &kv); if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1)) nat_elog_warn ("out2in key add failed"); } @@ -3814,7 +3856,6 @@ nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port, u32 fib_index, u32 ti) { snat_main_t *sm = &snat_main; - nat_ed_ses_key_t key; clib_bihash_kv_16_8_t kv, value; u32 thread_index; snat_session_t *s; @@ -3829,14 +3870,8 @@ nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port, thread_index = sm->num_workers; tsm = vec_elt_at_index (sm->per_thread_data, thread_index); - key.l_addr.as_u32 = out_addr->as_u32; - key.l_port = out_port; - key.r_addr.as_u32 = eh_addr->as_u32; - key.r_port = eh_port; - key.proto = proto; - key.fib_index = fib_index; - kv.key[0] = key.as_u64[0]; - kv.key[1] = key.as_u64[1]; + make_ed_kv (out_addr, eh_addr, proto, fib_index, out_port, eh_port, ~0ULL, + &kv); if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value)) return; @@ -3852,21 +3887,14 @@ nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port, u32 thread_index) { snat_main_t *sm = &snat_main; - nat_ed_ses_key_t key; clib_bihash_kv_16_8_t kv, value; snat_session_t *s; snat_main_per_thread_data_t *tsm; tsm = vec_elt_at_index (sm->per_thread_data, thread_index); - key.l_addr.as_u32 = out_addr->as_u32; - key.l_port = out_port; - key.r_addr.as_u32 = eh_addr->as_u32; - key.r_port = eh_port; - key.proto = proto; - key.fib_index = fib_index; - kv.key[0] = key.as_u64[0]; - kv.key[1] = key.as_u64[1]; + make_ed_kv (out_addr, eh_addr, proto, fib_index, out_port, eh_port, ~0ULL, + &kv); if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value)) return; @@ -4411,7 +4439,6 @@ nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port, { ip4_header_t ip; clib_bihash_16_8_t *t; - nat_ed_ses_key_t key; clib_bihash_kv_16_8_t kv, value; u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id); snat_session_t *s; @@ -4429,16 +4456,12 @@ nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port, tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed; - key.l_addr.as_u32 = addr->as_u32; - key.r_addr.as_u32 = eh_addr->as_u32; - key.l_port = clib_host_to_net_u16 (port); - key.r_port = clib_host_to_net_u16 (eh_port); - key.proto = proto; - key.fib_index = fib_index; - kv.key[0] = key.as_u64[0]; - kv.key[1] = key.as_u64[1]; + make_ed_kv (addr, eh_addr, proto, fib_index, clib_host_to_net_u16 (port), + clib_host_to_net_u16 (eh_port), ~0ULL, &kv); if (clib_bihash_search_16_8 (t, &kv, &value)) - return VNET_API_ERROR_NO_SUCH_ENTRY; + { + return VNET_API_ERROR_NO_SUCH_ENTRY; + } if (pool_is_free_index (tsm->sessions, value.value)) return VNET_API_ERROR_UNSPECIFIED; diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h index 98c18c06635..c4f1be23b56 100644 --- a/src/plugins/nat/nat.h +++ b/src/plugins/nat/nat.h @@ -88,23 +88,6 @@ typedef struct }; } snat_session_key_t; -/* endpoint-dependent session key (6-tuple) */ -typedef struct -{ - union - { - struct - { - ip4_address_t l_addr; - ip4_address_t r_addr; - u32 proto:8, fib_index:24; - u16 l_port; - u16 r_port; - }; - u64 as_u64[2]; - }; -} nat_ed_ses_key_t; - /* deterministic session outside key */ typedef struct { diff --git a/src/plugins/nat/nat44_classify.c b/src/plugins/nat/nat44_classify.c index 2afc479aa5b..a57f24177ab 100644 --- a/src/plugins/nat/nat44_classify.c +++ b/src/plugins/nat/nat44_classify.c @@ -258,11 +258,11 @@ nat44_ed_classify_node_fn_inline (vlib_main_t * vm, rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index0); - make_ed_kv (&ed_kv0, &ip0->src_address, - &ip0->dst_address, ip0->protocol, - rx_fib_index0, + 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, + &ed_kv0); /* process whole packet */ if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &ed_kv0, &ed_value0)) diff --git a/src/plugins/nat/nat44_hairpinning.c b/src/plugins/nat/nat44_hairpinning.c index c0b84127741..bdf9e3ce813 100644 --- a/src/plugins/nat/nat44_hairpinning.c +++ b/src/plugins/nat/nat44_hairpinning.c @@ -126,9 +126,9 @@ snat_hairpinning (snat_main_t * sm, if (is_ed) { clib_bihash_kv_16_8_t ed_kv, ed_value; - make_ed_kv (&ed_kv, &ip0->dst_address, &ip0->src_address, + make_ed_kv (&ip0->dst_address, &ip0->src_address, ip0->protocol, sm->outside_fib_index, udp0->dst_port, - udp0->src_port); + udp0->src_port, ~0ULL, &ed_kv); rv = clib_bihash_search_16_8 (&sm->per_thread_data[ti].out2in_ed, &ed_kv, &ed_value); si = ed_value.value; @@ -226,11 +226,12 @@ snat_icmp_hairpinning (snat_main_t * sm, if (is_ed) { clib_bihash_kv_16_8_t ed_kv, ed_value; - make_ed_kv (&ed_kv, &ip0->dst_address, &ip0->src_address, + make_ed_kv (&ip0->dst_address, &ip0->src_address, inner_ip0->protocol, sm->outside_fib_index, - l4_header->src_port, l4_header->dst_port); - if (clib_bihash_search_16_8 (&sm->per_thread_data[ti].out2in_ed, - &ed_kv, &ed_value)) + l4_header->src_port, l4_header->dst_port, ~0ULL, + &ed_kv); + if (clib_bihash_search_16_8 + (&sm->per_thread_data[ti].out2in_ed, &ed_kv, &ed_value)) return 1; si = ed_value.value; } @@ -397,8 +398,8 @@ nat44_ed_hairpinning_unknown_proto (snat_main_t * sm, tsm = &sm->per_thread_data[ti]; old_addr = ip->dst_address.as_u32; - make_ed_kv (&s_kv, &ip->dst_address, &ip->src_address, ip->protocol, - sm->outside_fib_index, 0, 0); + make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol, + sm->outside_fib_index, 0, 0, ~0ULL, &s_kv); if (clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value)) { make_sm_kv (&kv, &ip->dst_address, 0, 0, 0); diff --git a/src/plugins/nat/nat_inlines.h b/src/plugins/nat/nat_inlines.h index daf501dcef3..a0803566ccc 100644 --- a/src/plugins/nat/nat_inlines.h +++ b/src/plugins/nat/nat_inlines.h @@ -473,43 +473,67 @@ nat44_session_update_lru (snat_main_t * sm, snat_session_t * s, } always_inline void -make_ed_kv (clib_bihash_kv_16_8_t * kv, ip4_address_t * l_addr, - ip4_address_t * r_addr, u8 proto, u32 fib_index, u16 l_port, - u16 r_port) +make_ed_kv (ip4_address_t * l_addr, ip4_address_t * r_addr, u8 proto, + u32 fib_index, u16 l_port, u16 r_port, u64 value, + clib_bihash_kv_16_8_t * kv) { - nat_ed_ses_key_t *key = (nat_ed_ses_key_t *) kv->key; - - key->l_addr.as_u32 = l_addr->as_u32; - key->r_addr.as_u32 = r_addr->as_u32; - key->fib_index = fib_index; - key->proto = proto; - key->l_port = l_port; - key->r_port = r_port; + kv->key[0] = (u64) r_addr->as_u32 << 32 | l_addr->as_u32; + kv->key[1] = + (u64) r_port << 48 | (u64) l_port << 32 | fib_index << 8 | proto; + kv->value = value; +} - kv->value = ~0ULL; +always_inline void +split_ed_kv (clib_bihash_kv_16_8_t * kv, + ip4_address_t * l_addr, ip4_address_t * r_addr, u8 * proto, + u32 * fib_index, u16 * l_port, u16 * r_port) +{ + if (l_addr) + { + l_addr->as_u32 = kv->key[0] & (u32) ~ 0; + } + if (r_addr) + { + r_addr->as_u32 = kv->key[0] >> 32; + } + if (r_port) + { + *r_port = kv->key[1] >> 48; + } + if (l_port) + { + *l_port = (kv->key[1] >> 32) & (u16) ~ 0; + } + if (fib_index) + { + *fib_index = (kv->key[1] >> 8) & ((1 << 24) - 1); + } + if (proto) + { + *proto = kv->key[1] & (u8) ~ 0; + } } always_inline void make_sm_kv (clib_bihash_kv_8_8_t * kv, ip4_address_t * addr, u8 proto, u32 fib_index, u16 port) { - snat_session_key_t key; - - key.addr.as_u32 = addr->as_u32; - key.port = port; - key.protocol = proto; - key.fib_index = fib_index; + kv->key = (u64) fib_index << 51 | (u64) proto << 48 | (u64) port << 32 | + addr->as_u32; - kv->key = key.as_u64; kv->value = ~0ULL; } static_always_inline int -get_icmp_i2o_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, - nat_ed_ses_key_t * p_key0) +get_icmp_i2o_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, u32 rx_fib_index, + u64 value, u8 * snat_proto, u16 * l_port, u16 * r_port, + clib_bihash_kv_16_8_t * kv) { + u8 proto; + u16 _l_port, _r_port; + ip4_address_t *l_addr, *r_addr; + icmp46_header_t *icmp0; - nat_ed_ses_key_t key0; icmp_echo_header_t *echo0, *inner_echo0 = 0; ip4_header_t *inner_ip0 = 0; void *l4_header = 0; @@ -521,47 +545,63 @@ get_icmp_i2o_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, if (!icmp_type_is_error_message (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)) { - key0.proto = IP_PROTOCOL_ICMP; - key0.l_addr = ip0->src_address; - key0.r_addr = ip0->dst_address; - key0.l_port = vnet_buffer (b)->ip.reass.l4_src_port; // TODO should this be src or dst? - key0.r_port = 0; + proto = IP_PROTOCOL_ICMP; + l_addr = &ip0->src_address; + r_addr = &ip0->dst_address; + _l_port = vnet_buffer (b)->ip.reass.l4_src_port; // TODO should this be src or dst? + _r_port = 0; } else { inner_ip0 = (ip4_header_t *) (echo0 + 1); l4_header = ip4_next_header (inner_ip0); - key0.proto = inner_ip0->protocol; - key0.r_addr = inner_ip0->src_address; - key0.l_addr = inner_ip0->dst_address; + proto = inner_ip0->protocol; + r_addr = &inner_ip0->src_address; + l_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.r_port = 0; - key0.l_port = inner_echo0->identifier; + _r_port = 0; + _l_port = inner_echo0->identifier; break; case SNAT_PROTOCOL_UDP: case SNAT_PROTOCOL_TCP: - key0.l_port = ((tcp_udp_header_t *) l4_header)->dst_port; - key0.r_port = ((tcp_udp_header_t *) l4_header)->src_port; + _l_port = ((tcp_udp_header_t *) l4_header)->dst_port; + _r_port = ((tcp_udp_header_t *) l4_header)->src_port; break; default: return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL; } } - *p_key0 = key0; + make_ed_kv (l_addr, r_addr, proto, rx_fib_index, _l_port, _r_port, value, + kv); + if (snat_proto) + { + *snat_proto = ip_proto_to_snat_proto (proto); + } + if (l_port) + { + *l_port = _l_port; + } + if (r_port) + { + *r_port = _r_port; + } return 0; } static_always_inline int -get_icmp_o2i_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, - nat_ed_ses_key_t * p_key0) +get_icmp_o2i_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, u32 rx_fib_index, + u64 value, u8 * snat_proto, u16 * l_port, u16 * r_port, + clib_bihash_kv_16_8_t * kv) { icmp46_header_t *icmp0; - nat_ed_ses_key_t key0; + u8 proto; + ip4_address_t *l_addr, *r_addr; + u16 _l_port, _r_port; icmp_echo_header_t *echo0, *inner_echo0 = 0; ip4_header_t *inner_ip0; void *l4_header = 0; @@ -573,37 +613,50 @@ get_icmp_o2i_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, if (!icmp_type_is_error_message (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)) { - key0.proto = IP_PROTOCOL_ICMP; - key0.l_addr = ip0->dst_address; - key0.r_addr = ip0->src_address; - key0.l_port = vnet_buffer (b)->ip.reass.l4_src_port; // TODO should this be src or dst? - key0.r_port = 0; + proto = IP_PROTOCOL_ICMP; + l_addr = &ip0->dst_address; + r_addr = &ip0->src_address; + _l_port = vnet_buffer (b)->ip.reass.l4_src_port; // TODO should this be src or dst? + _r_port = 0; } 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; + proto = inner_ip0->protocol; + l_addr = &inner_ip0->src_address; + 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 = inner_echo0->identifier; - key0.r_port = 0; + _l_port = inner_echo0->identifier; + _r_port = 0; 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; + _l_port = ((tcp_udp_header_t *) l4_header)->src_port; + _r_port = ((tcp_udp_header_t *) l4_header)->dst_port; break; default: return -1; } } - *p_key0 = key0; + make_ed_kv (l_addr, r_addr, proto, rx_fib_index, _l_port, _r_port, value, + kv); + if (snat_proto) + { + *snat_proto = ip_proto_to_snat_proto (proto); + } + if (l_port) + { + *l_port = _l_port; + } + if (r_port) + { + *r_port = _r_port; + } return 0; } diff --git a/src/plugins/nat/out2in_ed.c b/src/plugins/nat/out2in_ed.c index 560dc0d89d4..1382125dcf7 100644 --- a/src/plugins/nat/out2in_ed.c +++ b/src/plugins/nat/out2in_ed.c @@ -94,7 +94,10 @@ nat44_o2i_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; @@ -106,28 +109,28 @@ nat44_o2i_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg) sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s); if (ctx->now >= sess_timeout_time) { - ed_key.l_addr = s->in2out.addr; - ed_key.r_addr = s->ext_host_addr; - ed_key.fib_index = s->in2out.fib_index; + l_addr = &s->in2out.addr; + r_addr = &s->ext_host_addr; + fib_index = s->in2out.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->in2out.port; - ed_key.r_port = s->ext_host_port; + proto = snat_proto_to_ip_proto (s->in2out.protocol); + l_port = s->in2out.port; + r_port = s->ext_host_port; } if (is_twice_nat_session (s)) { - ed_key.r_addr = s->ext_host_nat_addr; - ed_key.r_port = s->ext_host_nat_port; + r_addr = &s->ext_host_nat_addr; + r_port = s->ext_host_nat_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->in2out_ed, &ed_kv, 0)) nat_elog_warn ("in2out_ed key del failed"); @@ -233,9 +236,9 @@ create_session_for_static_mapping_ed (snat_main_t * sm, s->in2out.protocol = s->out2in.protocol; /* Add to lookup tables */ - make_ed_kv (&kv, &e_key.addr, &s->ext_host_addr, ip->protocol, - e_key.fib_index, e_key.port, s->ext_host_port); - kv.value = s - tsm->sessions; + make_ed_kv (&e_key.addr, &s->ext_host_addr, ip->protocol, + e_key.fib_index, e_key.port, s->ext_host_port, + s - tsm->sessions, &kv); ctx.now = now; ctx.thread_index = thread_index; if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->out2in_ed, &kv, @@ -261,15 +264,16 @@ create_session_for_static_mapping_ed (snat_main_t * sm, s->ext_host_nat_addr.as_u32 = eh_key.addr.as_u32; s->ext_host_nat_port = eh_key.port; s->flags |= SNAT_SESSION_FLAG_TWICE_NAT; - make_ed_kv (&kv, &l_key.addr, &s->ext_host_nat_addr, ip->protocol, - l_key.fib_index, l_key.port, s->ext_host_nat_port); + make_ed_kv (&l_key.addr, &s->ext_host_nat_addr, ip->protocol, + l_key.fib_index, l_key.port, s->ext_host_nat_port, + s - tsm->sessions, &kv); } else { - make_ed_kv (&kv, &l_key.addr, &s->ext_host_addr, ip->protocol, - l_key.fib_index, l_key.port, s->ext_host_port); + make_ed_kv (&l_key.addr, &s->ext_host_addr, ip->protocol, + l_key.fib_index, l_key.port, s->ext_host_port, + s - tsm->sessions, &kv); } - kv.value = s - tsm->sessions; if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, &kv, nat44_i2o_ed_is_idle_session_cb, &ctx)) @@ -299,14 +303,14 @@ create_session_for_static_mapping_ed (snat_main_t * sm, } static int -next_src_nat (snat_main_t * sm, ip4_header_t * ip, u8 proto, u16 src_port, +next_src_nat (snat_main_t * sm, ip4_header_t * ip, u16 src_port, u16 dst_port, u32 thread_index, u32 rx_fib_index) { clib_bihash_kv_16_8_t kv, value; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; - make_ed_kv (&kv, &ip->src_address, &ip->dst_address, proto, - rx_fib_index, src_port, dst_port); + make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol, + rx_fib_index, src_port, dst_port, ~0ULL, &kv); if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value)) return 1; @@ -317,37 +321,35 @@ static void create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, 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_session_t *s = 0; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; f64 now = vlib_time_now (sm->vlib_main); + u16 l_port, r_port; if (ip->protocol == IP_PROTOCOL_ICMP) { - if (get_icmp_o2i_ed_key (b, ip, &key)) + if (get_icmp_o2i_ed_key + (b, ip, rx_fib_index, ~0ULL, 0, &l_port, &r_port, &kv)) 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; + if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP) + { + udp = ip4_next_header (ip); + l_port = udp->dst_port; + r_port = udp->src_port; + } + else + { + l_port = 0; + r_port = 0; + } + make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol, + rx_fib_index, l_port, r_port, ~0ULL, &kv); } - key.fib_index = 0; - 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)) { @@ -367,13 +369,13 @@ create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip, return; } - proto = ip_proto_to_snat_proto (key.proto); + proto = ip_proto_to_snat_proto (ip->protocol); - s->ext_host_addr = key.r_addr; - s->ext_host_port = key.r_port; + s->ext_host_addr = ip->src_address; + s->ext_host_port = r_port; s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS; - s->out2in.addr = key.l_addr; - s->out2in.port = key.l_port; + s->out2in.addr = ip->dst_address; + s->out2in.port = l_port; s->out2in.protocol = proto; if (proto == ~0) { @@ -423,32 +425,30 @@ icmp_match_out2in_ed (snat_main_t * sm, vlib_node_runtime_t * node, u8 * p_dont_translate, void *d, void *e) { u32 next = ~0, sw_if_index, rx_fib_index; - nat_ed_ses_key_t key; clib_bihash_kv_16_8_t kv, value; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; snat_session_t *s = 0; u8 dont_translate = 0, is_addr_only, identity_nat; snat_session_key_t e_key, l_key; + u16 l_port, r_port; 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); - if (get_icmp_o2i_ed_key (b, ip, &key)) + if (get_icmp_o2i_ed_key + (b, ip, rx_fib_index, ~0ULL, p_proto, &l_port, &r_port, &kv)) { b->error = node->errors[NAT_OUT2IN_ED_ERROR_UNSUPPORTED_PROTOCOL]; 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->out2in_ed, &kv, &value)) { /* Try to match static mapping */ e_key.addr = ip->dst_address; - e_key.port = key.l_port; - e_key.protocol = ip_proto_to_snat_proto (key.proto); + e_key.port = l_port; + e_key.protocol = ip_proto_to_snat_proto (ip->protocol); e_key.fib_index = rx_fib_index; if (snat_static_mapping_match (sm, e_key, &l_key, 1, &is_addr_only, 0, 0, 0, &identity_nat)) @@ -469,7 +469,7 @@ icmp_match_out2in_ed (snat_main_t * sm, vlib_node_runtime_t * node, else { dont_translate = 1; - if (next_src_nat (sm, ip, key.proto, key.l_port, key.r_port, + if (next_src_nat (sm, ip, l_port, r_port, thread_index, rx_fib_index)) { next = NAT_NEXT_IN2OUT_ED_FAST_PATH; @@ -529,8 +529,6 @@ icmp_match_out2in_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->in2out; @@ -560,8 +558,8 @@ nat44_ed_out2in_unknown_proto (snat_main_t * sm, old_addr = ip->dst_address.as_u32; - make_ed_kv (&s_kv, &ip->dst_address, &ip->src_address, ip->protocol, - rx_fib_index, 0, 0); + make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol, rx_fib_index, + 0, 0, ~0ULL, &s_kv); if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value)) { @@ -613,9 +611,8 @@ nat44_ed_out2in_unknown_proto (snat_main_t * sm, if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1)) nat_elog_notice ("out2in key add failed"); - make_ed_kv (&s_kv, &ip->dst_address, &ip->src_address, ip->protocol, - m->fib_index, 0, 0); - s_kv.value = s - tsm->sessions; + make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol, + m->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"); } @@ -721,10 +718,10 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, goto trace0; } - make_ed_kv (&kv0, &ip0->dst_address, &ip0->src_address, + make_ed_kv (&ip0->dst_address, &ip0->src_address, ip0->protocol, rx_fib_index0, vnet_buffer (b0)->ip.reass.l4_dst_port, - vnet_buffer (b0)->ip.reass.l4_src_port); + vnet_buffer (b0)->ip.reass.l4_src_port, ~0ULL, &kv0); if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0)) { @@ -1006,10 +1003,10 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, goto trace0; } - make_ed_kv (&kv0, &ip0->dst_address, &ip0->src_address, + make_ed_kv (&ip0->dst_address, &ip0->src_address, ip0->protocol, rx_fib_index0, vnet_buffer (b0)->ip.reass.l4_dst_port, - vnet_buffer (b0)->ip.reass.l4_src_port); + vnet_buffer (b0)->ip.reass.l4_src_port, ~0ULL, &kv0); s0 = NULL; if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0)) @@ -1059,12 +1056,10 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, } else { - if (next_src_nat (sm, ip0, ip0->protocol, - vnet_buffer (b0)->ip. - reass.l4_src_port, - vnet_buffer (b0)->ip. - reass.l4_dst_port, thread_index, - rx_fib_index0)) + if (next_src_nat + (sm, ip0, vnet_buffer (b0)->ip.reass.l4_src_port, + vnet_buffer (b0)->ip.reass.l4_dst_port, + thread_index, rx_fib_index0)) { next0 = NAT_NEXT_IN2OUT_ED_FAST_PATH; goto trace0;