diff options
author | Filip Varga <fivarga@cisco.com> | 2021-09-30 13:35:59 +0200 |
---|---|---|
committer | Ole Tr�an <otroan@employees.org> | 2021-10-20 10:47:27 +0000 |
commit | 1953da661069c967f1159162dc65c9a1210fcdbd (patch) | |
tree | 3528b0868b5e585f7a511f87f1deb88674948a5a | |
parent | 27775f0b903f4ea088514153e27354d5094cbf0c (diff) |
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 <fivarga@cisco.com>
Change-Id: Ie197faa576cb49acb3d218f14e00cb7d13ad9342
-rw-r--r-- | src/plugins/nat/nat44-ei/nat44_ei.api | 39 | ||||
-rw-r--r-- | src/plugins/nat/nat44-ei/nat44_ei.c | 2004 | ||||
-rw-r--r-- | src/plugins/nat/nat44-ei/nat44_ei.h | 107 | ||||
-rw-r--r-- | src/plugins/nat/nat44-ei/nat44_ei_api.c | 278 | ||||
-rw-r--r-- | src/plugins/nat/nat44-ei/nat44_ei_cli.c | 171 | ||||
-rw-r--r-- | src/plugins/nat/nat44-ei/nat44_ei_handoff.c | 2 | ||||
-rw-r--r-- | test/test_nat44_ei.py | 17 |
7 files changed, 1575 insertions, 1043 deletions
diff --git a/src/plugins/nat/nat44-ei/nat44_ei.api b/src/plugins/nat/nat44-ei/nat44_ei.api index 9ea1a3a1dde..e535906321a 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei.api +++ b/src/plugins/nat/nat44-ei/nat44_ei.api @@ -550,6 +550,45 @@ define nat44_ei_interface_output_feature_details { vl_api_interface_index_t sw_if_index; }; +/** \brief add/del NAT output interface (postrouting + in2out translation) + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - true if add, false if delete + @param sw_if_index - software index of the interface +*/ +autoendian autoreply define nat44_ei_add_del_output_interface { + u32 client_index; + u32 context; + bool is_add; + vl_api_interface_index_t sw_if_index; +}; + +service { + rpc nat44_ei_output_interface_get returns nat44_ei_output_interface_get_reply + stream nat44_ei_output_interface_details; +}; + +define nat44_ei_output_interface_get +{ + u32 client_index; + u32 context; + u32 cursor; +}; + +define nat44_ei_output_interface_get_reply +{ + u32 context; + i32 retval; + u32 cursor; +}; + +define nat44_ei_output_interface_details +{ + u32 context; + vl_api_interface_index_t sw_if_index; +}; + /** \brief Add/delete NAT44 static mapping @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request 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,408 +629,479 @@ 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; + } + + 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)) { - nat44_ei_log_err ("error interface already configured"); - return VNET_API_ERROR_VALUE_EXIST; + 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"; + } + else + { + del_feature_name = + !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in"; + + feature_name = "nat44-ei-classify"; } - } - if (nm->static_mapping_only && !(nm->static_mapping_connection_tracking)) - feature_name = is_inside ? "nat44-ei-in2out-fast" : "nat44-ei-out2in-fast"; + 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; + } + } + } else { if (nm->num_workers > 1) - feature_name = is_inside ? "nat44-ei-in2out-worker-handoff" : - "nat44-ei-out2in-worker-handoff"; + { + 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"; - } + { + feature_name = is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in"; + } + nat_validate_interface_counters (nm, sw_if_index); - 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); + 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) + { + return rv; + } + } + + pool_get (nm->interfaces, i); + i->sw_if_index = sw_if_index; + i->flags = 0; + } - 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); + fib_index = + fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index); if (!is_inside) { - vec_foreach (outside_fib, nm->outside_fibs) + i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE; + + outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index); + if (outside_fib) { - 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; - } + outside_fib->refcount++; } - if (!is_del) + else { vec_add2 (nm->outside_fibs, outside_fib, 1); - outside_fib->refcount = 1; outside_fib->fib_index = fib_index; + outside_fib->refcount = 1; } - } -feature_set: - pool_foreach (i, nm->interfaces) + 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 { - if (i->sw_if_index == sw_if_index) - { - 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; + i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE; + } - 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"; - } + return 0; +} - 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 - { - if ((nat44_ei_interface_is_inside (i) && is_inside) || - (nat44_ei_interface_is_outside (i) && !is_inside)) - return 0; +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; - 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"); - } + nat44_ei_outside_fib_t *outside_fib; + nat44_ei_interface_t *i; + u32 fib_index; + int rv; - 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; - } + fail_if_disabled (); - goto fib; - } + if (nm->out2in_dpo && !is_inside) + { + nat44_ei_log_err ("error unsupported"); + return VNET_API_ERROR_UNSUPPORTED; } - if (is_del) + i = nat44_ei_get_interface (nm->interfaces, sw_if_index); + if (i == 0) { 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; - 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; - - if (is_inside && !nm->out2in_dpo) + if (nat44_ei_interface_is_inside (i) && nat44_ei_interface_is_outside (i)) { - rv = vnet_feature_enable_disable ("ip4-local", "nat44-ei-hairpinning", + if (nm->num_workers > 1) + { + 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"; + 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", 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; - } - -set_flags: - if (is_inside) - { - i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE; - return 0; + { + 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 - i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE; + { + 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"; + } - /* 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); + 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; + } + } - pool_foreach (m, nm->static_mappings) + // remove interface + pool_put (nm->interfaces, i); + } + + if (!is_inside) { - if (!(nat44_ei_is_addr_only_static_mapping (m)) || - (m->local_addr.as_u32 == m->external_addr.as_u32)) - continue; + 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 (&m->external_addr, 32, sw_if_index, - !is_del); + 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_interface_add_del_output_feature (u32 sw_if_index, u8 is_inside, - int is_del) +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_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 (nat44_ei_get_interface (nm->interfaces, sw_if_index)) { - nat44_ei_log_err ("error unsupported"); - return VNET_API_ERROR_UNSUPPORTED; + nat44_ei_log_err ("error interface already configured"); + return VNET_API_ERROR_VALUE_EXIST; } - pool_foreach (i, nm->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 (!is_inside) + if (nm->num_workers > 1) { - 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 = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1); + 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", "nat44-ei-out2in-worker-handoff", sw_if_index, 1, 0, 0); + if (rv) + { + return rv; + } + rv = vnet_feature_enable_disable ( + "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index, 1, + 0, 0); + if (rv) + { + return rv; } } - -feature_set: - if (is_inside) + 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; - 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", "nat44-ei-out2in", + sw_if_index, 1, 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-output", "nat44-ei-in2out-output", + sw_if_index, 1, 0, 0); if (rv) - return rv; - goto fq; + { + return rv; + } + } + + nat_validate_interface_counters (nm, sw_if_index); + + 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; + + 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++; + } + 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); + + 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; } 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, 0); 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, 0); 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, 0, 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, 0, + 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, 0); 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, 0); 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, 0, 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, 0, 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); + pool_put (nm->output_feature_interfaces, i); - 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_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) + outside_fib->refcount--; + if (!outside_fib->refcount) { - if (is_del) - pool_put (nm->output_feature_interfaces, i); - else - return VNET_API_ERROR_VALUE_EXIST; - - goto fib; + 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) { - nat44_ei_log_err ("error interface couldn't be found"); - return VNET_API_ERROR_NO_SUCH_ENTRY; + return nat44_ei_del_output_interface (sw_if_index); } - - 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; else - i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE; - - /* Add/delete external addresses to FIB */ -fib: - if (is_inside) - return 0; - - 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); + return nat44_ei_add_output_interface (sw_if_index); } - - return 0; } int @@ -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; - - 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; - } + a = nm->addresses + i; - /* 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; + } } + } +} + +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 (identity_nat) + 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; + } + + 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)) + { + return VNET_API_ERROR_VALUE_EXIST; + } + } - /* Delete dynamic sessions matching local address (+ local port) */ - // TODO: based on type of NAT EI/ED - if (!(nm->static_mapping_only)) + if (!(is_sm_addr_only (flags) || nm->static_mapping_only)) + { + if (nat44_ei_reserve_port (e_addr, e_port, proto)) { - 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)) + // 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; + } + } - if (nat44_ei_is_session_static (s)) - continue; + pool_get (nm->static_mappings, m); + clib_memset (m, 0, sizeof (*m)); - if (!addr_only && s->in2out.port != m->local_port) - continue; + m->flags = flags; + m->local_addr = l_addr; + m->external_addr = e_addr; - 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); + m->tag = vec_dup (tag); - if (!addr_only) - break; - } - } - } - } + 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 { - if (!m) + 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)) { - if (sw_if_index != ~0) - return 0; - else - return VNET_API_ERROR_NO_SUCH_ENTRY; + return VNET_API_ERROR_NO_SUCH_ENTRY; } - if (identity_nat) + first_int_addr = + ip4_interface_first_address (nm->ip4_main, sw_if_index, 0); + if (!first_int_addr) { - if (vrf_id == ~0) - vrf_id = nm->inside_vrf_id; + // dhcp resolution required + return 0; + } - pool_foreach (local, m->locals) - { - if (local->vrf_id == vrf_id) - find = local - m->locals; - } - if (find == ~0) - return VNET_API_ERROR_NO_SUCH_ENTRY; + 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; + } - local = pool_elt_at_index (m->locals, find); - fib_index = local->fib_index; - pool_put (m->locals, local); + // 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; } - else - fib_index = m->fib_index; + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + + m = pool_elt_at_index (nm->static_mappings, value.value); + + if (is_sm_identity_nat (flags)) + { + u8 found = 0; - /* Free external address port */ - if (!(addr_only || nm->static_mapping_only)) + if (vrf_id == ~0) { - for (i = 0; i < vec_len (nm->addresses); i++) + vrf_id = nm->inside_vrf_id; + } + + pool_foreach (local, m->locals) + { + if (local->vrf_id == vrf_id) { - 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; - } + local = pool_elt_at_index (m->locals, local - m->locals); + fib_index = local->fib_index; + pool_put (m->locals, local); + found = 1; } } + if (!found) + { + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + } + else + { + fib_index = m->fib_index; + } + if (!(is_sm_addr_only (flags) || nm->static_mapping_only)) + { + if (nat44_ei_free_port (e_addr, e_port, proto)) + { + 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; + } } - pool_foreach (interface, nm->output_feature_interfaces) + /* 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) { - 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; + (void) nat44_ei_add_address (first_int_addr, ~0); + } + + 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 (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 diff --git a/src/plugins/nat/nat44-ei/nat44_ei.h b/src/plugins/nat/nat44-ei/nat44_ei.h index 2e95b1413ca..0134c7882dd 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei.h +++ b/src/plugins/nat/nat44-ei/nat44_ei.h @@ -63,8 +63,8 @@ typedef enum #define NAT44_EI_SESSION_FLAG_UNKNOWN_PROTO (1 << 1) /* Static mapping flags */ -#define NAT44_EI_STATIC_MAPPING_FLAG_ADDR_ONLY (1 << 0) -#define NAT44_EI_STATIC_MAPPING_FLAG_IDENTITY_NAT (1 << 1) +#define NAT44_EI_SM_FLAG_ADDR_ONLY (1 << 0) +#define NAT44_EI_SM_FLAG_IDENTITY_NAT (1 << 1) typedef struct { @@ -139,13 +139,9 @@ typedef struct u32 vrf_id; u32 flags; nat_protocol_t proto; - u8 addr_only; - u8 identity_nat; - u8 exact; u8 *tag; } nat44_ei_static_map_resolve_t; -// TODO: cleanup/redo (there is no lb in EI nat) typedef struct { /* backend IP address */ @@ -340,6 +336,8 @@ typedef struct nat44_ei_main_s /* Interface pool */ nat44_ei_interface_t *interfaces; nat44_ei_interface_t *output_feature_interfaces; + // broken api backward compatibility + nat44_ei_interface_t *output_feature_dummy_interfaces; /* Is translation memory size calculated or user defined */ u8 translation_memory_size_set; @@ -484,9 +482,16 @@ typedef struct nat44_ei_main_s extern nat44_ei_main_t nat44_ei_main; int nat44_ei_plugin_enable (nat44_ei_config_t c); - int nat44_ei_plugin_disable (); +int nat44_ei_add_del_interface (u32 sw_if_index, u8 is_inside, int is_del); +int nat44_ei_add_del_output_interface (u32 sw_if_index, int is_del); + +int nat44_ei_add_address (ip4_address_t *addr, u32 vrf_id); +int nat44_ei_del_address (ip4_address_t addr, u8 delete_sm); +int nat44_ei_add_interface_address (u32 sw_if_index); +int nat44_ei_del_interface_address (u32 sw_if_index); + /** * @brief Delete specific NAT44 EI user and his sessions * @@ -533,29 +538,14 @@ void nat44_ei_set_alloc_mape (u16 psid, u16 psid_offset, u16 psid_length); */ void nat44_ei_set_alloc_range (u16 start_port, u16 end_port); -/** - * @brief Add/delete NAT44-EI static mapping - * - * @param l_addr local IPv4 address - * @param e_addr external IPv4 address - * @param l_port local port number - * @param e_port external port number - * @param proto L4 protocol - * @param sw_if_index use interface address as external IPv4 address - * @param vrf_id local VRF ID - * @param addr_only 1 = 1:1NAT, 0 = 1:1NAPT - * @param identity_nat identity NAT - * @param tag opaque string tag - * @param is_add 1 = add, 0 = delete - * - * @return 0 on success, non-zero value otherwise +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); - */ -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); +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); /** * @brief Delete NAT44-EI session @@ -620,9 +610,6 @@ int nat44_ei_set_outside_address_and_port (nat44_ei_address_t *addresses, ip4_address_t addr, u16 port, nat_protocol_t protocol); -int nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, - u8 delete_sm); - void nat44_ei_free_session_data (nat44_ei_main_t *nm, nat44_ei_session_t *s, u32 thread_index, u8 is_ha); @@ -630,20 +617,9 @@ int nat44_ei_set_workers (uword *bitmap); void nat44_ei_add_del_address_dpo (ip4_address_t addr, u8 is_add); -int nat44_ei_add_address (nat44_ei_main_t *nm, ip4_address_t *addr, - u32 vrf_id); - void nat44_ei_delete_session (nat44_ei_main_t *nm, nat44_ei_session_t *ses, u32 thread_index); -int nat44_ei_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del); - -int nat44_ei_interface_add_del_output_feature (u32 sw_if_index, u8 is_inside, - int is_del); - -int nat44_ei_add_interface_address (nat44_ei_main_t *nm, u32 sw_if_index, - int is_del); - /* Call back functions for clib_bihash_add_or_overwrite_stale */ int nat44_i2o_is_idle_session_cb (clib_bihash_kv_8_8_t *kv, void *arg); int nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t *kv, void *arg); @@ -665,20 +641,41 @@ u32 nat44_ei_icmp_hairpinning (nat44_ei_main_t *nm, vlib_buffer_t *b0, int nat44_ei_set_frame_queue_nelts (u32 frame_queue_nelts); -#define nat44_ei_is_session_static(sp) \ - (sp->flags & NAT44_EI_SESSION_FLAG_STATIC_MAPPING) -#define nat44_ei_is_unk_proto_session(sp) \ - (sp->flags & NAT44_EI_SESSION_FLAG_UNKNOWN_PROTO) +always_inline bool +nat44_ei_is_session_static (nat44_ei_session_t *s) +{ + return (s->flags & NAT44_EI_SESSION_FLAG_STATIC_MAPPING); +} + +always_inline bool +nat44_ei_is_unk_proto_session (nat44_ei_session_t *s) +{ + return (s->flags & NAT44_EI_SESSION_FLAG_UNKNOWN_PROTO); +} -#define nat44_ei_interface_is_inside(ip) \ - (ip->flags & NAT44_EI_INTERFACE_FLAG_IS_INSIDE) -#define nat44_ei_interface_is_outside(ip) \ - (ip->flags & NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE) +always_inline bool +nat44_ei_interface_is_inside (nat44_ei_interface_t *i) +{ + return (i->flags & NAT44_EI_INTERFACE_FLAG_IS_INSIDE); +} -#define nat44_ei_is_addr_only_static_mapping(mp) \ - (mp->flags & NAT44_EI_STATIC_MAPPING_FLAG_ADDR_ONLY) -#define nat44_ei_is_identity_static_mapping(mp) \ - (mp->flags & NAT44_EI_STATIC_MAPPING_FLAG_IDENTITY_NAT) +always_inline bool +nat44_ei_interface_is_outside (nat44_ei_interface_t *i) +{ + return (i->flags & NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE); +} + +always_inline bool +is_sm_addr_only (u32 f) +{ + return (f & NAT44_EI_SM_FLAG_ADDR_ONLY); +} + +always_inline bool +is_sm_identity_nat (u32 f) +{ + return (f & NAT44_EI_SM_FLAG_IDENTITY_NAT); +} /* logging */ #define nat44_ei_log_err(...) \ diff --git a/src/plugins/nat/nat44-ei/nat44_ei_api.c b/src/plugins/nat/nat44-ei/nat44_ei_api.c index 427140ffb92..c6d17c94205 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_api.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_api.c @@ -469,9 +469,9 @@ vl_api_nat44_ei_add_del_address_range_t_handler ( for (i = 0; i < count; i++) { if (is_add) - rv = nat44_ei_add_address (nm, &this_addr, vrf_id); + rv = nat44_ei_add_address (&this_addr, vrf_id); else - rv = nat44_ei_del_address (nm, this_addr, 0); + rv = nat44_ei_del_address (this_addr, 0); if (rv) goto send_reply; @@ -540,7 +540,7 @@ vl_api_nat44_ei_interface_add_del_feature_t_handler ( VALIDATE_SW_IF_INDEX (mp); - rv = nat44_ei_interface_add_del (sw_if_index, mp->flags & NAT44_EI_IF_INSIDE, + rv = nat44_ei_add_del_interface (sw_if_index, mp->flags & NAT44_EI_IF_INSIDE, is_del); BAD_SW_IF_INDEX_LABEL; @@ -588,19 +588,68 @@ vl_api_nat44_ei_interface_dump_t_handler (vl_api_nat44_ei_interface_dump_t *mp) } } +static_always_inline int +add_del_dummy_output_interface (u32 sw_if_index, u8 is_inside, u8 is_add) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + nat44_ei_interface_t *i; + int rv = 1; + + pool_foreach (i, nm->output_feature_dummy_interfaces) + { + if (i->sw_if_index == sw_if_index) + { + if (!is_add) + { + pool_put (nm->output_feature_dummy_interfaces, i); + rv = 0; + } + goto done; + } + } + + if (is_add) + { + pool_get (nm->output_feature_dummy_interfaces, i); + i->sw_if_index = sw_if_index; + + if (is_inside) + { + i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE; + } + else + { + i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE; + } + + rv = 0; + } + +done: + return rv; +} + static void vl_api_nat44_ei_interface_add_del_output_feature_t_handler ( vl_api_nat44_ei_interface_add_del_output_feature_t *mp) { - nat44_ei_main_t *nm = &nat44_ei_main; vl_api_nat44_ei_interface_add_del_output_feature_reply_t *rmp; - u32 sw_if_index = ntohl (mp->sw_if_index); + nat44_ei_main_t *nm = &nat44_ei_main; + u32 sw_if_index; int rv = 0; VALIDATE_SW_IF_INDEX (mp); - rv = nat44_ei_interface_add_del_output_feature ( - sw_if_index, mp->flags & NAT44_EI_IF_INSIDE, !mp->is_add); + sw_if_index = ntohl (mp->sw_if_index); + + // register all interfaces in the dummy structure + rv = add_del_dummy_output_interface ( + sw_if_index, mp->flags & NAT44_EI_IF_INSIDE, mp->is_add); + + if (!(mp->flags & NAT44_EI_IF_INSIDE)) + { + rv = nat44_ei_add_del_output_interface (sw_if_index, !mp->is_add); + } BAD_SW_IF_INDEX_LABEL; REPLY_MACRO (VL_API_NAT44_EI_INTERFACE_ADD_DEL_OUTPUT_FEATURE_REPLY); @@ -622,7 +671,9 @@ send_nat44_ei_interface_output_feature_details (nat44_ei_interface_t *i, rmp->context = context; if (nat44_ei_interface_is_inside (i)) - rmp->flags |= NAT44_EI_IF_INSIDE; + { + rmp->flags |= NAT44_EI_IF_INSIDE; + } vl_api_send_msg (reg, (u8 *) rmp); } @@ -639,49 +690,131 @@ vl_api_nat44_ei_interface_output_feature_dump_t_handler ( if (!reg) return; - pool_foreach (i, nm->output_feature_interfaces) + pool_foreach (i, nm->output_feature_dummy_interfaces) { send_nat44_ei_interface_output_feature_details (i, reg, mp->context); } } static void +vl_api_nat44_ei_add_del_output_interface_t_handler ( + vl_api_nat44_ei_add_del_output_interface_t *mp) +{ + vl_api_nat44_ei_add_del_output_interface_reply_t *rmp; + nat44_ei_main_t *nm = &nat44_ei_main; + u32 sw_if_index; + int rv = 0; + + VALIDATE_SW_IF_INDEX (mp); + + sw_if_index = ntohl (mp->sw_if_index); + + rv = nat44_ei_add_del_output_interface (sw_if_index, !mp->is_add); + + BAD_SW_IF_INDEX_LABEL; + REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_OUTPUT_INTERFACE_REPLY); +} + +#define vl_endianfun +#include <nat/nat44-ei/nat44_ei.api.h> +#undef vl_endianfun +static void +send_nat44_ei_output_interface_details (u32 index, vl_api_registration_t *rp, + u32 context) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + vl_api_nat44_ei_output_interface_details_t *rmp; + nat44_ei_interface_t *i = + pool_elt_at_index (nm->output_feature_interfaces, index); + + /* Make sure every field is initiated (or don't skip the clib_memset()) */ + REPLY_MACRO_DETAILS4 ( + VL_API_NAT44_EI_OUTPUT_INTERFACE_DETAILS, rp, context, ({ + rmp->sw_if_index = i->sw_if_index; + + /* Endian hack until apigen registers _details + * endian functions */ + vl_api_nat44_ei_output_interface_details_t_endian (rmp); + rmp->_vl_msg_id = htons (rmp->_vl_msg_id); + rmp->context = htonl (rmp->context); + })); +} + +static void +vl_api_nat44_ei_output_interface_get_t_handler ( + vl_api_nat44_ei_output_interface_get_t *mp) +{ + vl_api_nat44_ei_output_interface_get_reply_t *rmp; + nat44_ei_main_t *nm = &nat44_ei_main; + i32 rv = 0; + + if (pool_elts (nm->output_feature_interfaces) == 0) + { + REPLY_MACRO (VL_API_NAT44_EI_OUTPUT_INTERFACE_GET_REPLY); + return; + } + + REPLY_AND_DETAILS_MACRO ( + VL_API_NAT44_EI_OUTPUT_INTERFACE_GET_REPLY, nm->output_feature_interfaces, + ({ send_nat44_ei_output_interface_details (cursor, rp, mp->context); })); +} + +static void vl_api_nat44_ei_add_del_static_mapping_t_handler ( vl_api_nat44_ei_add_del_static_mapping_t *mp) { - nat44_ei_main_t *nm = &nat44_ei_main; vl_api_nat44_ei_add_del_static_mapping_reply_t *rmp; - ip4_address_t local_addr, external_addr; - u16 local_port = 0, external_port = 0; - u32 vrf_id, external_sw_if_index; + + nat44_ei_main_t *nm = &nat44_ei_main; int rv = 0; - nat_protocol_t proto; + + ip4_address_t l_addr, e_addr, pool_addr = { 0 }; + u32 sw_if_index, flags = 0, vrf_id; + u16 l_port = 0, e_port = 0; + nat_protocol_t proto = 0; u8 *tag = 0; - memcpy (&local_addr.as_u8, mp->local_ip_address, 4); - memcpy (&external_addr.as_u8, mp->external_ip_address, 4); + memcpy (&l_addr.as_u8, mp->local_ip_address, 4); - if (!(mp->flags & NAT44_EI_ADDR_ONLY_MAPPING)) + if (mp->flags & NAT44_EI_ADDR_ONLY_MAPPING) { - local_port = mp->local_port; - external_port = mp->external_port; + flags |= NAT44_EI_SM_FLAG_ADDR_ONLY; + } + else + { + l_port = mp->local_port; + e_port = mp->external_port; + proto = ip_proto_to_nat_proto (mp->protocol); } - vrf_id = clib_net_to_host_u32 (mp->vrf_id); - external_sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index); - proto = ip_proto_to_nat_proto (mp->protocol); - - mp->tag[sizeof (mp->tag) - 1] = 0; - tag = format (0, "%s", mp->tag); - vec_terminate_c_string (tag); - - rv = nat44_ei_add_del_static_mapping ( - local_addr, external_addr, local_port, external_port, proto, - external_sw_if_index, vrf_id, mp->flags & NAT44_EI_ADDR_ONLY_MAPPING, 0, - tag, mp->is_add); + sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index); + if (sw_if_index != ~0) + { + e_addr.as_u32 = 0; + } + else + { + memcpy (&e_addr.as_u8, mp->external_ip_address, 4); + } - vec_free (tag); + vrf_id = clib_net_to_host_u32 (mp->vrf_id); + if (mp->is_add) + { + mp->tag[sizeof (mp->tag) - 1] = 0; + tag = format (0, "%s", mp->tag); + vec_terminate_c_string (tag); + + rv = nat44_ei_add_static_mapping (l_addr, e_addr, l_port, e_port, proto, + vrf_id, sw_if_index, flags, pool_addr, + tag); + vec_free (tag); + } + else + { + rv = nat44_ei_del_static_mapping (l_addr, e_addr, l_port, e_port, proto, + vrf_id, sw_if_index, flags); + } REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_STATIC_MAPPING_REPLY); } @@ -704,7 +837,7 @@ send_nat44_ei_static_mapping_details (nat44_ei_static_mapping_t *m, rmp->vrf_id = htonl (m->vrf_id); rmp->context = context; - if (nat44_ei_is_addr_only_static_mapping (m)) + if (is_sm_addr_only (m->flags)) { rmp->flags |= NAT44_EI_ADDR_ONLY_MAPPING; } @@ -738,7 +871,7 @@ send_nat44_ei_static_map_resolve_details (nat44_ei_static_map_resolve_t *m, rmp->vrf_id = htonl (m->vrf_id); rmp->context = context; - if (m->addr_only) + if (is_sm_addr_only (m->flags)) { rmp->flags |= NAT44_EI_ADDR_ONLY_MAPPING; } @@ -770,14 +903,14 @@ vl_api_nat44_ei_static_mapping_dump_t_handler ( pool_foreach (m, nm->static_mappings) { - if (!nat44_ei_is_identity_static_mapping (m)) + if (!is_sm_identity_nat (m->flags)) send_nat44_ei_static_mapping_details (m, reg, mp->context); } for (j = 0; j < vec_len (nm->to_resolve); j++) { rp = nm->to_resolve + j; - if (!rp->identity_nat) + if (!is_sm_identity_nat (rp->flags)) send_nat44_ei_static_map_resolve_details (rp, reg, mp->context); } } @@ -786,35 +919,56 @@ static void vl_api_nat44_ei_add_del_identity_mapping_t_handler ( vl_api_nat44_ei_add_del_identity_mapping_t *mp) { - nat44_ei_main_t *nm = &nat44_ei_main; vl_api_nat44_ei_add_del_identity_mapping_reply_t *rmp; - ip4_address_t addr; - u16 port = 0; - u32 vrf_id, sw_if_index; + + nat44_ei_main_t *nm = &nat44_ei_main; int rv = 0; - nat_protocol_t proto = NAT_PROTOCOL_OTHER; + + ip4_address_t addr, pool_addr = { 0 }; + u32 sw_if_index, flags, vrf_id; + nat_protocol_t proto = 0; + u16 port = 0; u8 *tag = 0; - if (!(mp->flags & NAT44_EI_ADDR_ONLY_MAPPING)) + flags = NAT44_EI_SM_FLAG_IDENTITY_NAT; + + if (mp->flags & NAT44_EI_ADDR_ONLY_MAPPING) + { + flags |= NAT44_EI_SM_FLAG_ADDR_ONLY; + } + else { port = mp->port; proto = ip_proto_to_nat_proto (mp->protocol); } - vrf_id = clib_net_to_host_u32 (mp->vrf_id); + sw_if_index = clib_net_to_host_u32 (mp->sw_if_index); if (sw_if_index != ~0) - addr.as_u32 = 0; + { + addr.as_u32 = 0; + } else - memcpy (&addr.as_u8, mp->ip_address, 4); - mp->tag[sizeof (mp->tag) - 1] = 0; - tag = format (0, "%s", mp->tag); - vec_terminate_c_string (tag); + { + memcpy (&addr.as_u8, mp->ip_address, 4); + } - rv = nat44_ei_add_del_static_mapping ( - addr, addr, port, port, proto, sw_if_index, vrf_id, - mp->flags & NAT44_EI_ADDR_ONLY_MAPPING, 1, tag, mp->is_add); + vrf_id = clib_net_to_host_u32 (mp->vrf_id); - vec_free (tag); + if (mp->is_add) + { + mp->tag[sizeof (mp->tag) - 1] = 0; + tag = format (0, "%s", mp->tag); + vec_terminate_c_string (tag); + + rv = nat44_ei_add_static_mapping (addr, addr, port, port, proto, vrf_id, + sw_if_index, flags, pool_addr, tag); + vec_free (tag); + } + else + { + rv = nat44_ei_del_static_mapping (addr, addr, port, port, proto, vrf_id, + sw_if_index, flags); + } REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_IDENTITY_MAPPING_REPLY); } @@ -833,7 +987,7 @@ send_nat44_ei_identity_mapping_details (nat44_ei_static_mapping_t *m, rmp->_vl_msg_id = ntohs (VL_API_NAT44_EI_IDENTITY_MAPPING_DETAILS + nm->msg_id_base); - if (nat44_ei_is_addr_only_static_mapping (m)) + if (is_sm_addr_only (m->flags)) rmp->flags |= NAT44_EI_ADDR_ONLY_MAPPING; clib_memcpy (rmp->ip_address, &(m->local_addr), 4); @@ -860,7 +1014,7 @@ send_nat44_ei_identity_map_resolve_details (nat44_ei_static_map_resolve_t *m, rmp->_vl_msg_id = ntohs (VL_API_NAT44_EI_IDENTITY_MAPPING_DETAILS + nm->msg_id_base); - if (m->addr_only) + if (is_sm_addr_only (m->flags)) rmp->flags = (vl_api_nat44_ei_config_flags_t) NAT44_EI_ADDR_ONLY_MAPPING; rmp->port = m->l_port; @@ -890,7 +1044,7 @@ vl_api_nat44_ei_identity_mapping_dump_t_handler ( pool_foreach (m, nm->static_mappings) { - if (nat44_ei_is_identity_static_mapping (m)) + if (is_sm_identity_nat (m->flags)) { pool_foreach_index (j, m->locals) { @@ -902,7 +1056,7 @@ vl_api_nat44_ei_identity_mapping_dump_t_handler ( for (j = 0; j < vec_len (nm->to_resolve); j++) { rp = nm->to_resolve + j; - if (rp->identity_nat) + if (is_sm_identity_nat (rp->flags)) send_nat44_ei_identity_map_resolve_details (rp, reg, mp->context); } } @@ -915,13 +1069,17 @@ vl_api_nat44_ei_add_del_interface_addr_t_handler ( vl_api_nat44_ei_add_del_interface_addr_reply_t *rmp; u32 sw_if_index = ntohl (mp->sw_if_index); int rv = 0; - u8 is_del; - - is_del = !mp->is_add; VALIDATE_SW_IF_INDEX (mp); - rv = nat44_ei_add_interface_address (nm, sw_if_index, is_del); + if (mp->is_add) + { + rv = nat44_ei_add_interface_address (sw_if_index); + } + else + { + rv = nat44_ei_del_interface_address (sw_if_index); + } BAD_SW_IF_INDEX_LABEL; REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_INTERFACE_ADDR_REPLY); diff --git a/src/plugins/nat/nat44-ei/nat44_ei_cli.c b/src/plugins/nat/nat44-ei/nat44_ei_cli.c index 0780e5d68b6..f3e71982e5c 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_cli.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_cli.c @@ -112,9 +112,9 @@ format_nat44_ei_static_mapping (u8 *s, va_list *args) nat44_ei_static_mapping_t *m = va_arg (*args, nat44_ei_static_mapping_t *); nat44_ei_lb_addr_port_t *local; - if (nat44_ei_is_identity_static_mapping (m)) + if (is_sm_identity_nat (m->flags)) { - if (nat44_ei_is_addr_only_static_mapping (m)) + if (is_sm_addr_only (m->flags)) s = format (s, "identity mapping %U", format_ip4_address, &m->local_addr); else @@ -130,7 +130,7 @@ format_nat44_ei_static_mapping (u8 *s, va_list *args) return s; } - if (nat44_ei_is_addr_only_static_mapping (m)) + if (is_sm_addr_only (m->flags)) { s = format (s, "local %U external %U vrf %d", format_ip4_address, &m->local_addr, format_ip4_address, &m->external_addr, @@ -154,7 +154,7 @@ format_nat44_ei_static_map_to_resolve (u8 *s, va_list *args) va_arg (*args, nat44_ei_static_map_resolve_t *); vnet_main_t *vnm = vnet_get_main (); - if (m->addr_only) + if (is_sm_addr_only (m->flags)) s = format (s, "local %U external %U vrf %d", format_ip4_address, &m->l_addr, format_vnet_sw_if_index_name, vnm, m->sw_if_index, m->vrf_id); @@ -790,9 +790,9 @@ add_address_command_fn (vlib_main_t *vm, unformat_input_t *input, for (i = 0; i < count; i++) { if (is_add) - rv = nat44_ei_add_address (nm, &this_addr, vrf_id); + rv = nat44_ei_add_address (&this_addr, vrf_id); else - rv = nat44_ei_del_address (nm, this_addr, 0); + rv = nat44_ei_del_address (this_addr, 0); switch (rv) { @@ -894,8 +894,7 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input, sw_if_index = inside_sw_if_indices[i]; if (is_output_feature) { - if (nat44_ei_interface_add_del_output_feature (sw_if_index, 1, - is_del)) + if (nat44_ei_add_del_output_interface (sw_if_index, is_del)) { error = clib_error_return ( 0, "%s %U failed", is_del ? "del" : "add", @@ -905,7 +904,7 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input, } else { - if (nat44_ei_interface_add_del (sw_if_index, 1, is_del)) + if (nat44_ei_add_del_interface (sw_if_index, 1, is_del)) { error = clib_error_return ( 0, "%s %U failed", is_del ? "del" : "add", @@ -923,8 +922,7 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input, sw_if_index = outside_sw_if_indices[i]; if (is_output_feature) { - if (nat44_ei_interface_add_del_output_feature (sw_if_index, 0, - is_del)) + if (nat44_ei_add_del_output_interface (sw_if_index, is_del)) { error = clib_error_return ( 0, "%s %U failed", is_del ? "del" : "add", @@ -934,7 +932,7 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input, } else { - if (nat44_ei_interface_add_del (sw_if_index, 0, is_del)) + if (nat44_ei_add_del_interface (sw_if_index, 0, is_del)) { error = clib_error_return ( 0, "%s %U failed", is_del ? "del" : "add", @@ -990,14 +988,16 @@ add_static_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) { unformat_input_t _line_input, *line_input = &_line_input; - clib_error_t *error = 0; - ip4_address_t l_addr, e_addr; - u32 l_port = 0, e_port = 0, vrf_id = ~0; - int is_add = 1, addr_only = 1, rv; - u32 sw_if_index = ~0; vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + int rv; + nat_protocol_t proto = NAT_PROTOCOL_OTHER; - u8 proto_set = 0; + ip4_address_t l_addr, e_addr, pool_addr = { 0 }; + u32 l_port = 0, e_port = 0, vrf_id = ~0; + u8 l_port_set = 0, e_port_set = 0; + u32 sw_if_index = ~0, flags = 0; + int is_add = 1; if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_EI_EXPECTED_ARGUMENT); @@ -1006,29 +1006,37 @@ add_static_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input, { if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr, &l_port)) - addr_only = 0; + { + l_port_set = 1; + } else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr)) ; else if (unformat (line_input, "external %U %u", unformat_ip4_address, &e_addr, &e_port)) - addr_only = 0; + { + e_port_set = 1; + } else if (unformat (line_input, "external %U", unformat_ip4_address, &e_addr)) ; else if (unformat (line_input, "external %U %u", unformat_vnet_sw_interface, vnm, &sw_if_index, &e_port)) - addr_only = 0; + { + e_port_set = 1; + } else if (unformat (line_input, "external %U", unformat_vnet_sw_interface, vnm, &sw_if_index)) ; else if (unformat (line_input, "vrf %u", &vrf_id)) ; else if (unformat (line_input, "%U", unformat_nat_protocol, &proto)) - proto_set = 1; + ; else if (unformat (line_input, "del")) - is_add = 0; + { + is_add = 0; + } else { error = clib_error_return (0, "unknown input: '%U'", @@ -1037,25 +1045,33 @@ add_static_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input, } } - if (addr_only) + if (l_port_set != e_port_set) { - if (proto_set) - { - error = clib_error_return ( - 0, "address only mapping doesn't support protocol"); - goto done; - } + error = clib_error_return (0, "Either both ports are set or none."); + goto done; } - else if (!proto_set) + + if (!l_port_set) { - error = clib_error_return (0, "protocol is required"); - goto done; + flags |= NAT44_EI_SM_FLAG_ADDR_ONLY; + } + else + { + l_port = clib_host_to_net_u16 (l_port); + e_port = clib_host_to_net_u16 (e_port); } - rv = nat44_ei_add_del_static_mapping ( - l_addr, e_addr, clib_host_to_net_u16 (l_port), - clib_host_to_net_u16 (e_port), proto, sw_if_index, vrf_id, addr_only, 0, 0, - is_add); + if (is_add) + { + rv = + nat44_ei_add_static_mapping (l_addr, e_addr, l_port, e_port, proto, + vrf_id, sw_if_index, flags, pool_addr, 0); + } + else + { + rv = nat44_ei_del_static_mapping (l_addr, e_addr, l_port, e_port, proto, + vrf_id, sw_if_index, flags); + } switch (rv) { @@ -1091,17 +1107,15 @@ add_identity_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) { unformat_input_t _line_input, *line_input = &_line_input; - clib_error_t *error = 0; - u32 port = 0, vrf_id = ~0; - ip4_address_t addr; - int is_add = 1; - int addr_only = 1; - u32 sw_if_index = ~0; vnet_main_t *vnm = vnet_get_main (); - int rv; + clib_error_t *error = 0; + + int rv, is_add = 1, port_set = 0; + u32 sw_if_index = ~0, port, flags, vrf_id = ~0; nat_protocol_t proto; + ip4_address_t addr; - addr.as_u32 = 0; + flags = NAT44_EI_SM_FLAG_IDENTITY_NAT; if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_EI_EXPECTED_ARGUMENT); @@ -1117,9 +1131,13 @@ add_identity_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input, ; else if (unformat (line_input, "%U %u", unformat_nat_protocol, &proto, &port)) - addr_only = 0; + { + port_set = 1; + } else if (unformat (line_input, "del")) - is_add = 0; + { + is_add = 0; + } else { error = clib_error_return (0, "unknown input: '%U'", @@ -1128,9 +1146,26 @@ add_identity_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input, } } - rv = nat44_ei_add_del_static_mapping ( - addr, addr, clib_host_to_net_u16 (port), clib_host_to_net_u16 (port), - proto, sw_if_index, vrf_id, addr_only, 1, 0, is_add); + if (!port_set) + { + flags |= NAT44_EI_SM_FLAG_ADDR_ONLY; + } + else + { + port = clib_host_to_net_u16 (port); + } + + if (is_add) + { + + rv = nat44_ei_add_static_mapping (addr, addr, port, port, proto, vrf_id, + sw_if_index, flags, addr, 0); + } + else + { + rv = nat44_ei_del_static_mapping (addr, addr, port, port, proto, vrf_id, + sw_if_index, flags); + } switch (rv) { @@ -1184,12 +1219,11 @@ nat44_ei_add_interface_address_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) { - nat44_ei_main_t *nm = &nat44_ei_main; unformat_input_t _line_input, *line_input = &_line_input; - u32 sw_if_index; - int rv; - int is_del = 0; + nat44_ei_main_t *nm = &nat44_ei_main; clib_error_t *error = 0; + int rv, is_del = 0; + u32 sw_if_index; if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_EI_EXPECTED_ARGUMENT); @@ -1200,7 +1234,9 @@ nat44_ei_add_interface_address_command_fn (vlib_main_t *vm, nm->vnet_main, &sw_if_index)) ; else if (unformat (line_input, "del")) - is_del = 1; + { + is_del = 1; + } else { error = clib_error_return (0, "unknown input '%U'", @@ -1209,17 +1245,21 @@ nat44_ei_add_interface_address_command_fn (vlib_main_t *vm, } } - rv = nat44_ei_add_interface_address (nm, sw_if_index, is_del); - - switch (rv) + if (!is_del) { - case 0: - break; - - default: - error = clib_error_return ( - 0, "nat44_ei_add_interface_address returned %d", rv); - goto done; + rv = nat44_ei_add_interface_address (sw_if_index); + if (rv) + { + error = clib_error_return (0, "add address returned %d", rv); + } + } + else + { + rv = nat44_ei_del_interface_address (sw_if_index); + if (rv) + { + error = clib_error_return (0, "del address returned %d", rv); + } } done: @@ -1493,7 +1533,6 @@ nat_show_timeouts_command_fn (vlib_main_t *vm, unformat_input_t *input, { nat44_ei_main_t *nm = &nat44_ei_main; - // TODO: make format timeout function vlib_cli_output (vm, "udp timeout: %dsec", nm->timeouts.udp); vlib_cli_output (vm, "tcp-established timeout: %dsec", nm->timeouts.tcp.established); diff --git a/src/plugins/nat/nat44-ei/nat44_ei_handoff.c b/src/plugins/nat/nat44-ei/nat44_ei_handoff.c index c7a1317026b..5c16d871c4d 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_handoff.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_handoff.c @@ -83,8 +83,6 @@ nat44_ei_worker_handoff_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_get_buffers (vm, from, b, n_left_from); - // TODO: move to nm - // TODO: remove callbacks and use inlines that should be moved here if (is_in2out) { fq_index = is_output ? nm->fq_in2out_output_index : nm->fq_in2out_index; diff --git a/test/test_nat44_ei.py b/test/test_nat44_ei.py index 5fdcf3fa3c7..6dcda8c6ae4 100644 --- a/test/test_nat44_ei.py +++ b/test/test_nat44_ei.py @@ -2831,13 +2831,6 @@ class TestNAT44EI(MethodHolder): def test_output_feature(self): """ NAT44EI output feature (in2out postrouting) """ self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT44_EI_IF_INSIDE - self.vapi.nat44_ei_interface_add_del_output_feature( - is_add=1, flags=flags, - sw_if_index=self.pg0.sw_if_index) - self.vapi.nat44_ei_interface_add_del_output_feature( - is_add=1, flags=flags, - sw_if_index=self.pg1.sw_if_index) self.vapi.nat44_ei_interface_add_del_output_feature( is_add=1, sw_if_index=self.pg3.sw_if_index) @@ -2884,13 +2877,6 @@ class TestNAT44EI(MethodHolder): self.nat44_add_address(nat_ip_vrf10, vrf_id=10) self.nat44_add_address(nat_ip_vrf20, vrf_id=20) - flags = self.config_flags.NAT44_EI_IF_INSIDE - self.vapi.nat44_ei_interface_add_del_output_feature( - is_add=1, flags=flags, - sw_if_index=self.pg4.sw_if_index) - self.vapi.nat44_ei_interface_add_del_output_feature( - is_add=1, flags=flags, - sw_if_index=self.pg6.sw_if_index) self.vapi.nat44_ei_interface_add_del_output_feature( is_add=1, sw_if_index=self.pg3.sw_if_index) @@ -2937,9 +2923,8 @@ class TestNAT44EI(MethodHolder): server_out_port = 8765 self.nat44_add_address(self.nat_addr) - flags = self.config_flags.NAT44_EI_IF_INSIDE self.vapi.nat44_ei_interface_add_del_output_feature( - is_add=1, flags=flags, + is_add=1, sw_if_index=self.pg0.sw_if_index) self.vapi.nat44_ei_interface_add_del_output_feature( is_add=1, |