#include <vnet/ip/ip4.h>
#include <vnet/plugin/plugin.h>
#include <nat/nat.h>
+#include <nat/nat_dpo.h>
#include <nat/nat_ipfix_logging.h>
#include <nat/nat_det.h>
#include <nat/nat64.h>
/* Add external address to FIB */
pool_foreach (i, sm->interfaces,
({
- if (nat_interface_is_inside(i))
+ if (nat_interface_is_inside(i) || sm->out2in_dpo)
continue;
snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
}));
pool_foreach (i, sm->output_feature_interfaces,
({
- if (nat_interface_is_inside(i))
+ if (nat_interface_is_inside(i) || sm->out2in_dpo)
continue;
snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
* @param sw_if_index External port instead of specific IP address.
* @param is_add If 0 delete static mapping, otherwise add.
* @param twice_nat If 1 translate external host address and port.
+ * @param out2in_only If 1 rule match only out2in direction
*
* @returns
*/
int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
u32 sw_if_index, snat_protocol_t proto, int is_add,
- u8 twice_nat)
+ u8 twice_nat, u8 out2in_only)
{
snat_main_t * sm = &snat_main;
snat_static_mapping_t *m;
/* Find external address in allocated addresses and reserve port for
address and port pair mapping when dynamic translations enabled */
- if (!addr_only && !(sm->static_mapping_only))
+ if (!(addr_only || sm->static_mapping_only || out2in_only))
{
for (i = 0; i < vec_len (sm->addresses); i++)
{
m->vrf_id = vrf_id;
m->fib_index = fib_index;
m->twice_nat = twice_nat;
+ m->out2in_only = out2in_only;
if (!addr_only)
{
m->local_port = l_port;
m_key.fib_index = m->fib_index;
kv.key = m_key.as_u64;
kv.value = m - sm->static_mappings;
- clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
- if (twice_nat)
+ if (!out2in_only)
+ clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
+ if (twice_nat || out2in_only)
{
m_key.port = clib_host_to_net_u16 (l_port);
kv.key = m_key.as_u64;
kv.key = m_key.as_u64;
kv.value = m - sm->static_mappings;
clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
- if (twice_nat)
+ if (twice_nat || out2in_only)
{
m_key.port = clib_host_to_net_u16 (e_port);
kv.key = m_key.as_u64;
return VNET_API_ERROR_NO_SUCH_ENTRY;
/* Free external address port */
- if (!addr_only && !(sm->static_mapping_only))
+ if (!(addr_only || sm->static_mapping_only || out2in_only))
{
for (i = 0; i < vec_len (sm->addresses); i++)
{
m_key.protocol = m->proto;
m_key.fib_index = m->fib_index;
kv.key = m_key.as_u64;
- clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
- if (twice_nat)
+ if (!out2in_only)
+ clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
+ if (twice_nat || out2in_only)
{
m_key.port = clib_host_to_net_u16 (m->local_port);
kv.key = m_key.as_u64;
m_key.fib_index = sm->outside_fib_index;
kv.key = m_key.as_u64;
clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
- if (twice_nat)
+ if (twice_nat || out2in_only)
{
m_key.port = clib_host_to_net_u16 (m->external_port);
kv.key = m_key.as_u64;
/* Add/delete external address to FIB */
pool_foreach (interface, sm->interfaces,
({
- if (nat_interface_is_inside(interface))
+ if (nat_interface_is_inside(interface) || sm->out2in_dpo)
continue;
snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
}));
pool_foreach (interface, sm->output_feature_interfaces,
({
- if (nat_interface_is_inside(interface))
+ if (nat_interface_is_inside(interface) || sm->out2in_dpo)
continue;
snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
snat_protocol_t proto, u32 vrf_id,
nat44_lb_addr_port_t *locals, u8 is_add,
- u8 twice_nat)
+ u8 twice_nat, u8 out2in_only)
{
snat_main_t * sm = &snat_main;
snat_static_mapping_t *m;
/* Find external address in allocated addresses and reserve port for
address and port pair mapping when dynamic translations enabled */
- if (!sm->static_mapping_only)
+ if (!(sm->static_mapping_only || out2in_only))
{
for (i = 0; i < vec_len (sm->addresses); i++)
{
m->external_port = e_port;
m->proto = proto;
m->twice_nat = twice_nat;
+ m->out2in_only = out2in_only;
m_key.addr = m->external_addr;
m_key.port = m->external_port;
for (i = 0; i < vec_len (locals); i++)
{
m_key.addr = locals[i].addr;
- m_key.port = locals[i].port;
- kv.key = m_key.as_u64;
- kv.value = m - sm->static_mappings;
- clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
+ if (!out2in_only)
+ {
+ m_key.port = locals[i].port;
+ kv.key = m_key.as_u64;
+ kv.value = m - sm->static_mappings;
+ clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
+ }
locals[i].prefix = (i == 0) ? locals[i].probability :\
(locals[i - 1].prefix + locals[i].probability);
vec_add1 (m->locals, locals[i]);
fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_HI);
/* Free external address port */
- if (!sm->static_mapping_only)
+ if (!(sm->static_mapping_only || out2in_only))
{
for (i = 0; i < vec_len (sm->addresses); i++)
{
vec_foreach (local, m->locals)
{
m_key.addr = local->addr;
- m_key.port = local->port;
- m_key.fib_index = m->fib_index;
- kv.key = m_key.as_u64;
- if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
+ if (!out2in_only)
{
- clib_warning ("static_mapping_by_local key del failed");
- return VNET_API_ERROR_UNSPECIFIED;
+ m_key.port = local->port;
+ m_key.fib_index = m->fib_index;
+ kv.key = m_key.as_u64;
+ if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
+ {
+ clib_warning ("static_mapping_by_local key del failed");
+ return VNET_API_ERROR_UNSPECIFIED;
+ }
}
m_key.port = clib_host_to_net_u16 (local->port);
(void) snat_add_static_mapping (m->local_addr, m->external_addr,
m->local_port, m->external_port,
m->vrf_id, m->addr_only, ~0,
- m->proto, 0, m->twice_nat);
+ m->proto, 0, m->twice_nat,
+ m->out2in_only);
}));
}
else
/* Delete external address from FIB */
pool_foreach (interface, sm->interfaces,
({
- if (nat_interface_is_inside(interface))
+ if (nat_interface_is_inside(interface) || sm->out2in_dpo)
continue;
snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
}));
pool_foreach (interface, sm->output_feature_interfaces,
({
- if (nat_interface_is_inside(interface))
+ if (nat_interface_is_inside(interface) || sm->out2in_dpo)
continue;
snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
snat_static_mapping_t * m;
snat_det_map_t * dm;
+ if (sm->out2in_dpo && !is_inside)
+ return VNET_API_ERROR_UNSUPPORTED;
+
if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
else
i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
if (sm->num_workers > 1 && !sm->deterministic)
- del_feature_name = "nat44-handoff-classify";
+ {
+ del_feature_name = "nat44-handoff-classify";
+ feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
+ "nat44-out2in-worker-handoff";
+ }
else if (sm->deterministic)
- del_feature_name = "nat44-det-classify";
+ {
+ del_feature_name = "nat44-det-classify";
+ feature_name = !is_inside ? "nat44-det-in2out" :
+ "nat44-det-out2in";
+ }
else
- del_feature_name = "nat44-classify";
+ {
+ del_feature_name = "nat44-classify";
+ feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
+ }
vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
sw_if_index, 0, 0, 0);
/* Add/delete external addresses to FIB */
fib:
- if (is_inside)
+ if (is_inside && !sm->out2in_dpo)
{
vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
sw_if_index, !is_del, 0, 0);
clib_bitmap_foreach (i, bitmap,
({
vec_add1(sm->workers, i);
- sm->per_thread_data[i].snat_thread_index = j;
+ sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
j++;
}));
sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
+ sm->forwarding_enabled = 0;
p = hash_get_mem (tm->thread_registrations_by_name, "workers");
if (p)
vec_add1 (im->add_del_interface_address_callbacks, cb4);
+ nat_dpo_module_init ();
+
/* Init IPFIX logging */
snat_ipfix_logging_init(vm);
return 1;
}
+void
+nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
+{
+ dpo_id_t dpo_v4 = DPO_INVALID;
+ fib_prefix_t pfx = {
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_len = 32,
+ .fp_addr.ip4.as_u32 = addr.as_u32,
+ };
+
+ if (is_add)
+ {
+ nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
+ fib_table_entry_special_dpo_add (0, &pfx, FIB_SOURCE_PLUGIN_HI,
+ FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
+ dpo_reset (&dpo_v4);
+ }
+ else
+ {
+ fib_table_entry_special_remove (0, &pfx, FIB_SOURCE_PLUGIN_HI);
+ }
+}
+
static clib_error_t *
add_address_command_fn (vlib_main_t * vm,
unformat_input_t * input,
break;
}
+ if (sm->out2in_dpo)
+ nat44_add_del_address_dpo (this_addr, is_add);
+
increment_v4_address (&this_addr);
}
snat_protocol_t proto = ~0;
u8 proto_set = 0;
u8 twice_nat = 0;
+ u8 out2in_only = 0;
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
proto_set = 1;
else if (unformat (line_input, "twice-nat"))
twice_nat = 1;
+ else if (unformat (line_input, "out2in-only"))
+ out2in_only = 1;
else if (unformat (line_input, "del"))
is_add = 0;
else
rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
vrf_id, addr_only, sw_if_index, proto, is_add,
- twice_nat);
+ twice_nat, out2in_only);
switch (rv)
{
.function = add_static_mapping_command_fn,
.short_help =
"nat44 add static mapping tcp|udp|icmp local <addr> [<port>] "
- "external <addr> [<port>] [vrf <table-id>] [twice-nat] [del]",
+ "external <addr> [<port>] [vrf <table-id>] [twice-nat] [out2in-only] [del]",
};
static clib_error_t *
rv = snat_add_static_mapping(addr, addr, (u16) port, (u16) port,
vrf_id, addr_only, sw_if_index, proto, is_add,
- 0);
+ 0, 0);
switch (rv)
{
u8 proto_set = 0;
nat44_lb_addr_port_t *locals = 0, local;
u8 twice_nat = 0;
+ u8 out2in_only = 0;
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
proto_set = 1;
else if (unformat (line_input, "twice-nat"))
twice_nat = 1;
+ else if (unformat (line_input, "out2in-only"))
+ out2in_only = 1;
else if (unformat (line_input, "del"))
is_add = 0;
else
}
rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
- locals, is_add, twice_nat);
+ locals, is_add, twice_nat, out2in_only);
switch (rv)
{
.short_help =
"nat44 add load-balancing static mapping protocol tcp|udp "
"external <addr>:<port> local <addr>:<port> probability <n> [twice-nat] "
- "[vrf <table-id>] [del]",
+ "[vrf <table-id>] [out2in-only] [del]",
};
static clib_error_t *
snat_session_t *s;
int i;
u32 proto;
+ u32 next_worker_index = 0;
/* first try static mappings without port */
if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
}
/* worker by outside port */
- return (u32) ((clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread);
+ next_worker_index = sm->first_worker_index;
+ next_worker_index +=
+ sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
+ return next_worker_index;
}
static clib_error_t *
u8 static_mapping_only = 0;
u8 static_mapping_connection_tracking = 0;
snat_main_per_thread_data_t *tsm;
+ dslite_main_t * dm = &dslite_main;
sm->deterministic = 0;
+ sm->out2in_dpo = 0;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
else if (unformat (input, "nat64 st hash memory %d",
&nat64_st_memory_size))
;
+ else if (unformat (input, "out2in dpo"))
+ sm->out2in_dpo = 1;
+ else if (unformat (input, "dslite ce"))
+ dslite_set_ce(dm, 1);
else
return clib_error_return (0, "unknown input '%U'",
format_unformat_error, input);
{
if (vec_len (m->locals))
{
- s = format (s, "%U vrf %d external %U:%d %s",
+ s = format (s, "%U vrf %d external %U:%d %s %s",
format_snat_protocol, m->proto,
m->vrf_id,
format_ip4_address, &m->external_addr, m->external_port,
- m->twice_nat ? "twice-nat" : "");
+ m->twice_nat ? "twice-nat" : "",
+ m->out2in_only ? "out2in-only" : "");
vec_foreach (local, m->locals)
s = format (s, "\n local %U:%d probability %d\%",
format_ip4_address, &local->addr, local->port,
local->probability);
}
else
- s = format (s, "%U local %U:%d external %U:%d vrf %d %s",
+ s = format (s, "%U local %U:%d external %U:%d vrf %d %s %s",
format_snat_protocol, m->proto,
format_ip4_address, &m->local_addr, m->local_port,
format_ip4_address, &m->external_addr, m->external_port,
- m->vrf_id, m->twice_nat ? "twice-nat" : "");
+ m->vrf_id, m->twice_nat ? "twice-nat" : "",
+ m->out2in_only ? "out2in-only" : "");
}
return s;
}
~0 /* sw_if_index */,
rp->proto,
rp->is_add,
- 0);
+ 0, 0);
if (rv)
clib_warning ("snat_add_static_mapping returned %d",
rv);
{
error = clib_error_return (0, "unknown input '%U'",
format_unformat_error, line_input);
+ goto done;
}
}
"<in_addr>:<in_port> <ext_addr>:<ext_port>",
.function = snat_det_close_session_in_fn,
};
+
+static clib_error_t *
+snat_forwarding_set_command_fn (vlib_main_t *vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ snat_main_t *sm = &snat_main;
+ unformat_input_t _line_input, *line_input = &_line_input;
+ u8 forwarding_enable;
+ u8 forwarding_enable_set = 0;
+ clib_error_t *error = 0;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return clib_error_return (0, "'enable' or 'disable' expected");
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (!forwarding_enable_set && unformat (line_input, "enable"))
+ {
+ forwarding_enable = 1;
+ forwarding_enable_set = 1;
+ }
+ else if (!forwarding_enable_set && unformat (line_input, "disable"))
+ {
+ forwarding_enable = 0;
+ forwarding_enable_set = 1;
+ }
+ else
+ {
+ error = clib_error_return (0, "unknown input '%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+ }
+
+ if (!forwarding_enable_set)
+ {
+ error = clib_error_return (0, "'enable' or 'disable' expected");
+ goto done;
+ }
+
+ sm->forwarding_enabled = forwarding_enable;
+
+done:
+ unformat_free(line_input);
+
+ return error;
+}
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 forwarding}
+ * Enable or disable forwarding
+ * Forward packets which don't match existing translation
+ * or static mapping instead of dropping them.
+ * To enable forwarding, use:
+ * vpp# nat44 forwarding enable
+ * To disable forwarding, use:
+ * vpp# nat44 forwarding disable
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (snat_forwarding_set_command, static) = {
+ .path = "nat44 forwarding",
+ .short_help = "nat44 forwarding enable|disable",
+ .function = snat_forwarding_set_command_fn,
+};