From 1953da661069c967f1159162dc65c9a1210fcdbd Mon Sep 17 00:00:00 2001 From: Filip Varga Date: Thu, 30 Sep 2021 13:35:59 +0200 Subject: nat: nat44-ei configuration improvements nat44-ed core configuration improvements & fixes [0-5] adjusted for nat44-ei plugin. Improvements: * repeating code converted to functions * simplified functions used for pool address, static mapping and interface configuration. Clean up: * remove obsolete code and logic persisted after plugin separation from old SNAT plugin. Fixes: * [0] return correct API behavior changed in [5] Type: improvement [0] https://gerrit.fd.io/r/c/vpp/+/33622 [1] https://gerrit.fd.io/r/c/vpp/+/33431 [2] https://gerrit.fd.io/r/c/vpp/+/33337 [3] https://gerrit.fd.io/r/c/vpp/+/33249 [4] https://gerrit.fd.io/r/c/vpp/+/32796 [5] https://gerrit.fd.io/r/c/vpp/+/32951 Signed-off-by: Filip Varga Change-Id: Ie197faa576cb49acb3d218f14e00cb7d13ad9342 --- src/plugins/nat/nat44-ei/nat44_ei.c | 2028 ++++++++++++++++++++--------------- 1 file changed, 1172 insertions(+), 856 deletions(-) (limited to 'src/plugins/nat/nat44-ei/nat44_ei.c') diff --git a/src/plugins/nat/nat44-ei/nat44_ei.c b/src/plugins/nat/nat44-ei/nat44_ei.c index 3691af3a53e..694bc6bec5a 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei.c +++ b/src/plugins/nat/nat44-ei/nat44_ei.c @@ -304,6 +304,76 @@ nat_validate_interface_counters (nat44_ei_main_t *nm, u32 sw_if_index) nat_validate_simple_counter (nm->counters.hairpinning, sw_if_index); } +static void +nat44_ei_add_del_addr_to_fib_foreach_out_if (ip4_address_t *addr, u8 is_add) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + nat44_ei_interface_t *i; + + pool_foreach (i, nm->interfaces) + { + if (nat44_ei_interface_is_outside (i) && !nm->out2in_dpo) + { + nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, is_add); + } + } + pool_foreach (i, nm->output_feature_interfaces) + { + if (nat44_ei_interface_is_outside (i) && !nm->out2in_dpo) + { + nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, is_add); + } + } +} + +static_always_inline void +nat44_ei_add_del_addr_to_fib_foreach_addr (u32 sw_if_index, u8 is_add) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + nat44_ei_address_t *ap; + + vec_foreach (ap, nm->addresses) + { + nat44_ei_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, is_add); + } +} + +static_always_inline void +nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (u32 sw_if_index, u8 is_add) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + nat44_ei_static_mapping_t *m; + + pool_foreach (m, nm->static_mappings) + { + if (is_sm_addr_only (m->flags) && + !(m->local_addr.as_u32 == m->external_addr.as_u32)) + { + nat44_ei_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, + is_add); + } + } +} + +static int +nat44_ei_is_address_used_in_static_mapping (ip4_address_t addr) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + nat44_ei_static_mapping_t *m; + pool_foreach (m, nm->static_mappings) + { + if (is_sm_addr_only (m->flags) || is_sm_identity_nat (m->flags)) + { + continue; + } + if (m->external_addr.as_u32 == addr.as_u32) + { + return 1; + } + } + return 0; +} + clib_error_t * nat44_ei_init (vlib_main_t *vm) { @@ -372,14 +442,15 @@ nat44_ei_init (vlib_main_t *vm) /* Use all available workers by default */ if (nm->num_workers > 1) { - for (i = 0; i < nm->num_workers; i++) bitmap = clib_bitmap_set (bitmap, i, 1); nat44_ei_set_workers (bitmap); clib_bitmap_free (bitmap); } else - nm->per_thread_data[0].snat_thread_index = 0; + { + nm->per_thread_data[0].snat_thread_index = 0; + } /* callbacks to call when interface address changes. */ cbi.function = nat44_ei_ip4_add_del_interface_address_cb; @@ -472,6 +543,25 @@ nat44_ei_plugin_enable (nat44_ei_config_t c) vlib_zero_simple_counter (&nm->total_sessions, 0); vlib_zero_simple_counter (&nm->user_limit_reached, 0); + if (nm->num_workers > 1) + { + if (nm->fq_in2out_index == ~0) + { + nm->fq_in2out_index = vlib_frame_queue_main_init ( + nm->in2out_node_index, nm->frame_queue_nelts); + } + if (nm->fq_out2in_index == ~0) + { + nm->fq_out2in_index = vlib_frame_queue_main_init ( + nm->out2in_node_index, nm->frame_queue_nelts); + } + if (nm->fq_in2out_output_index == ~0) + { + nm->fq_in2out_output_index = vlib_frame_queue_main_init ( + nm->in2out_output_node_index, nm->frame_queue_nelts); + } + } + nat_ha_enable (); nm->enabled = 1; @@ -492,17 +582,44 @@ nat44_ei_addresses_free (nat44_ei_address_t **addresses) *addresses = 0; } -int -nat44_ei_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) +static_always_inline nat44_ei_outside_fib_t * +nat44_ei_get_outside_fib (nat44_ei_outside_fib_t *outside_fibs, u32 fib_index) +{ + nat44_ei_outside_fib_t *f; + vec_foreach (f, outside_fibs) + { + if (f->fib_index == fib_index) + { + return f; + } + } + return 0; +} + +static_always_inline nat44_ei_interface_t * +nat44_ei_get_interface (nat44_ei_interface_t *interfaces, u32 sw_if_index) +{ + nat44_ei_interface_t *i; + pool_foreach (i, interfaces) + { + if (i->sw_if_index == sw_if_index) + { + return i; + } + } + return 0; +} + +static_always_inline int +nat44_ei_add_interface (u32 sw_if_index, u8 is_inside) { const char *feature_name, *del_feature_name; nat44_ei_main_t *nm = &nat44_ei_main; - nat44_ei_interface_t *i; - nat44_ei_address_t *ap; - nat44_ei_static_mapping_t *m; + nat44_ei_outside_fib_t *outside_fib; - u32 fib_index = - fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index); + nat44_ei_interface_t *i; + u32 fib_index; + int rv; fail_if_disabled (); @@ -512,410 +629,481 @@ nat44_ei_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) return VNET_API_ERROR_UNSUPPORTED; } - pool_foreach (i, nm->output_feature_interfaces) + if (nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index)) { - if (i->sw_if_index == sw_if_index) - { - nat44_ei_log_err ("error interface already configured"); - return VNET_API_ERROR_VALUE_EXIST; - } + nat44_ei_log_err ("error interface already configured"); + return VNET_API_ERROR_VALUE_EXIST; } - if (nm->static_mapping_only && !(nm->static_mapping_connection_tracking)) - feature_name = is_inside ? "nat44-ei-in2out-fast" : "nat44-ei-out2in-fast"; - else + i = nat44_ei_get_interface (nm->interfaces, sw_if_index); + if (i) { + if ((nat44_ei_interface_is_inside (i) && is_inside) || + (nat44_ei_interface_is_outside (i) && !is_inside)) + { + return 0; + } if (nm->num_workers > 1) - feature_name = is_inside ? "nat44-ei-in2out-worker-handoff" : - "nat44-ei-out2in-worker-handoff"; + { + del_feature_name = !is_inside ? "nat44-ei-in2out-worker-handoff" : + "nat44-ei-out2in-worker-handoff"; + feature_name = "nat44-ei-handoff-classify"; + } else - feature_name = is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in"; - } - - if (nm->fq_in2out_index == ~0 && nm->num_workers > 1) - nm->fq_in2out_index = vlib_frame_queue_main_init (nm->in2out_node_index, - nm->frame_queue_nelts); + { + del_feature_name = + !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in"; - if (nm->fq_out2in_index == ~0 && nm->num_workers > 1) - nm->fq_out2in_index = vlib_frame_queue_main_init (nm->out2in_node_index, - nm->frame_queue_nelts); + feature_name = "nat44-ei-classify"; + } - if (!is_inside) - { - vec_foreach (outside_fib, nm->outside_fibs) + rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1); + if (rv) { - if (outside_fib->fib_index == fib_index) - { - if (is_del) - { - outside_fib->refcount--; - if (!outside_fib->refcount) - vec_del1 (nm->outside_fibs, - outside_fib - nm->outside_fibs); - } - else - outside_fib->refcount++; - goto feature_set; - } + return rv; } - if (!is_del) + rv = vnet_feature_enable_disable ("ip4-unicast", del_feature_name, + sw_if_index, 0, 0, 0); + if (rv) { - vec_add2 (nm->outside_fibs, outside_fib, 1); - outside_fib->refcount = 1; - outside_fib->fib_index = fib_index; + return rv; + } + rv = vnet_feature_enable_disable ("ip4-unicast", feature_name, + sw_if_index, 1, 0, 0); + if (rv) + { + return rv; + } + if (!is_inside) + { + rv = vnet_feature_enable_disable ( + "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0); + if (rv) + { + return rv; + } } } - -feature_set: - pool_foreach (i, nm->interfaces) + else { - if (i->sw_if_index == sw_if_index) + if (nm->num_workers > 1) { - if (is_del) - { - if (nat44_ei_interface_is_inside (i) && - nat44_ei_interface_is_outside (i)) - { - if (is_inside) - i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_INSIDE; - else - i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE; - - if (nm->num_workers > 1) - { - del_feature_name = "nat44-ei-handoff-classify"; - clib_warning ( - "del_feature_name = nat44-ei-handoff-classify"); - feature_name = !is_inside ? - "nat44-ei-in2out-worker-handoff" : - "nat44-ei-out2in-worker-handoff"; - } - else - { - del_feature_name = "nat44-ei-classify"; - clib_warning ("del_feature_name = nat44-ei-classify"); - feature_name = - !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in"; - } + feature_name = is_inside ? "nat44-ei-in2out-worker-handoff" : + "nat44-ei-out2in-worker-handoff"; + } + else + { + feature_name = is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in"; + } + nat_validate_interface_counters (nm, sw_if_index); - int rv = - ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0); - if (rv) - return rv; - rv = vnet_feature_enable_disable ( - "ip4-unicast", del_feature_name, sw_if_index, 0, 0, 0); - if (rv) - return rv; - rv = vnet_feature_enable_disable ( - "ip4-unicast", feature_name, sw_if_index, 1, 0, 0); - if (rv) - return rv; - if (!is_inside) - { - rv = vnet_feature_enable_disable ("ip4-local", - "nat44-ei-hairpinning", - sw_if_index, 1, 0, 0); - if (rv) - return rv; - } - } - else - { - int rv = - ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0); - if (rv) - return rv; - rv = vnet_feature_enable_disable ( - "ip4-unicast", feature_name, sw_if_index, 0, 0, 0); - if (rv) - return rv; - pool_put (nm->interfaces, i); - if (is_inside) - { - rv = vnet_feature_enable_disable ("ip4-local", - "nat44-ei-hairpinning", - sw_if_index, 0, 0, 0); - if (rv) - return rv; - } - } - } - else + rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1); + if (rv) + { + return rv; + } + rv = vnet_feature_enable_disable ("ip4-unicast", feature_name, + sw_if_index, 1, 0, 0); + if (rv) + { + return rv; + } + if (is_inside && !nm->out2in_dpo) + { + rv = vnet_feature_enable_disable ( + "ip4-local", "nat44-ei-hairpinning", sw_if_index, 1, 0, 0); + if (rv) { - if ((nat44_ei_interface_is_inside (i) && is_inside) || - (nat44_ei_interface_is_outside (i) && !is_inside)) - return 0; - - if (nm->num_workers > 1) - { - del_feature_name = !is_inside ? - "nat44-ei-in2out-worker-handoff" : - "nat44-ei-out2in-worker-handoff"; - feature_name = "nat44-ei-handoff-classify"; - clib_warning ("feature_name = nat44-ei-handoff-classify"); - } - else - { - del_feature_name = - !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in"; - feature_name = "nat44-ei-classify"; - clib_warning ("feature_name = nat44-ei-classify"); - } - - int rv = - ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1); - if (rv) - return rv; - rv = vnet_feature_enable_disable ( - "ip4-unicast", del_feature_name, sw_if_index, 0, 0, 0); - if (rv) - return rv; - rv = vnet_feature_enable_disable ("ip4-unicast", feature_name, - sw_if_index, 1, 0, 0); - if (rv) - return rv; - if (!is_inside) - { - rv = vnet_feature_enable_disable ( - "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0); - if (rv) - return rv; - } - goto set_flags; + return rv; } - - goto fib; } - } - if (is_del) - { - nat44_ei_log_err ("error interface couldn't be found"); - return VNET_API_ERROR_NO_SUCH_ENTRY; + pool_get (nm->interfaces, i); + i->sw_if_index = sw_if_index; + i->flags = 0; } - pool_get (nm->interfaces, i); - i->sw_if_index = sw_if_index; - i->flags = 0; - nat_validate_interface_counters (nm, sw_if_index); - - int rv = vnet_feature_enable_disable ("ip4-unicast", feature_name, - sw_if_index, 1, 0, 0); - if (rv) - return rv; - - rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1); - if (rv) - return rv; + fib_index = + fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index); - if (is_inside && !nm->out2in_dpo) + if (!is_inside) { - rv = vnet_feature_enable_disable ("ip4-local", "nat44-ei-hairpinning", - sw_if_index, 1, 0, 0); - if (rv) - return rv; - } + i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE; -set_flags: - if (is_inside) - { - i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE; - return 0; + outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index); + if (outside_fib) + { + outside_fib->refcount++; + } + else + { + vec_add2 (nm->outside_fibs, outside_fib, 1); + outside_fib->fib_index = fib_index; + outside_fib->refcount = 1; + } + + nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 1); + nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1); } else - i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE; - - /* Add/delete external addresses to FIB */ -fib: - vec_foreach (ap, nm->addresses) - nat44_ei_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, !is_del); - - pool_foreach (m, nm->static_mappings) { - if (!(nat44_ei_is_addr_only_static_mapping (m)) || - (m->local_addr.as_u32 == m->external_addr.as_u32)) - continue; - - nat44_ei_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, - !is_del); + i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE; } return 0; } -int -nat44_ei_interface_add_del_output_feature (u32 sw_if_index, u8 is_inside, - int is_del) +static_always_inline int +nat44_ei_del_interface (u32 sw_if_index, u8 is_inside) { + const char *feature_name, *del_feature_name; nat44_ei_main_t *nm = &nat44_ei_main; - nat44_ei_interface_t *i; - nat44_ei_address_t *ap; - nat44_ei_static_mapping_t *m; + nat44_ei_outside_fib_t *outside_fib; - u32 fib_index = - fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index); + nat44_ei_interface_t *i; + u32 fib_index; + int rv; fail_if_disabled (); - if (nm->static_mapping_only && !(nm->static_mapping_connection_tracking)) + if (nm->out2in_dpo && !is_inside) { nat44_ei_log_err ("error unsupported"); return VNET_API_ERROR_UNSUPPORTED; } - pool_foreach (i, nm->interfaces) + i = nat44_ei_get_interface (nm->interfaces, sw_if_index); + if (i == 0) { - if (i->sw_if_index == sw_if_index) - { - nat44_ei_log_err ("error interface already configured"); - return VNET_API_ERROR_VALUE_EXIST; - } + nat44_ei_log_err ("error interface couldn't be found"); + return VNET_API_ERROR_NO_SUCH_ENTRY; } - if (!is_inside) + if (nat44_ei_interface_is_inside (i) && nat44_ei_interface_is_outside (i)) { - vec_foreach (outside_fib, nm->outside_fibs) + if (nm->num_workers > 1) { - if (outside_fib->fib_index == fib_index) - { - if (is_del) - { - outside_fib->refcount--; - if (!outside_fib->refcount) - vec_del1 (nm->outside_fibs, - outside_fib - nm->outside_fibs); - } - else - outside_fib->refcount++; - goto feature_set; - } + del_feature_name = "nat44-ei-handoff-classify"; + feature_name = !is_inside ? "nat44-ei-in2out-worker-handoff" : + "nat44-ei-out2in-worker-handoff"; } - if (!is_del) + else { - vec_add2 (nm->outside_fibs, outside_fib, 1); - outside_fib->refcount = 1; - outside_fib->fib_index = fib_index; + del_feature_name = "nat44-ei-classify"; + feature_name = !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in"; } - } -feature_set: - if (is_inside) - { - int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del); - if (rv) - return rv; - rv = - ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del); + rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0); if (rv) - return rv; - rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-hairpin-dst", - sw_if_index, !is_del, 0, 0); + { + return rv; + } + rv = vnet_feature_enable_disable ("ip4-unicast", del_feature_name, + sw_if_index, 0, 0, 0); if (rv) - return rv; - rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-hairpin-src", - sw_if_index, !is_del, 0, 0); + { + return rv; + } + rv = vnet_feature_enable_disable ("ip4-unicast", feature_name, + sw_if_index, 1, 0, 0); if (rv) - return rv; - goto fq; + { + return rv; + } + if (is_inside) + { + i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_INSIDE; + } + else + { + rv = vnet_feature_enable_disable ( + "ip4-local", "nat44-ei-hairpinning", sw_if_index, 1, 0, 0); + if (rv) + { + return rv; + } + i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE; + } + } + else + { + if (nm->num_workers > 1) + { + feature_name = is_inside ? "nat44-ei-in2out-worker-handoff" : + "nat44-ei-out2in-worker-handoff"; + } + else + { + feature_name = is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in"; + } + + rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0); + if (rv) + { + return rv; + } + rv = vnet_feature_enable_disable ("ip4-unicast", feature_name, + sw_if_index, 0, 0, 0); + if (rv) + { + return rv; + } + if (is_inside) + { + rv = vnet_feature_enable_disable ( + "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0); + if (rv) + { + return rv; + } + } + + // remove interface + pool_put (nm->interfaces, i); + } + + if (!is_inside) + { + fib_index = + fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index); + outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index); + if (outside_fib) + { + outside_fib->refcount--; + if (!outside_fib->refcount) + { + vec_del1 (nm->outside_fibs, outside_fib - nm->outside_fibs); + } + } + + nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 0); + nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 0); + } + + return 0; +} + +int +nat44_ei_add_del_interface (u32 sw_if_index, u8 is_inside, int is_del) +{ + if (is_del) + { + return nat44_ei_del_interface (sw_if_index, is_inside); + } + else + { + return nat44_ei_add_interface (sw_if_index, is_inside); + } +} + +static_always_inline int +nat44_ei_add_output_interface (u32 sw_if_index) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + + nat44_ei_outside_fib_t *outside_fib; + nat44_ei_interface_t *i; + u32 fib_index; + int rv; + + fail_if_disabled (); + + if (nat44_ei_get_interface (nm->interfaces, sw_if_index)) + { + nat44_ei_log_err ("error interface already configured"); + return VNET_API_ERROR_VALUE_EXIST; + } + + if (nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index)) + { + nat44_ei_log_err ("error interface already configured"); + return VNET_API_ERROR_VALUE_EXIST; } if (nm->num_workers > 1) { - int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del); + rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1); if (rv) - return rv; - rv = - ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del); + { + return rv; + } + rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1); if (rv) - return rv; - rv = vnet_feature_enable_disable ("ip4-unicast", - "nat44-ei-out2in-worker-handoff", - sw_if_index, !is_del, 0, 0); + { + return rv; + } + rv = vnet_feature_enable_disable ( + "ip4-unicast", "nat44-ei-out2in-worker-handoff", sw_if_index, 1, 0, 0); if (rv) - return rv; + { + return rv; + } rv = vnet_feature_enable_disable ( - "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index, - !is_del, 0, 0); + "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index, 1, + 0, 0); if (rv) - return rv; + { + return rv; + } } else { - int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del); + rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1); if (rv) - return rv; - rv = - ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del); + { + return rv; + } + rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1); if (rv) - return rv; + { + return rv; + } rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-out2in", - sw_if_index, !is_del, 0, 0); + sw_if_index, 1, 0, 0); if (rv) - return rv; + { + return rv; + } rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-in2out-output", - sw_if_index, !is_del, 0, 0); + sw_if_index, 1, 0, 0); if (rv) - return rv; + { + return rv; + } } -fq: - if (nm->fq_in2out_output_index == ~0 && nm->num_workers > 1) - nm->fq_in2out_output_index = - vlib_frame_queue_main_init (nm->in2out_output_node_index, 0); + nat_validate_interface_counters (nm, sw_if_index); - if (nm->fq_out2in_index == ~0 && nm->num_workers > 1) - nm->fq_out2in_index = - vlib_frame_queue_main_init (nm->out2in_node_index, 0); + pool_get (nm->output_feature_interfaces, i); + i->sw_if_index = sw_if_index; + i->flags = 0; + i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE; + i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE; - pool_foreach (i, nm->output_feature_interfaces) + fib_index = + fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index); + outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index); + if (outside_fib) { - if (i->sw_if_index == sw_if_index) - { - if (is_del) - pool_put (nm->output_feature_interfaces, i); - else - return VNET_API_ERROR_VALUE_EXIST; - - goto fib; - } + outside_fib->refcount++; + } + else + { + vec_add2 (nm->outside_fibs, outside_fib, 1); + outside_fib->fib_index = fib_index; + outside_fib->refcount = 1; } - if (is_del) + nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 1); + nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1); + + return 0; +} + +static_always_inline int +nat44_ei_del_output_interface (u32 sw_if_index) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + + nat44_ei_outside_fib_t *outside_fib; + nat44_ei_interface_t *i; + u32 fib_index; + int rv; + + fail_if_disabled (); + + i = nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index); + if (!i) { nat44_ei_log_err ("error interface couldn't be found"); return VNET_API_ERROR_NO_SUCH_ENTRY; } - pool_get (nm->output_feature_interfaces, i); - i->sw_if_index = sw_if_index; - i->flags = 0; - nat_validate_interface_counters (nm, sw_if_index); - if (is_inside) - i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE; + if (nm->num_workers > 1) + { + rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0); + if (rv) + { + return rv; + } + rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 0); + if (rv) + { + return rv; + } + rv = vnet_feature_enable_disable ( + "ip4-unicast", "nat44-ei-out2in-worker-handoff", sw_if_index, 0, 0, 0); + if (rv) + { + return rv; + } + rv = vnet_feature_enable_disable ( + "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index, 0, + 0, 0); + if (rv) + { + return rv; + } + } else - i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE; - - /* Add/delete external addresses to FIB */ -fib: - if (is_inside) - return 0; + { + rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0); + if (rv) + { + return rv; + } + rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 0); + if (rv) + { + return rv; + } + rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-out2in", + sw_if_index, 0, 0, 0); + if (rv) + { + return rv; + } + rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-in2out-output", + sw_if_index, 0, 0, 0); + if (rv) + { + return rv; + } + } - vec_foreach (ap, nm->addresses) - nat44_ei_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, !is_del); + pool_put (nm->output_feature_interfaces, i); - pool_foreach (m, nm->static_mappings) + fib_index = + fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index); + outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index); + if (outside_fib) { - if (!((nat44_ei_is_addr_only_static_mapping (m))) || - (m->local_addr.as_u32 == m->external_addr.as_u32)) - continue; - - nat44_ei_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, - !is_del); + outside_fib->refcount--; + if (!outside_fib->refcount) + { + vec_del1 (nm->outside_fibs, outside_fib - nm->outside_fibs); + } } + nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 1); + nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1); + return 0; } +int +nat44_ei_add_del_output_interface (u32 sw_if_index, int is_del) +{ + if (is_del) + { + return nat44_ei_del_output_interface (sw_if_index); + } + else + { + return nat44_ei_add_output_interface (sw_if_index); + } +} + int nat44_ei_plugin_disable () { @@ -928,9 +1116,13 @@ nat44_ei_plugin_disable () pool_foreach (i, pool) { if (nat44_ei_interface_is_inside (i)) - error = nat44_ei_interface_add_del (i->sw_if_index, 1, 1); + { + error = nat44_ei_del_interface (i->sw_if_index, 1); + } if (nat44_ei_interface_is_outside (i)) - error = nat44_ei_interface_add_del (i->sw_if_index, 0, 1); + { + error = nat44_ei_del_interface (i->sw_if_index, 0); + } if (error) { @@ -944,13 +1136,7 @@ nat44_ei_plugin_disable () pool = pool_dup (nm->output_feature_interfaces); pool_foreach (i, pool) { - if (nat44_ei_interface_is_inside (i)) - error = - nat44_ei_interface_add_del_output_feature (i->sw_if_index, 1, 1); - if (nat44_ei_interface_is_outside (i)) - error = - nat44_ei_interface_add_del_output_feature (i->sw_if_index, 0, 1); - + error = nat44_ei_del_output_interface (i->sw_if_index); if (error) { nat44_ei_log_err ("error occurred while removing interface %u", @@ -1727,30 +1913,6 @@ nat44_ei_set_alloc_mape (u16 psid, u16 psid_offset, u16 psid_length) nm->psid_length = psid_length; } -static void -nat44_ei_add_static_mapping_when_resolved (ip4_address_t l_addr, u16 l_port, - u16 e_port, nat_protocol_t proto, - u32 sw_if_index, u32 vrf_id, - int addr_only, int identity_nat, - u8 *tag) -{ - nat44_ei_main_t *nm = &nat44_ei_main; - nat44_ei_static_map_resolve_t *rp; - - vec_add2 (nm->to_resolve, rp, 1); - clib_memset (rp, 0, sizeof (*rp)); - - rp->l_addr.as_u32 = l_addr.as_u32; - rp->l_port = l_port; - rp->e_port = e_port; - rp->sw_if_index = sw_if_index; - rp->vrf_id = vrf_id; - rp->proto = proto; - rp->addr_only = addr_only; - rp->identity_nat = identity_nat; - rp->tag = vec_dup (tag); -} - void nat44_ei_delete_session (nat44_ei_main_t *nm, nat44_ei_session_t *ses, u32 thread_index) @@ -1789,10 +1951,13 @@ nat44_ei_del_session (nat44_ei_main_t *nm, ip4_address_t *addr, u16 port, { nat44_ei_main_per_thread_data_t *tnm; clib_bihash_kv_8_8_t kv, value; - u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id); + u32 fib_index; nat44_ei_session_t *s; clib_bihash_8_8_t *t; + fail_if_disabled (); + + fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id); init_nat_k (&kv, *addr, port, fib_index, proto); t = is_in ? &nm->in2out : &nm->out2in; if (!clib_bihash_search_8_8 (t, &kv, &value)) @@ -1842,412 +2007,563 @@ nat44_ei_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len, u32 sw_if_index, u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index); if (is_add) - fib_table_entry_update_one_path ( - fib_index, &prefix, nm->fib_src_low, - (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL | - FIB_ENTRY_FLAG_EXCLUSIVE), - DPO_PROTO_IP4, NULL, sw_if_index, ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE); + { + fib_table_entry_update_one_path (fib_index, &prefix, nm->fib_src_low, + (FIB_ENTRY_FLAG_CONNECTED | + FIB_ENTRY_FLAG_LOCAL | + FIB_ENTRY_FLAG_EXCLUSIVE), + DPO_PROTO_IP4, NULL, sw_if_index, ~0, 1, + NULL, FIB_ROUTE_PATH_FLAG_NONE); + } else - fib_table_entry_delete (fib_index, &prefix, nm->fib_src_low); + { + fib_table_entry_delete (fib_index, &prefix, nm->fib_src_low); + } } int -nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, - u16 l_port, u16 e_port, nat_protocol_t proto, - u32 sw_if_index, u32 vrf_id, u8 addr_only, - u8 identity_nat, u8 *tag, u8 is_add) +nat44_ei_reserve_port (ip4_address_t addr, u16 port, nat_protocol_t proto) { + u32 ti = nat44_ei_get_thread_idx_by_port (port); nat44_ei_main_t *nm = &nat44_ei_main; - nat44_ei_static_mapping_t *m = 0; - clib_bihash_kv_8_8_t kv, value; nat44_ei_address_t *a = 0; - u32 fib_index = ~0; - nat44_ei_interface_t *interface; - nat44_ei_main_per_thread_data_t *tnm; - nat44_ei_user_key_t u_key; - nat44_ei_user_t *u; - dlist_elt_t *head, *elt; - u32 elt_index, head_index; - u32 ses_index; - u64 user_index; - nat44_ei_session_t *s; - nat44_ei_static_map_resolve_t *rp, *rp_match = 0; - nat44_ei_lb_addr_port_t *local; - u32 find = ~0; int i; - if (sw_if_index != ~0) + for (i = 0; i < vec_len (nm->addresses); i++) { - ip4_address_t *first_int_addr; + a = nm->addresses + i; - for (i = 0; i < vec_len (nm->to_resolve); i++) - { - rp = nm->to_resolve + i; - if (rp->sw_if_index != sw_if_index || - rp->l_addr.as_u32 != l_addr.as_u32 || rp->vrf_id != vrf_id || - rp->addr_only != addr_only) - continue; - - if (!addr_only) - { - if ((rp->l_port != l_port && rp->e_port != e_port) || - rp->proto != proto) - continue; - } - - rp_match = rp; - break; - } - - /* Might be already set... */ - first_int_addr = ip4_interface_first_address ( - nm->ip4_main, sw_if_index, 0 /* just want the address */); + if (a->addr.as_u32 != addr.as_u32) + continue; - if (is_add) + switch (proto) { - if (rp_match) - return VNET_API_ERROR_VALUE_EXIST; +#define _(N, j, n, s) \ + case NAT_PROTOCOL_##N: \ + if (a->busy_##n##_port_refcounts[port]) \ + goto done; \ + ++a->busy_##n##_port_refcounts[port]; \ + if (port > 1024) \ + { \ + a->busy_##n##_ports++; \ + a->busy_##n##_ports_per_thread[ti]++; \ + } \ + break; + foreach_nat_protocol +#undef _ + default : nat_elog_info (nm, "unknown protocol"); + goto done; + } - nat44_ei_add_static_mapping_when_resolved ( - l_addr, l_port, e_port, proto, sw_if_index, vrf_id, addr_only, - identity_nat, tag); + return 0; + } - /* DHCP resolution required? */ - if (!first_int_addr) - return 0; +done: + return 1; +} - e_addr.as_u32 = first_int_addr->as_u32; - /* Identity mapping? */ - if (l_addr.as_u32 == 0) - l_addr.as_u32 = e_addr.as_u32; - } - else - { - if (!rp_match) - return VNET_API_ERROR_NO_SUCH_ENTRY; +int +nat44_ei_free_port (ip4_address_t addr, u16 port, nat_protocol_t proto) +{ + u32 ti = nat44_ei_get_thread_idx_by_port (port); + nat44_ei_main_t *nm = &nat44_ei_main; + nat44_ei_address_t *a = 0; + int i; - vec_del1 (nm->to_resolve, i); + for (i = 0; i < vec_len (nm->addresses); i++) + { + a = nm->addresses + i; - if (!first_int_addr) - return 0; + if (a->addr.as_u32 != addr.as_u32) + continue; - e_addr.as_u32 = first_int_addr->as_u32; - /* Identity mapping? */ - if (l_addr.as_u32 == 0) - l_addr.as_u32 = e_addr.as_u32; + switch (proto) + { +#define _(N, j, n, s) \ + case NAT_PROTOCOL_##N: \ + --a->busy_##n##_port_refcounts[port]; \ + if (port > 1024) \ + { \ + a->busy_##n##_ports--; \ + a->busy_##n##_ports_per_thread[ti]--; \ + } \ + break; + foreach_nat_protocol +#undef _ + default : nat_elog_info (nm, "unknown protocol"); + goto done; } + + return 0; } - init_nat_k (&kv, e_addr, addr_only ? 0 : e_port, 0, addr_only ? 0 : proto); - if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value)) - m = pool_elt_at_index (nm->static_mappings, value.value); +done: + return 1; +} - if (is_add) - { - if (m) - { - // identity mapping for second vrf - if (nat44_ei_is_identity_static_mapping (m)) - { - pool_foreach (local, m->locals) - { - if (local->vrf_id == vrf_id) - return VNET_API_ERROR_VALUE_EXIST; - } - pool_get (m->locals, local); - local->vrf_id = vrf_id; - local->fib_index = fib_table_find_or_create_and_lock ( - FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low); - init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index, - m->proto, 0, m - nm->static_mappings); - clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 1); - return 0; - } - return VNET_API_ERROR_VALUE_EXIST; - } +void +nat44_ei_add_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, + nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, + u32 flags, ip4_address_t pool_addr, u8 *tag) +{ + nat44_ei_static_map_resolve_t *rp; + nat44_ei_main_t *nm = &nat44_ei_main; - /* Convert VRF id to FIB index */ - if (vrf_id != ~0) - { - fib_index = fib_table_find_or_create_and_lock ( - FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low); - } - /* If not specified use inside VRF id from NAT44 plugin config */ - else - { - fib_index = nm->inside_fib_index; - vrf_id = nm->inside_vrf_id; - fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low); - } + vec_add2 (nm->to_resolve, rp, 1); + rp->l_addr.as_u32 = l_addr.as_u32; + rp->l_port = l_port; + rp->e_port = e_port; + rp->sw_if_index = sw_if_index; + rp->vrf_id = vrf_id; + rp->proto = proto; + rp->flags = flags; + rp->pool_addr = pool_addr; + rp->tag = vec_dup (tag); +} - if (!identity_nat) - { - init_nat_k (&kv, l_addr, addr_only ? 0 : l_port, fib_index, - addr_only ? 0 : proto); - if (!clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv, - &value)) - return VNET_API_ERROR_VALUE_EXIST; - } +int +nat44_ei_get_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, + nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, + u32 flags, int *out) +{ + nat44_ei_static_map_resolve_t *rp; + nat44_ei_main_t *nm = &nat44_ei_main; + int i; + + for (i = 0; i < vec_len (nm->to_resolve); i++) + { + rp = nm->to_resolve + i; - /* Find external address in allocated addresses and reserve port for - address and port pair mapping when dynamic translations enabled */ - if (!(addr_only || nm->static_mapping_only)) + if (rp->sw_if_index == sw_if_index && rp->vrf_id == vrf_id) { - for (i = 0; i < vec_len (nm->addresses); i++) + if (is_sm_identity_nat (rp->flags) && is_sm_identity_nat (flags)) { - if (nm->addresses[i].addr.as_u32 == e_addr.as_u32) + if (!(is_sm_addr_only (rp->flags) && is_sm_addr_only (flags))) { - a = nm->addresses + i; - /* External port must be unused */ - switch (proto) + if (rp->e_port != e_port || rp->proto != proto) { -#define _(N, j, n, s) \ - case NAT_PROTOCOL_##N: \ - if (a->busy_##n##_port_refcounts[e_port]) \ - return VNET_API_ERROR_INVALID_VALUE; \ - ++a->busy_##n##_port_refcounts[e_port]; \ - if (e_port > 1024) \ - { \ - a->busy_##n##_ports++; \ - a->busy_##n##_ports_per_thread[nat44_ei_get_thread_idx_by_port ( \ - e_port)]++; \ - } \ - break; - foreach_nat_protocol -#undef _ - default : nat_elog_info (nm, "unknown protocol"); - return VNET_API_ERROR_INVALID_VALUE_2; + continue; } - break; } } - /* External address must be allocated */ - if (!a && (l_addr.as_u32 != e_addr.as_u32)) + else if (rp->l_addr.as_u32 == l_addr.as_u32) { - if (sw_if_index != ~0) + if (!(is_sm_addr_only (rp->flags) && is_sm_addr_only (flags))) { - for (i = 0; i < vec_len (nm->to_resolve); i++) + if (rp->l_port != l_port || rp->e_port != e_port || + rp->proto != proto) { - rp = nm->to_resolve + i; - if (rp->addr_only) - continue; - if (rp->sw_if_index != sw_if_index && - rp->l_addr.as_u32 != l_addr.as_u32 && - rp->vrf_id != vrf_id && rp->l_port != l_port && - rp->e_port != e_port && rp->proto != proto) - continue; - - vec_del1 (nm->to_resolve, i); - break; + continue; } } - return VNET_API_ERROR_NO_SUCH_ENTRY; } + else + { + continue; + } + if (out) + { + *out = i; + } + return 0; } + } + return 1; +} - pool_get (nm->static_mappings, m); - clib_memset (m, 0, sizeof (*m)); - m->tag = vec_dup (tag); - m->local_addr = l_addr; - m->external_addr = e_addr; +int +nat44_ei_del_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, + nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, + u32 flags) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + int i; + if (!nat44_ei_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags, &i)) + { + vec_del1 (nm->to_resolve, i); + return 0; + } + return 1; +} - if (addr_only) - m->flags |= NAT44_EI_STATIC_MAPPING_FLAG_ADDR_ONLY; - else +void +delete_matching_dynamic_sessions (const nat44_ei_static_mapping_t *m, + u32 worker_index) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + clib_bihash_kv_8_8_t kv, value; + nat44_ei_session_t *s; + nat44_ei_user_key_t u_key; + nat44_ei_user_t *u; + nat44_ei_main_per_thread_data_t *tnm; + dlist_elt_t *head, *elt; + u32 elt_index, head_index; + u32 ses_index; + u64 user_index; + + if (nm->static_mapping_only) + return; + + tnm = vec_elt_at_index (nm->per_thread_data, worker_index); + + u_key.addr = m->local_addr; + u_key.fib_index = m->fib_index; + kv.key = u_key.as_u64; + if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value)) + { + user_index = value.value; + u = pool_elt_at_index (tnm->users, user_index); + if (u->nsessions) { - m->local_port = l_port; - m->external_port = e_port; - m->proto = proto; + head_index = u->sessions_per_user_list_head_index; + head = pool_elt_at_index (tnm->list_pool, head_index); + elt_index = head->next; + elt = pool_elt_at_index (tnm->list_pool, elt_index); + ses_index = elt->value; + while (ses_index != ~0) + { + s = pool_elt_at_index (tnm->sessions, ses_index); + elt = pool_elt_at_index (tnm->list_pool, elt->next); + ses_index = elt->value; + + if (nat44_ei_is_session_static (s)) + continue; + + if (!is_sm_addr_only (m->flags) && + s->in2out.port != m->local_port) + continue; + + nat44_ei_free_session_data_v2 (nm, s, tnm - nm->per_thread_data, + 0); + nat44_ei_delete_session (nm, s, tnm - nm->per_thread_data); + + if (!is_sm_addr_only (m->flags)) + break; + } } + } +} - if (identity_nat) +int +nat44_ei_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, + u16 l_port, u16 e_port, nat_protocol_t proto, + u32 vrf_id, u32 sw_if_index, u32 flags, + ip4_address_t pool_addr, u8 *tag) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + clib_bihash_kv_8_8_t kv, value; + nat44_ei_lb_addr_port_t *local; + nat44_ei_static_mapping_t *m; + u32 fib_index = ~0; + u32 worker_index; + + fail_if_disabled (); + + if (is_sm_addr_only (flags)) + { + e_port = l_port = proto = 0; + } + + if (sw_if_index != ~0) + { + // this mapping is interface bound + ip4_address_t *first_int_addr; + + // check if this record isn't registered for resolve + if (!nat44_ei_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags, 0)) { - m->flags |= NAT44_EI_STATIC_MAPPING_FLAG_IDENTITY_NAT; - pool_get (m->locals, local); - local->vrf_id = vrf_id; - local->fib_index = fib_index; + return VNET_API_ERROR_VALUE_EXIST; } - else + // register record for resolve + nat44_ei_add_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags, pool_addr, tag); + + first_int_addr = + ip4_interface_first_address (nm->ip4_main, sw_if_index, 0); + if (!first_int_addr) { - m->vrf_id = vrf_id; - m->fib_index = fib_index; + // dhcp resolution required + return 0; } - if (nm->num_workers > 1) + e_addr.as_u32 = first_int_addr->as_u32; + } + + if (is_sm_identity_nat (flags)) + { + l_port = e_port; + l_addr.as_u32 = e_addr.as_u32; + } + + // fib index 0 + init_nat_k (&kv, e_addr, e_port, 0, proto); + + if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value)) + { + m = pool_elt_at_index (nm->static_mappings, value.value); + if (!is_sm_identity_nat (m->flags)) { - ip4_header_t ip = { - .src_address = m->local_addr, - }; - vec_add1 (m->workers, - nat44_ei_get_in2out_worker_index (&ip, m->fib_index, 0)); - tnm = vec_elt_at_index (nm->per_thread_data, m->workers[0]); + return VNET_API_ERROR_VALUE_EXIST; } - else - tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers); - init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, 0, - m - nm->static_mappings); + // case: + // adding local identity nat record for different vrf table + pool_foreach (local, m->locals) + { + if (local->vrf_id == vrf_id) + { + return VNET_API_ERROR_VALUE_EXIST; + } + } + + pool_get (m->locals, local); + + local->vrf_id = vrf_id; + local->fib_index = fib_table_find_or_create_and_lock ( + FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low); + + init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index, + m->proto, 0, m - nm->static_mappings); clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 1); - init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0, - m - nm->static_mappings); - clib_bihash_add_del_8_8 (&nm->static_mapping_by_external, &kv, 1); + return 0; + } - /* Delete dynamic sessions matching local address (+ local port) */ - // TODO: based on type of NAT EI/ED - if (!(nm->static_mapping_only)) + if (vrf_id != ~0) + { + fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id, + nm->fib_src_low); + } + else + { + // fallback to default vrf + vrf_id = nm->inside_vrf_id; + fib_index = nm->inside_fib_index; + fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low); + } + + if (!is_sm_identity_nat (flags)) + { + init_nat_k (&kv, l_addr, l_port, fib_index, proto); + if (!clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv, &value)) { - u_key.addr = m->local_addr; - u_key.fib_index = m->fib_index; - kv.key = u_key.as_u64; - if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value)) + return VNET_API_ERROR_VALUE_EXIST; + } + } + + if (!(is_sm_addr_only (flags) || nm->static_mapping_only)) + { + if (nat44_ei_reserve_port (e_addr, e_port, proto)) + { + // remove resolve record + if ((sw_if_index != ~0) && !is_sm_identity_nat (flags)) { - user_index = value.value; - u = pool_elt_at_index (tnm->users, user_index); - if (u->nsessions) - { - head_index = u->sessions_per_user_list_head_index; - head = pool_elt_at_index (tnm->list_pool, head_index); - elt_index = head->next; - elt = pool_elt_at_index (tnm->list_pool, elt_index); - ses_index = elt->value; - while (ses_index != ~0) - { - s = pool_elt_at_index (tnm->sessions, ses_index); - elt = pool_elt_at_index (tnm->list_pool, elt->next); - ses_index = elt->value; + nat44_ei_del_resolve_record (l_addr, l_port, e_port, proto, + vrf_id, sw_if_index, flags); + } + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + } + + pool_get (nm->static_mappings, m); + clib_memset (m, 0, sizeof (*m)); + + m->flags = flags; + m->local_addr = l_addr; + m->external_addr = e_addr; + + m->tag = vec_dup (tag); + + if (!is_sm_addr_only (flags)) + { + m->local_port = l_port; + m->external_port = e_port; + m->proto = proto; + } + + if (is_sm_identity_nat (flags)) + { + pool_get (m->locals, local); + + local->vrf_id = vrf_id; + local->fib_index = fib_index; + } + else + { + m->vrf_id = vrf_id; + m->fib_index = fib_index; + } + + init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, 0, + m - nm->static_mappings); + clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 1); + + init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0, + m - nm->static_mappings); + clib_bihash_add_del_8_8 (&nm->static_mapping_by_external, &kv, 1); + + if (nm->num_workers > 1) + { + // store worker index for this record + ip4_header_t ip = { + .src_address = m->local_addr, + }; + worker_index = nat44_ei_get_in2out_worker_index (&ip, m->fib_index, 0); + vec_add1 (m->workers, worker_index); + } + else + { + worker_index = nm->num_workers; + } + delete_matching_dynamic_sessions (m, worker_index); + + if (is_sm_addr_only (flags)) + { + nat44_ei_add_del_addr_to_fib_foreach_out_if (&e_addr, 1); + } + + return 0; +} + +int +nat44_ei_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, + u16 l_port, u16 e_port, nat_protocol_t proto, + u32 vrf_id, u32 sw_if_index, u32 flags) +{ + nat44_ei_main_per_thread_data_t *tnm; + nat44_ei_main_t *nm = &nat44_ei_main; + clib_bihash_kv_8_8_t kv, value; + nat44_ei_lb_addr_port_t *local; + nat44_ei_static_mapping_t *m; + u32 fib_index = ~0; + nat44_ei_user_key_t u_key; + + fail_if_disabled (); + + if (is_sm_addr_only (flags)) + { + e_port = l_port = proto = 0; + } + + if (sw_if_index != ~0) + { + // this mapping is interface bound + ip4_address_t *first_int_addr; + + // delete record registered for resolve + if (nat44_ei_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags)) + { + return VNET_API_ERROR_NO_SUCH_ENTRY; + } - if (nat44_ei_is_session_static (s)) - continue; + first_int_addr = + ip4_interface_first_address (nm->ip4_main, sw_if_index, 0); + if (!first_int_addr) + { + // dhcp resolution required + return 0; + } - if (!addr_only && s->in2out.port != m->local_port) - continue; + e_addr.as_u32 = first_int_addr->as_u32; + } - nat44_ei_free_session_data_v2 ( - nm, s, tnm - nm->per_thread_data, 0); - nat44_ei_delete_session (nm, s, - tnm - nm->per_thread_data); + if (is_sm_identity_nat (flags)) + { + l_port = e_port; + l_addr.as_u32 = e_addr.as_u32; + } - if (!addr_only) - break; - } - } - } + // fib index 0 + init_nat_k (&kv, e_addr, e_port, 0, proto); + + if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value)) + { + if (sw_if_index != ~0) + { + return 0; } + return VNET_API_ERROR_NO_SUCH_ENTRY; } - else + + m = pool_elt_at_index (nm->static_mappings, value.value); + + if (is_sm_identity_nat (flags)) { - if (!m) + u8 found = 0; + + if (vrf_id == ~0) { - if (sw_if_index != ~0) - return 0; - else - return VNET_API_ERROR_NO_SUCH_ENTRY; + vrf_id = nm->inside_vrf_id; } - if (identity_nat) + pool_foreach (local, m->locals) { - if (vrf_id == ~0) - vrf_id = nm->inside_vrf_id; - - pool_foreach (local, m->locals) + if (local->vrf_id == vrf_id) { - if (local->vrf_id == vrf_id) - find = local - m->locals; + local = pool_elt_at_index (m->locals, local - m->locals); + fib_index = local->fib_index; + pool_put (m->locals, local); + found = 1; } - if (find == ~0) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - local = pool_elt_at_index (m->locals, find); - fib_index = local->fib_index; - pool_put (m->locals, local); } - else - fib_index = m->fib_index; + if (!found) + { + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + } + else + { + fib_index = m->fib_index; + } - /* Free external address port */ - if (!(addr_only || nm->static_mapping_only)) + if (!(is_sm_addr_only (flags) || nm->static_mapping_only)) + { + if (nat44_ei_free_port (e_addr, e_port, proto)) { - for (i = 0; i < vec_len (nm->addresses); i++) - { - if (nm->addresses[i].addr.as_u32 == e_addr.as_u32) - { - a = nm->addresses + i; - switch (proto) - { -#define _(N, j, n, s) \ - case NAT_PROTOCOL_##N: \ - --a->busy_##n##_port_refcounts[e_port]; \ - if (e_port > 1024) \ - { \ - a->busy_##n##_ports--; \ - a->busy_##n##_ports_per_thread[nat44_ei_get_thread_idx_by_port ( \ - e_port)]--; \ - } \ - break; - foreach_nat_protocol -#undef _ - default : return VNET_API_ERROR_INVALID_VALUE_2; - } - break; - } - } + return VNET_API_ERROR_INVALID_VALUE; } + } + init_nat_k (&kv, l_addr, l_port, fib_index, proto); + clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 0); + + if (!nm->static_mapping_only || nm->static_mapping_connection_tracking) + { + // delete sessions for static mapping if (nm->num_workers > 1) tnm = vec_elt_at_index (nm->per_thread_data, m->workers[0]); else tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers); - init_nat_k (&kv, m->local_addr, m->local_port, fib_index, m->proto); - clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 0); - - /* Delete session(s) for static mapping if exist */ - if (!(nm->static_mapping_only) || - (nm->static_mapping_only && nm->static_mapping_connection_tracking)) - { - u_key.addr = m->local_addr; - u_key.fib_index = fib_index; - kv.key = u_key.as_u64; - nat44_ei_static_mapping_del_sessions (nm, tnm, u_key, addr_only, - e_addr, e_port); - } + u_key.addr = m->local_addr; + u_key.fib_index = fib_index; + kv.key = u_key.as_u64; + nat44_ei_static_mapping_del_sessions ( + nm, tnm, u_key, is_sm_addr_only (flags), e_addr, e_port); + } - fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low); - if (pool_elts (m->locals)) - return 0; + fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low); - init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto); + if (!pool_elts (m->locals)) + { + // this is last record remove all required stuff + // fib_index 0 + init_nat_k (&kv, e_addr, e_port, 0, proto); clib_bihash_add_del_8_8 (&nm->static_mapping_by_external, &kv, 0); vec_free (m->tag); vec_free (m->workers); - /* Delete static mapping from pool */ pool_put (nm->static_mappings, m); - } - - if (!addr_only || (l_addr.as_u32 == e_addr.as_u32)) - return 0; - /* Add/delete external address to FIB */ - pool_foreach (interface, nm->interfaces) - { - if (nat44_ei_interface_is_inside (interface) || nm->out2in_dpo) - continue; - - nat44_ei_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, - is_add); - break; + if (is_sm_addr_only (flags) && !is_sm_identity_nat (flags)) + { + nat44_ei_add_del_addr_to_fib_foreach_out_if (&e_addr, 0); + } } - pool_foreach (interface, nm->output_feature_interfaces) - { - if (nat44_ei_interface_is_inside (interface) || nm->out2in_dpo) - continue; - nat44_ei_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, - is_add); - break; - } return 0; } @@ -2302,16 +2618,16 @@ nat44_ei_static_mapping_match (ip4_address_t match_addr, u16 match_port, } /* Address only mapping doesn't change port */ - if (nat44_ei_is_addr_only_static_mapping (m)) + if (is_sm_addr_only (m->flags)) *mapping_port = match_port; else *mapping_port = port; if (PREDICT_FALSE (is_addr_only != 0)) - *is_addr_only = nat44_ei_is_addr_only_static_mapping (m); + *is_addr_only = is_sm_addr_only (m->flags); if (PREDICT_FALSE (is_identity_nat != 0)) - *is_identity_nat = nat44_ei_is_identity_static_mapping (m); + *is_identity_nat = is_sm_identity_nat (m->flags); return 0; } @@ -2574,11 +2890,13 @@ nat44_ei_update_outside_fib (ip4_main_t *im, uword opaque, u32 sw_if_index, } int -nat44_ei_add_address (nat44_ei_main_t *nm, ip4_address_t *addr, u32 vrf_id) +nat44_ei_add_address (ip4_address_t *addr, u32 vrf_id) { - nat44_ei_address_t *ap; - nat44_ei_interface_t *i; + nat44_ei_main_t *nm = &nat44_ei_main; vlib_thread_main_t *tm = vlib_get_thread_main (); + nat44_ei_address_t *ap; + + fail_if_disabled (); /* Check if address already exists */ vec_foreach (ap, nm->addresses) @@ -2592,12 +2910,14 @@ nat44_ei_add_address (nat44_ei_main_t *nm, ip4_address_t *addr, u32 vrf_id) vec_add2 (nm->addresses, ap, 1); + ap->fib_index = ~0; ap->addr = *addr; + if (vrf_id != ~0) - ap->fib_index = fib_table_find_or_create_and_lock ( - FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low); - else - ap->fib_index = ~0; + { + ap->fib_index = fib_table_find_or_create_and_lock ( + FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low); + } #define _(N, i, n, s) \ clib_memset (ap->busy_##n##_port_refcounts, 0, \ @@ -2609,120 +2929,30 @@ nat44_ei_add_address (nat44_ei_main_t *nm, ip4_address_t *addr, u32 vrf_id) foreach_nat_protocol #undef _ - /* Add external address to FIB */ - pool_foreach (i, nm->interfaces) - { - if (nat44_ei_interface_is_inside (i) || nm->out2in_dpo) - continue; - - nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1); - break; - } - pool_foreach (i, nm->output_feature_interfaces) - { - if (nat44_ei_interface_is_inside (i) || nm->out2in_dpo) - continue; - - nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1); - break; - } + nat44_ei_add_del_addr_to_fib_foreach_out_if (addr, 1); return 0; } int -nat44_ei_add_interface_address (nat44_ei_main_t *nm, u32 sw_if_index, - int is_del) -{ - ip4_main_t *ip4_main = nm->ip4_main; - ip4_address_t *first_int_addr; - nat44_ei_static_map_resolve_t *rp; - u32 *indices_to_delete = 0; - int i, j; - u32 *auto_add_sw_if_indices = nm->auto_add_sw_if_indices; - - first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, - 0 /* just want the address */); - - for (i = 0; i < vec_len (auto_add_sw_if_indices); i++) - { - if (auto_add_sw_if_indices[i] == sw_if_index) - { - if (is_del) - { - /* if have address remove it */ - if (first_int_addr) - (void) nat44_ei_del_address (nm, first_int_addr[0], 1); - else - { - for (j = 0; j < vec_len (nm->to_resolve); j++) - { - rp = nm->to_resolve + j; - if (rp->sw_if_index == sw_if_index) - vec_add1 (indices_to_delete, j); - } - if (vec_len (indices_to_delete)) - { - for (j = vec_len (indices_to_delete) - 1; j >= 0; j--) - vec_del1 (nm->to_resolve, j); - vec_free (indices_to_delete); - } - } - vec_del1 (nm->auto_add_sw_if_indices, i); - } - else - return VNET_API_ERROR_VALUE_EXIST; - - return 0; - } - } - - if (is_del) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - /* add to the auto-address list */ - vec_add1 (nm->auto_add_sw_if_indices, sw_if_index); - - /* If the address is already bound - or static - add it now */ - if (first_int_addr) - (void) nat44_ei_add_address (nm, first_int_addr, ~0); - - return 0; -} - -static int -nat44_ei_is_address_used_in_static_mapping (ip4_address_t addr) +nat44_ei_del_address (ip4_address_t addr, u8 delete_sm) { nat44_ei_main_t *nm = &nat44_ei_main; - nat44_ei_static_mapping_t *m; - pool_foreach (m, nm->static_mappings) - { - if (nat44_ei_is_addr_only_static_mapping (m) || - nat44_ei_is_identity_static_mapping (m)) - continue; - if (m->external_addr.as_u32 == addr.as_u32) - return 1; - } - return 0; -} - -int -nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, u8 delete_sm) -{ nat44_ei_address_t *a = 0; nat44_ei_session_t *ses; u32 *ses_to_be_removed = 0, *ses_index; nat44_ei_main_per_thread_data_t *tnm; - nat44_ei_interface_t *interface; nat44_ei_static_mapping_t *m; - int i; + int j; + + fail_if_disabled (); /* Find SNAT address */ - for (i = 0; i < vec_len (nm->addresses); i++) + for (j = 0; j < vec_len (nm->addresses); j++) { - if (nm->addresses[i].addr.as_u32 == addr.as_u32) + if (nm->addresses[j].addr.as_u32 == addr.as_u32) { - a = nm->addresses + i; + a = nm->addresses + j; break; } } @@ -2737,11 +2967,9 @@ nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, u8 delete_sm) pool_foreach (m, nm->static_mappings) { if (m->external_addr.as_u32 == addr.as_u32) - (void) nat44_ei_add_del_static_mapping ( - m->local_addr, m->external_addr, m->local_port, m->external_port, - m->proto, ~0 /* sw_if_index */, m->vrf_id, - nat44_ei_is_addr_only_static_mapping (m), - nat44_ei_is_identity_static_mapping (m), m->tag, 0); + nat44_ei_del_static_mapping (m->local_addr, m->external_addr, + m->local_port, m->external_port, + m->proto, m->vrf_id, ~0, m->flags); } } else @@ -2755,7 +2983,9 @@ nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, u8 delete_sm) } if (a->fib_index != ~0) - fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low); + { + fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low); + } /* Delete sessions using address */ if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports) @@ -2783,25 +3013,107 @@ nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, u8 delete_sm) #define _(N, i, n, s) vec_free (a->busy_##n##_ports_per_thread); foreach_nat_protocol #undef _ - vec_del1 (nm->addresses, i); - /* Delete external address from FIB */ - pool_foreach (interface, nm->interfaces) + vec_del1 (nm->addresses, j); + + nat44_ei_add_del_addr_to_fib_foreach_out_if (&addr, 0); + + return 0; +} + +int +nat44_ei_add_interface_address (u32 sw_if_index) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + ip4_main_t *ip4_main = nm->ip4_main; + ip4_address_t *first_int_addr; + u32 *auto_add_sw_if_indices = nm->auto_add_sw_if_indices; + int i; + + for (i = 0; i < vec_len (auto_add_sw_if_indices); i++) { - if (nat44_ei_interface_is_inside (interface) || nm->out2in_dpo) - continue; - nat44_ei_add_del_addr_to_fib (&addr, 32, interface->sw_if_index, 0); - break; + if (auto_add_sw_if_indices[i] == sw_if_index) + { + return VNET_API_ERROR_VALUE_EXIST; + } + } + + /* add to the auto-address list */ + vec_add1 (nm->auto_add_sw_if_indices, sw_if_index); + + // if the address is already bound - or static - add it now + first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0); + if (first_int_addr) + { + (void) nat44_ei_add_address (first_int_addr, ~0); } - pool_foreach (interface, nm->output_feature_interfaces) + return 0; +} + +int +nat44_ei_del_interface_address (u32 sw_if_index) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + ip4_main_t *ip4_main = nm->ip4_main; + ip4_address_t *first_int_addr; + nat44_ei_static_map_resolve_t *rp; + u32 *indices_to_delete = 0; + int i, j; + u32 *auto_add_sw_if_indices = nm->auto_add_sw_if_indices; + + fail_if_disabled (); + + first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0); + + for (i = 0; i < vec_len (auto_add_sw_if_indices); i++) { - if (nat44_ei_interface_is_inside (interface) || nm->out2in_dpo) - continue; - nat44_ei_add_del_addr_to_fib (&addr, 32, interface->sw_if_index, 0); - break; + if (auto_add_sw_if_indices[i] == sw_if_index) + { + first_int_addr = + ip4_interface_first_address (ip4_main, sw_if_index, 0); + if (first_int_addr) + { + (void) nat44_ei_del_address (first_int_addr[0], 1); + } + else + { + for (j = 0; j < vec_len (nm->to_resolve); j++) + { + rp = nm->to_resolve + j; + if (rp->sw_if_index == sw_if_index) + { + vec_add1 (indices_to_delete, j); + } + } + if (vec_len (indices_to_delete)) + { + for (j = vec_len (indices_to_delete) - 1; j >= 0; j--) + { + vec_del1 (nm->to_resolve, j); + } + vec_free (indices_to_delete); + } + } + + vec_del1 (nm->auto_add_sw_if_indices, i); + return 0; + } } + return VNET_API_ERROR_NO_SUCH_ENTRY; +} +static_always_inline int +is_sw_if_index_reg_for_auto_resolve (u32 *sw_if_indices, u32 sw_if_index) +{ + u32 *i; + vec_foreach (i, sw_if_indices) + { + if (*i == sw_if_index) + { + return 1; + } + } return 0; } @@ -2814,61 +3126,59 @@ nat44_ei_ip4_add_del_interface_address_cb (ip4_main_t *im, uword opaque, { nat44_ei_main_t *nm = &nat44_ei_main; nat44_ei_static_map_resolve_t *rp; - ip4_address_t l_addr; - int i, j; - int rv; nat44_ei_address_t *addresses = nm->addresses; + int rv, i; if (!nm->enabled) - return; - - for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++) { - if (sw_if_index == nm->auto_add_sw_if_indices[i]) - goto match; + return; } - return; + if (!is_sw_if_index_reg_for_auto_resolve (nm->auto_add_sw_if_indices, + sw_if_index)) + { + return; + } -match: if (!is_delete) { /* Don't trip over lease renewal, static config */ - for (j = 0; j < vec_len (addresses); j++) - if (addresses[j].addr.as_u32 == address->as_u32) - return; + for (i = 0; i < vec_len (addresses); i++) + { + if (addresses[i].addr.as_u32 == address->as_u32) + { + return; + } + } + + (void) nat44_ei_add_address (address, ~0); - (void) nat44_ei_add_address (nm, address, ~0); /* Scan static map resolution vector */ - for (j = 0; j < vec_len (nm->to_resolve); j++) + for (i = 0; i < vec_len (nm->to_resolve); i++) { - rp = nm->to_resolve + j; - if (rp->addr_only) - continue; + rp = nm->to_resolve + i; + if (is_sm_addr_only (rp->flags)) + { + continue; + } /* On this interface? */ if (rp->sw_if_index == sw_if_index) { - /* Indetity mapping? */ - if (rp->l_addr.as_u32 == 0) - l_addr.as_u32 = address[0].as_u32; - else - l_addr.as_u32 = rp->l_addr.as_u32; - /* Add the static mapping */ - rv = nat44_ei_add_del_static_mapping ( - l_addr, address[0], rp->l_port, rp->e_port, rp->proto, - ~0 /* sw_if_index */, rp->vrf_id, rp->addr_only, - rp->identity_nat, rp->tag, 1); + rv = nat44_ei_add_static_mapping ( + rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, + rp->vrf_id, ~0, rp->flags, rp->pool_addr, rp->tag); if (rv) - nat_elog_notice_X1 ( - nm, "nat44_ei_add_del_static_mapping returned %d", "i4", rv); + { + nat_elog_notice_X1 (nm, "add_static_mapping returned %d", + "i4", rv); + } } } - return; } else { - (void) nat44_ei_del_address (nm, address[0], 1); - return; + // remove all static mapping records + (void) nat44_ei_del_address (address[0], 1); } } @@ -2891,57 +3201,63 @@ nat44_ei_ip4_add_del_addr_only_sm_cb (ip4_main_t *im, uword opaque, nat44_ei_static_map_resolve_t *rp; nat44_ei_static_mapping_t *m; clib_bihash_kv_8_8_t kv, value; - int i, rv; - ip4_address_t l_addr; + int i, rv = 0, match = 0; if (!nm->enabled) - return; + { + return; + } for (i = 0; i < vec_len (nm->to_resolve); i++) { rp = nm->to_resolve + i; - if (rp->addr_only == 0) - continue; - if (rp->sw_if_index == sw_if_index) - goto match; + + if (is_sm_addr_only (rp->flags) && rp->sw_if_index == sw_if_index) + { + match = 1; + break; + } } - return; + if (!match) + { + return; + } -match: - init_nat_k (&kv, *address, rp->addr_only ? 0 : rp->e_port, - nm->outside_fib_index, rp->addr_only ? 0 : rp->proto); + init_nat_k (&kv, *address, is_sm_addr_only (rp->flags) ? 0 : rp->e_port, + nm->outside_fib_index, + is_sm_addr_only (rp->flags) ? 0 : rp->proto); if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value)) m = 0; else m = pool_elt_at_index (nm->static_mappings, value.value); - if (!is_delete) + if (is_delete) { - /* Don't trip over lease renewal, static config */ - if (m) + if (!m) return; + rv = nat44_ei_del_static_mapping (rp->l_addr, address[0], rp->l_port, + rp->e_port, rp->proto, rp->vrf_id, ~0, + rp->flags); + if (rv) + { + nat_elog_notice_X1 (nm, "nat44_ei_del_static_mapping returned %d", + "i4", rv); + } } else { - if (!m) + if (m) return; + rv = nat44_ei_add_static_mapping (rp->l_addr, address[0], rp->l_port, + rp->e_port, rp->proto, rp->vrf_id, ~0, + rp->flags, rp->pool_addr, rp->tag); + if (rv) + { + nat_elog_notice_X1 (nm, "nat44_ei_add_static_mapping returned %d", + "i4", rv); + } } - - /* Indetity mapping? */ - if (rp->l_addr.as_u32 == 0) - l_addr.as_u32 = address[0].as_u32; - else - l_addr.as_u32 = rp->l_addr.as_u32; - /* Add the static mapping */ - - rv = nat44_ei_add_del_static_mapping ( - l_addr, address[0], rp->l_port, rp->e_port, rp->proto, - ~0 /* sw_if_index */, rp->vrf_id, rp->addr_only, rp->identity_nat, rp->tag, - !is_delete); - if (rv) - nat_elog_notice_X1 (nm, "nat44_ei_add_del_static_mapping returned %d", - "i4", rv); } static_always_inline uword -- cgit 1.2.3-korg