nat44_ei_main_t nat44_ei_main;
extern vlib_node_registration_t nat44_ei_hairpinning_node;
-extern vlib_node_registration_t nat44_ei_hairpin_dst_node;
extern vlib_node_registration_t
nat44_ei_in2out_hairpinning_finish_ip4_lookup_node;
extern vlib_node_registration_t
if (PREDICT_FALSE (nm->enabled)) \
{ \
nat44_ei_log_err ("plugin enabled"); \
- return 1; \
+ return VNET_API_ERROR_FEATURE_ALREADY_ENABLED; \
} \
} \
while (0)
if (PREDICT_FALSE (!nm->enabled)) \
{ \
nat44_ei_log_err ("plugin disabled"); \
- return 1; \
+ return VNET_API_ERROR_FEATURE_ALREADY_DISABLED; \
} \
} \
while (0)
.runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa",
"ip4-sv-reassembly-output-feature"),
};
-VNET_FEATURE_INIT (ip4_nat44_ei_in2out_fast, static) = {
- .arc_name = "ip4-unicast",
- .node_name = "nat44-ei-in2out-fast",
- .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
- "ip4-sv-reassembly-feature"),
-};
-VNET_FEATURE_INIT (ip4_nat44_ei_out2in_fast, static) = {
- .arc_name = "ip4-unicast",
- .node_name = "nat44-ei-out2in-fast",
- .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
- "ip4-sv-reassembly-feature",
- "ip4-dhcp-client-detect"),
-};
-VNET_FEATURE_INIT (ip4_nat44_ei_hairpin_dst, static) = {
- .arc_name = "ip4-unicast",
- .node_name = "nat44-ei-hairpin-dst",
- .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
- "ip4-sv-reassembly-feature"),
-};
-VNET_FEATURE_INIT (ip4_nat44_ei_hairpin_src, static) = {
- .arc_name = "ip4-output",
- .node_name = "nat44-ei-hairpin-src",
- .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa",
- "ip4-sv-reassembly-output-feature"),
-};
VNET_FEATURE_INIT (ip4_nat44_ei_hairpinning, static) = {
.arc_name = "ip4-local",
.node_name = "nat44-ei-hairpinning",
void nat44_ei_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len,
u32 sw_if_index, int is_add);
+static void nat44_ei_worker_db_free (nat44_ei_main_per_thread_data_t *tnm);
+
+static int nat44_ei_add_static_mapping_internal (
+ 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);
+
+static int nat44_ei_del_static_mapping_internal (
+ 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);
+
+always_inline bool
+nat44_ei_port_is_used (nat44_ei_address_t *a, u8 proto, u16 port)
+{
+ return clib_bitmap_get (a->busy_port_bitmap[proto], port);
+}
+
+always_inline void
+nat44_ei_port_get (nat44_ei_address_t *a, u8 proto, u16 port)
+{
+ ASSERT (!nat44_ei_port_is_used (a, proto, port));
+ a->busy_port_bitmap[proto] =
+ clib_bitmap_set (a->busy_port_bitmap[proto], port, 1);
+}
+
+always_inline void
+nat44_ei_port_put (nat44_ei_address_t *a, u8 proto, u16 port)
+{
+ ASSERT (nat44_ei_port_is_used (a, proto, port));
+ a->busy_port_bitmap[proto] =
+ clib_bitmap_set (a->busy_port_bitmap[proto], port, 0);
+}
+
static u8 *
format_nat44_ei_classify_trace (u8 *s, va_list *args)
{
return s;
}
-static void nat44_ei_db_free ();
-
static void nat44_ei_db_init (u32 translations, u32 translation_buckets,
u32 user_buckets);
nm->hairpinning_fq_index =
vlib_frame_queue_main_init (nat44_ei_hairpinning_node.index, 0);
- nm->hairpin_dst_fq_index =
- vlib_frame_queue_main_init (nat44_ei_hairpin_dst_node.index, 0);
nm->in2out_hairpinning_finish_ip4_lookup_node_fq_index =
vlib_frame_queue_main_init (
nat44_ei_in2out_hairpinning_finish_ip4_lookup_node.index, 0);
nm->user_buckets);
nat44_ei_set_alloc_default ();
- // TODO: zero simple counter for all counters missing
-
vlib_zero_simple_counter (&nm->total_users, 0);
vlib_zero_simple_counter (&nm->total_sessions, 0);
vlib_zero_simple_counter (&nm->user_limit_reached, 0);
return 0;
}
-void
-nat44_ei_addresses_free (nat44_ei_address_t **addresses)
-{
- nat44_ei_address_t *ap;
- vec_foreach (ap, *addresses)
- {
-#define _(N, i, n, s) vec_free (ap->busy_##n##_ports_per_thread);
- foreach_nat_protocol
-#undef _
- }
- vec_free (*addresses);
- *addresses = 0;
-}
-
static_always_inline nat44_ei_outside_fib_t *
nat44_ei_get_outside_fib (nat44_ei_outside_fib_t *outside_fibs, u32 fib_index)
{
return 0;
}
+static_always_inline int
+nat44_ei_hairpinning_enable (u8 is_enable)
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ u32 sw_if_index = 0; // local0
+
+ if (is_enable)
+ {
+ nm->hairpin_reg += 1;
+ if (1 == nm->hairpin_reg)
+ {
+ return vnet_feature_enable_disable (
+ "ip4-local", "nat44-ei-hairpinning", sw_if_index, is_enable, 0, 0);
+ }
+ }
+ else
+ {
+ if (0 == nm->hairpin_reg)
+ return 1;
+
+ nm->hairpin_reg -= 1;
+ if (0 == nm->hairpin_reg)
+ {
+ return vnet_feature_enable_disable (
+ "ip4-local", "nat44-ei-hairpinning", sw_if_index, is_enable, 0, 0);
+ }
+ }
+
+ return 0;
+}
+
int
nat44_ei_add_interface (u32 sw_if_index, u8 is_inside)
{
}
if (!is_inside)
{
- rv = vnet_feature_enable_disable (
- "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0);
+ rv = nat44_ei_hairpinning_enable (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);
+ rv = nat44_ei_hairpinning_enable (1);
if (rv)
{
return rv;
}
else
{
- rv = vnet_feature_enable_disable (
- "ip4-local", "nat44-ei-hairpinning", sw_if_index, 1, 0, 0);
+ rv = nat44_ei_hairpinning_enable (1);
if (rv)
{
return rv;
}
if (is_inside)
{
- rv = vnet_feature_enable_disable (
- "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0);
+ rv = nat44_ei_hairpinning_enable (0);
if (rv)
{
return rv;
}
}
- 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);
+ 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_plugin_disable ()
+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_del_addresses ()
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ nat44_ei_address_t *a, *vec;
+ int error = 0;
+
+ vec = vec_dup (nm->addresses);
+ vec_foreach (a, vec)
+ {
+ error = nat44_ei_del_address (a->addr, 0);
+
+ if (error)
+ {
+ nat44_ei_log_err ("error occurred while removing adderess");
+ }
+ }
+ vec_free (vec);
+ vec_free (nm->addresses);
+ nm->addresses = 0;
+
+ vec_free (nm->auto_add_sw_if_indices);
+ nm->auto_add_sw_if_indices = 0;
+ return error;
+}
+
+int
+nat44_ei_del_interfaces ()
{
nat44_ei_main_t *nm = &nat44_ei_main;
nat44_ei_interface_t *i, *pool;
int error = 0;
- // first unregister all nodes from interfaces
pool = pool_dup (nm->interfaces);
pool_foreach (i, pool)
{
if (error)
{
- nat44_ei_log_err ("error occurred while removing interface %u",
- i->sw_if_index);
+ nat44_ei_log_err ("error occurred while removing interface");
}
}
pool_free (pool);
pool_free (nm->interfaces);
+ nm->interfaces = 0;
+ return error;
+}
+
+int
+nat44_ei_del_output_interfaces ()
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ nat44_ei_interface_t *i, *pool;
+ int error = 0;
pool = pool_dup (nm->output_feature_interfaces);
pool_foreach (i, pool)
error = nat44_ei_del_output_interface (i->sw_if_index);
if (error)
{
- nat44_ei_log_err ("error occurred while removing interface %u",
- i->sw_if_index);
+ nat44_ei_log_err ("error occurred while removing output interface");
}
}
pool_free (pool);
pool_free (nm->output_feature_interfaces);
+ nm->output_feature_interfaces = 0;
+ return error;
+}
- nat_ha_disable ();
- nat44_ei_db_free ();
+int
+nat44_ei_del_static_mappings ()
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ nat44_ei_static_mapping_t *m, *pool;
+ int error = 0;
- nat44_ei_addresses_free (&nm->addresses);
+ pool = pool_dup (nm->static_mappings);
+ pool_foreach (m, pool)
+ {
+ error = nat44_ei_del_static_mapping_internal (
+ m->local_addr, m->external_addr, m->local_port, m->external_port,
+ m->proto, m->vrf_id, ~0, m->flags);
+ if (error)
+ {
+ nat44_ei_log_err ("error occurred while removing mapping");
+ }
+ }
+ pool_free (pool);
+ pool_free (nm->static_mappings);
+ nm->static_mappings = 0;
vec_free (nm->to_resolve);
- vec_free (nm->auto_add_sw_if_indices);
-
nm->to_resolve = 0;
- nm->auto_add_sw_if_indices = 0;
- nm->forwarding_enabled = 0;
+ clib_bihash_free_8_8 (&nm->static_mapping_by_local);
+ clib_bihash_free_8_8 (&nm->static_mapping_by_external);
+
+ return error;
+}
+
+int
+nat44_ei_plugin_disable ()
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ nat44_ei_main_per_thread_data_t *tnm;
+ int rc, error = 0;
+
+ fail_if_disabled ();
+
+ nat_ha_disable ();
+
+ rc = nat44_ei_del_static_mappings ();
+ if (rc)
+ error = VNET_API_ERROR_BUG;
+
+ rc = nat44_ei_del_addresses ();
+ if (rc)
+ error = VNET_API_ERROR_BUG;
+
+ rc = nat44_ei_del_interfaces ();
+ if (rc)
+ error = VNET_API_ERROR_BUG;
+
+ rc = nat44_ei_del_output_interfaces ();
+ if (rc)
+ error = VNET_API_ERROR_BUG;
+
+ if (nm->pat)
+ {
+ clib_bihash_free_8_8 (&nm->in2out);
+ clib_bihash_free_8_8 (&nm->out2in);
+
+ vec_foreach (tnm, nm->per_thread_data)
+ {
+ nat44_ei_worker_db_free (tnm);
+ }
+ }
- nm->enabled = 0;
clib_memset (&nm->rconfig, 0, sizeof (nm->rconfig));
- return 0;
+ nm->forwarding_enabled = 0;
+ nm->enabled = 0;
+
+ return error;
}
int
u32 thread_index, ip4_address_t addr,
u16 port, nat_protocol_t protocol)
{
- nat44_ei_main_t *nm = &nat44_ei_main;
nat44_ei_address_t *a = 0;
u32 address_index;
u16 port_host_byte_order = clib_net_to_host_u16 (port);
continue;
a = addresses + address_index;
- switch (protocol)
- {
-#define _(N, j, n, s) \
- case NAT_PROTOCOL_##N: \
- if (a->busy_##n##_port_refcounts[port_host_byte_order]) \
- return VNET_API_ERROR_INSTANCE_IN_USE; \
- ++a->busy_##n##_port_refcounts[port_host_byte_order]; \
- a->busy_##n##_ports_per_thread[thread_index]++; \
- a->busy_##n##_ports++; \
- return 0;
- foreach_nat_protocol
-#undef _
- default : nat_elog_info (nm, "unknown protocol");
- return 1;
- }
+ if (nat44_ei_port_is_used (a, protocol, port_host_byte_order))
+ return VNET_API_ERROR_INSTANCE_IN_USE;
+
+ nat44_ei_port_get (a, protocol, port_host_byte_order);
+ a->busy_ports_per_thread[protocol][thread_index]++;
+ a->busy_ports[protocol]++;
+ return 0;
}
return VNET_API_ERROR_NO_SUCH_ENTRY;
u32 thread_index, ip4_address_t *addr,
u16 port, nat_protocol_t protocol)
{
- nat44_ei_main_t *nm = &nat44_ei_main;
nat44_ei_address_t *a;
u32 address_index;
u16 port_host_byte_order = clib_net_to_host_u16 (port);
ASSERT (address_index < vec_len (addresses));
a = addresses + address_index;
-
- switch (protocol)
- {
-#define _(N, i, n, s) \
- case NAT_PROTOCOL_##N: \
- ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1); \
- --a->busy_##n##_port_refcounts[port_host_byte_order]; \
- a->busy_##n##_ports--; \
- a->busy_##n##_ports_per_thread[thread_index]--; \
- break;
- foreach_nat_protocol
-#undef _
- default : nat_elog_info (nm, "unknown protocol");
- return;
- }
+ nat44_ei_port_put (a, protocol, port_host_byte_order);
+ a->busy_ports[protocol]--;
+ a->busy_ports_per_thread[protocol][thread_index]--;
}
void
return next_worker_index;
}
+u32
+nat44_ei_get_thread_idx_by_port (u16 e_port)
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ u32 thread_idx = nm->num_workers;
+ if (nm->num_workers > 1)
+ {
+ thread_idx = nm->first_worker_index +
+ nm->workers[(e_port - 1024) / nm->port_per_thread %
+ _vec_len (nm->workers)];
+ }
+ return thread_idx;
+}
+
u32
nat44_ei_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip0,
u32 rx_fib_index0, u8 is_output)
}
/* worker by outside port */
- next_worker_index = nm->first_worker_index;
- next_worker_index +=
- nm->workers[(clib_net_to_host_u16 (port) - 1024) / nm->port_per_thread];
+ next_worker_index =
+ nat44_ei_get_thread_idx_by_port (clib_net_to_host_u16 (port));
return next_worker_index;
}
if (vec_len (addresses) > 0)
{
-
int s_addr_offset = s_addr.as_u32 % vec_len (addresses);
for (i = s_addr_offset; i < vec_len (addresses); ++i)
{
a = addresses + i;
- switch (proto)
+
+ if (a->busy_ports_per_thread[proto][thread_index] < port_per_thread)
{
-#define _(N, j, n, s) \
- case NAT_PROTOCOL_##N: \
- if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
- { \
- if (a->fib_index == fib_index) \
- { \
- while (1) \
- { \
- portnum = (port_per_thread * snat_thread_index) + \
- nat_random_port (&nm->random_seed, 0, \
- port_per_thread - 1) + \
- 1024; \
- if (a->busy_##n##_port_refcounts[portnum]) \
- continue; \
- --a->busy_##n##_port_refcounts[portnum]; \
- a->busy_##n##_ports_per_thread[thread_index]++; \
- a->busy_##n##_ports++; \
- *addr = a->addr; \
- *port = clib_host_to_net_u16 (portnum); \
- return 0; \
- } \
- } \
- else if (a->fib_index == ~0) \
- { \
- ga = a; \
- } \
- } \
- break;
- foreach_nat_protocol;
- default:
- nat_elog_info (nm, "unknown protocol");
- return 1;
+ if (a->fib_index == fib_index)
+ {
+ while (1)
+ {
+ portnum = (port_per_thread * snat_thread_index) +
+ nat_random_port (&nm->random_seed, 0,
+ port_per_thread - 1) +
+ 1024;
+ if (nat44_ei_port_is_used (a, proto, portnum))
+ continue;
+ nat44_ei_port_get (a, proto, portnum);
+ a->busy_ports_per_thread[proto][thread_index]++;
+ a->busy_ports[proto]++;
+ *addr = a->addr;
+ *port = clib_host_to_net_u16 (portnum);
+ return 0;
+ }
+ }
+ else if (a->fib_index == ~0)
+ {
+ ga = a;
+ }
}
}
for (i = 0; i < s_addr_offset; ++i)
{
a = addresses + i;
- switch (proto)
+ if (a->busy_ports_per_thread[proto][thread_index] < port_per_thread)
{
- foreach_nat_protocol;
- default:
- nat_elog_info (nm, "unknown protocol");
- return 1;
+ if (a->fib_index == fib_index)
+ {
+ while (1)
+ {
+ portnum = (port_per_thread * snat_thread_index) +
+ nat_random_port (&nm->random_seed, 0,
+ port_per_thread - 1) +
+ 1024;
+ if (nat44_ei_port_is_used (a, proto, portnum))
+ continue;
+ nat44_ei_port_get (a, proto, portnum);
+ a->busy_ports_per_thread[proto][thread_index]++;
+ a->busy_ports[proto]++;
+ *addr = a->addr;
+ *port = clib_host_to_net_u16 (portnum);
+ return 0;
+ }
+ }
+ else if (a->fib_index == ~0)
+ {
+ ga = a;
+ }
}
}
- if (ga)
- {
- a = ga;
- // fake fib index to reuse macro
- fib_index = ~0;
- switch (proto)
+
+ if (ga)
{
- foreach_nat_protocol;
- default : nat_elog_info (nm, "unknown protocol");
- return 1;
+ a = ga;
+ if (a->busy_ports_per_thread[proto][thread_index] < port_per_thread)
+ {
+ if (a->fib_index == ~0)
+ {
+ while (1)
+ {
+ portnum = (port_per_thread * snat_thread_index) +
+ nat_random_port (&nm->random_seed, 0,
+ port_per_thread - 1) +
+ 1024;
+ if (nat44_ei_port_is_used (a, proto, portnum))
+ continue;
+ nat44_ei_port_get (a, proto, portnum);
+ a->busy_ports_per_thread[proto][thread_index]++;
+ a->busy_ports[proto]++;
+ *addr = a->addr;
+ *port = clib_host_to_net_u16 (portnum);
+ return 0;
+ }
+ }
+ }
}
}
- }
-
-#undef _
/* Totally out of translations to use... */
nat_ipfix_logging_addresses_exhausted (thread_index, 0);
if (!vec_len (addresses))
goto exhausted;
- switch (proto)
- {
-#define _(N, i, n, s) \
- case NAT_PROTOCOL_##N: \
- if (a->busy_##n##_ports < ports) \
- { \
- while (1) \
- { \
- portnum = nat_random_port (&nm->random_seed, nm->start_port, \
- nm->end_port); \
- if (a->busy_##n##_port_refcounts[portnum]) \
- continue; \
- ++a->busy_##n##_port_refcounts[portnum]; \
- a->busy_##n##_ports++; \
- *addr = a->addr; \
- *port = clib_host_to_net_u16 (portnum); \
- return 0; \
- } \
- } \
- break;
- foreach_nat_protocol
-#undef _
- default : nat_elog_info (nm, "unknown protocol");
- return 1;
+ if (a->busy_ports[proto] < ports)
+ {
+ while (1)
+ {
+ portnum =
+ nat_random_port (&nm->random_seed, nm->start_port, nm->end_port);
+ if (nat44_ei_port_is_used (a, proto, portnum))
+ continue;
+ nat44_ei_port_get (a, proto, portnum);
+ a->busy_ports[proto]++;
+ *addr = a->addr;
+ *port = clib_host_to_net_u16 (portnum);
+ return 0;
+ }
}
exhausted:
if (!vec_len (addresses))
goto exhausted;
- switch (proto)
- {
-#define _(N, i, n, s) \
- case NAT_PROTOCOL_##N: \
- if (a->busy_##n##_ports < ports) \
- { \
- while (1) \
- { \
- A = nat_random_port (&nm->random_seed, 1, \
- pow2_mask (nm->psid_offset)); \
- j = nat_random_port (&nm->random_seed, 0, pow2_mask (m)); \
- portnum = A | (nm->psid << nm->psid_offset) | (j << (16 - m)); \
- if (a->busy_##n##_port_refcounts[portnum]) \
- continue; \
- ++a->busy_##n##_port_refcounts[portnum]; \
- a->busy_##n##_ports++; \
- *addr = a->addr; \
- *port = clib_host_to_net_u16 (portnum); \
- return 0; \
- } \
- } \
- break;
- foreach_nat_protocol
-#undef _
- default : nat_elog_info (nm, "unknown protocol");
- return 1;
+ if (a->busy_ports[proto] < ports)
+ {
+ while (1)
+ {
+ A =
+ nat_random_port (&nm->random_seed, 1, pow2_mask (nm->psid_offset));
+ j = nat_random_port (&nm->random_seed, 0, pow2_mask (m));
+ portnum = A | (nm->psid << nm->psid_offset) | (j << (16 - m));
+ if (nat44_ei_port_is_used (a, proto, portnum))
+ continue;
+ nat44_ei_port_get (a, proto, portnum);
+ a->busy_ports[proto]++;
+ *addr = a->addr;
+ *port = clib_host_to_net_u16 (portnum);
+ return 0;
+ }
}
exhausted:
return VNET_API_ERROR_NO_SUCH_ENTRY;
}
-u32
-nat44_ei_get_thread_idx_by_port (u16 e_port)
-{
- nat44_ei_main_t *nm = &nat44_ei_main;
- u32 thread_idx = nm->num_workers;
- if (nm->num_workers > 1)
- {
- thread_idx = nm->first_worker_index +
- nm->workers[(e_port - 1024) / nm->port_per_thread];
- }
- return thread_idx;
-}
-
void
nat44_ei_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len, u32 sw_if_index,
int is_add)
if (a->addr.as_u32 != addr.as_u32)
continue;
- switch (proto)
- {
-#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;
- }
+ if (nat44_ei_port_is_used (a, proto, port))
+ continue;
+ nat44_ei_port_get (a, proto, port);
+ if (port > 1024)
+ {
+ a->busy_ports[proto]++;
+ a->busy_ports_per_thread[proto][ti]++;
+ }
return 0;
}
-done:
return 1;
}
if (a->addr.as_u32 != addr.as_u32)
continue;
- 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;
+ nat44_ei_port_put (a, proto, port);
+ if (port > 1024)
+ {
+ a->busy_ports[proto]--;
+ a->busy_ports_per_thread[proto][ti]--;
}
-
return 0;
}
-done:
return 1;
}
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)
+ if (is_sm_switch_address (flags))
{
- // 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))
{
return VNET_API_ERROR_VALUE_EXIST;
}
- // 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_address_t *first_int_addr =
+ ip4_interface_first_address (nm->ip4_main, sw_if_index, 0);
+ if (!first_int_addr)
+ {
+ // dhcp resolution required
+ return 0;
+ }
+
+ e_addr.as_u32 = first_int_addr->as_u32;
+ }
+
+ return nat44_ei_add_static_mapping_internal (l_addr, e_addr, l_port, e_port,
+ proto, vrf_id, sw_if_index,
+ flags, pool_addr, tag);
+}
+
+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_t *nm = &nat44_ei_main;
+
+ if (is_sm_switch_address (flags))
+ {
+
+ 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;
+ }
+
+ ip4_address_t *first_int_addr =
ip4_interface_first_address (nm->ip4_main, sw_if_index, 0);
if (!first_int_addr)
{
e_addr.as_u32 = first_int_addr->as_u32;
}
+ return nat44_ei_del_static_mapping_internal (
+ l_addr, e_addr, l_port, e_port, proto, vrf_id, sw_if_index, flags);
+}
+
+static int
+nat44_ei_add_static_mapping_internal (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 (is_sm_identity_nat (flags))
{
l_port = e_port;
if (nat44_ei_reserve_port (e_addr, e_port, proto))
{
// remove resolve record
- if ((sw_if_index != ~0) && !is_sm_identity_nat (flags))
+ if ((is_sm_switch_address (flags)) && !is_sm_identity_nat (flags))
{
nat44_ei_del_resolve_record (l_addr, l_port, e_port, proto,
vrf_id, sw_if_index, flags);
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)
+static int
+nat44_ei_del_static_mapping_internal (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;
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;
- }
-
- first_int_addr =
- ip4_interface_first_address (nm->ip4_main, sw_if_index, 0);
- if (!first_int_addr)
- {
- // dhcp resolution required
- return 0;
- }
-
- e_addr.as_u32 = first_int_addr->as_u32;
- }
-
if (is_sm_identity_nat (flags))
{
l_port = e_port;
if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
{
- if (sw_if_index != ~0)
+ if (is_sm_switch_address (flags))
{
return 0;
}
clib_dlist_init (tnm->lru_pool, tnm->unk_proto_lru_head_index);
}
-static void
-nat44_ei_db_free ()
-{
- nat44_ei_main_t *nm = &nat44_ei_main;
- nat44_ei_main_per_thread_data_t *tnm;
-
- pool_free (nm->static_mappings);
- clib_bihash_free_8_8 (&nm->static_mapping_by_local);
- clib_bihash_free_8_8 (&nm->static_mapping_by_external);
-
- if (nm->pat)
- {
- clib_bihash_free_8_8 (&nm->in2out);
- clib_bihash_free_8_8 (&nm->out2in);
- vec_foreach (tnm, nm->per_thread_data)
- {
- nat44_ei_worker_db_free (tnm);
- }
- }
-}
-
static void
nat44_ei_db_init (u32 translations, u32 translation_buckets, u32 user_buckets)
{
FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
}
-#define _(N, i, n, s) \
- clib_memset (ap->busy_##n##_port_refcounts, 0, \
- sizeof (ap->busy_##n##_port_refcounts)); \
- ap->busy_##n##_ports = 0; \
- ap->busy_##n##_ports_per_thread = 0; \
- vec_validate_init_empty (ap->busy_##n##_ports_per_thread, \
- tm->n_vlib_mains - 1, 0);
- foreach_nat_protocol
-#undef _
+ nat_protocol_t proto;
+ for (proto = 0; proto < NAT_N_PROTOCOLS; ++proto)
+ {
+ ap->busy_port_bitmap[proto] = 0;
+ ap->busy_ports[proto] = 0;
+ ap->busy_ports_per_thread[proto] = 0;
+ vec_validate_init_empty (ap->busy_ports_per_thread[proto],
+ tm->n_vlib_mains - 1, 0);
+ }
nat44_ei_add_del_addr_to_fib_foreach_out_if (addr, 1);
pool_foreach (m, nm->static_mappings)
{
if (m->external_addr.as_u32 == addr.as_u32)
- 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);
+ nat44_ei_del_static_mapping_internal (
+ m->local_addr, m->external_addr, m->local_port, m->external_port,
+ m->proto, m->vrf_id, ~0, m->flags);
}
}
else
}
}
- if (a->fib_index != ~0)
- {
- 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)
+ if (a->busy_ports[NAT_PROTOCOL_TCP] || a->busy_ports[NAT_PROTOCOL_UDP] ||
+ a->busy_ports[NAT_PROTOCOL_ICMP])
{
vec_foreach (tnm, nm->per_thread_data)
{
}
}
-#define _(N, i, n, s) vec_free (a->busy_##n##_ports_per_thread);
- foreach_nat_protocol
-#undef _
+ nat44_ei_add_del_addr_to_fib_foreach_out_if (&addr, 0);
- vec_del1 (nm->addresses, j);
+ if (a->fib_index != ~0)
+ {
+ fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
+ }
- nat44_ei_add_del_addr_to_fib_foreach_out_if (&addr, 0);
+ nat_protocol_t proto;
+ for (proto = 0; proto < NAT_N_PROTOCOLS; ++proto)
+ {
+ vec_free (a->busy_ports_per_thread[proto]);
+ }
+ vec_del1 (nm->addresses, j);
return 0;
}
/* On this interface? */
if (rp->sw_if_index == sw_if_index)
{
- rv = nat44_ei_add_static_mapping (
+ rv = nat44_ei_add_static_mapping_internal (
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, "add_static_mapping returned %d",
- "i4", rv);
+ nat_elog_notice_X1 (
+ nm, "add_static_mapping_internal returned %d", "i4", rv);
}
}
}
{
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);
+ rv = nat44_ei_del_static_mapping_internal (
+ 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",
{
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);
+ rv = nat44_ei_add_static_mapping_internal (
+ 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",