#include <vlibapi/api.h>
#include <vlibmemory/api.h>
#include <vlibsocket/api.h>
+#include <vpp/app/version.h>
snat_main_t snat_main;
.runs_before = VNET_FEATURES ("ip4-lookup"),
};
-
-/*
- * This routine exists to convince the vlib plugin framework that
- * we haven't accidentally copied a random .dll into the plugin directory.
- *
- * Also collects global variable pointers passed from the vpp engine
- */
-
-clib_error_t *
-vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
- int from_early_init)
-{
- snat_main_t * sm = &snat_main;
- clib_error_t * error = 0;
-
- sm->vlib_main = vm;
- sm->vnet_main = h->vnet_main;
- sm->ethernet_main = h->ethernet_main;
-
- return error;
-}
+/* *INDENT-OFF* */
+VLIB_PLUGIN_REGISTER () = {
+ .version = VPP_BUILD_VER,
+};
+/* *INDENT-ON* */
/*$$$$$ move to an installed header file */
#if (1 || CLIB_DEBUG > 0) /* "trust, but verify" */
* that VPP will reply to ARP for this address and we don't need to enable
* proxy ARP on the outside interface.
*
- * @param sm SNAT main
* @param addr IPv4 address.
* @param sw_if_index Interface.
* @param is_add If 0 delete, otherwise add.
*/
static void
-snat_add_del_addr_to_fib (snat_main_t *sm,
- ip4_address_t * addr,
- u32 sw_if_index,
- int is_add)
+snat_add_del_addr_to_fib (ip4_address_t * addr, u32 sw_if_index, int is_add)
{
- ip4_main_t * ip4_main = sm->ip4_main;
- ip4_address_t * first_int_addr;
fib_prefix_t prefix = {
.fp_len = 32,
.fp_proto = FIB_PROTOCOL_IP4,
};
u32 fib_index = ip4_fib_table_get_index_for_sw_if_index(sw_if_index);
- first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0);
- if (first_int_addr)
- {
- if (first_int_addr->as_u32 == addr->as_u32)
- return;
- }
-
if (is_add)
fib_table_entry_update_one_path(fib_index,
&prefix,
- FIB_SOURCE_INTERFACE,
+ FIB_SOURCE_PLUGIN_HI,
(FIB_ENTRY_FLAG_CONNECTED |
FIB_ENTRY_FLAG_LOCAL |
FIB_ENTRY_FLAG_EXCLUSIVE),
else
fib_table_entry_delete(fib_index,
&prefix,
- FIB_SOURCE_INTERFACE);
+ FIB_SOURCE_PLUGIN_HI);
}
void snat_add_address (snat_main_t *sm, ip4_address_t *addr)
vec_add2 (sm->addresses, ap, 1);
ap->addr = *addr;
- clib_bitmap_alloc (ap->busy_port_bitmap, 65535);
+#define _(N, i, n, s) \
+ clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535);
+ foreach_snat_protocol
+#undef _
/* Add external address to FIB */
pool_foreach (i, sm->interfaces,
if (i->is_inside)
continue;
- snat_add_del_addr_to_fib(sm, addr, i->sw_if_index, 1);
+ snat_add_del_addr_to_fib(addr, i->sw_if_index, 1);
+ break;
}));
}
u32 sw_if_index,
u16 e_port,
u32 vrf_id,
+ snat_protocol_t proto,
int addr_only,
int is_add)
{
rp->sw_if_index = sw_if_index;
rp->e_port = e_port;
rp->vrf_id = vrf_id;
+ rp->proto = proto;
rp->addr_only = addr_only;
rp->is_add = is_add;
}
*/
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, int is_add)
+ u32 sw_if_index, snat_protocol_t proto, int is_add)
{
snat_main_t * sm = &snat_main;
snat_static_mapping_t *m;
- snat_static_mapping_key_t m_key;
+ snat_session_key_t m_key;
clib_bihash_kv_8_8_t kv, value;
snat_address_t *a = 0;
u32 fib_index = ~0;
snat_interface_t *interface;
int i;
- /* If outside FIB index is not resolved yet */
- if (sm->outside_fib_index == ~0)
- {
- p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->outside_vrf_id);
- if (!p)
- return VNET_API_ERROR_NO_SUCH_FIB;
- sm->outside_fib_index = p[0];
- }
-
/* If the external address is a specific interface address */
if (sw_if_index != ~0)
{
if (first_int_addr == 0)
{
snat_add_static_mapping_when_resolved
- (sm, l_addr, l_port, sw_if_index, e_port, vrf_id,
+ (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
addr_only, is_add);
return 0;
}
m_key.addr = e_addr;
m_key.port = addr_only ? 0 : e_port;
+ m_key.protocol = addr_only ? 0 : proto;
m_key.fib_index = sm->outside_fib_index;
kv.key = m_key.as_u64;
if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
/* If not specified use inside VRF id from SNAT plugin startup config */
else
{
- if (sm->inside_fib_index == ~0)
- {
- p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->inside_vrf_id);
- if (!p)
- return VNET_API_ERROR_NO_SUCH_FIB;
- fib_index = p[0];
- sm->inside_fib_index = fib_index;
- }
- else
- fib_index = sm->inside_fib_index;
-
+ fib_index = sm->inside_fib_index;
vrf_id = sm->inside_vrf_id;
}
{
a = sm->addresses + i;
/* External port must be unused */
- if (clib_bitmap_get_no_check (a->busy_port_bitmap, e_port))
- return VNET_API_ERROR_INVALID_VALUE;
- clib_bitmap_set_no_check (a->busy_port_bitmap, e_port, 1);
- if (e_port > 1024)
- a->busy_ports++;
-
+ switch (proto)
+ {
+#define _(N, j, n, s) \
+ case SNAT_PROTOCOL_##N: \
+ if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
+ return VNET_API_ERROR_INVALID_VALUE; \
+ clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
+ if (e_port > 1024) \
+ a->busy_##n##_ports++; \
+ break;
+ foreach_snat_protocol
+#undef _
+ default:
+ clib_warning("unknown_protocol");
+ return VNET_API_ERROR_INVALID_VALUE_2;
+ }
break;
}
}
{
m->local_port = l_port;
m->external_port = e_port;
+ m->proto = proto;
}
m_key.addr = m->local_addr;
m_key.port = m->local_port;
+ m_key.protocol = m->proto;
m_key.fib_index = m->fib_index;
kv.key = m_key.as_u64;
kv.value = m - sm->static_mappings;
if (sm->workers)
{
snat_user_key_t w_key0;
- snat_static_mapping_key_t w_key1;
+ snat_worker_key_t w_key1;
w_key0.addr = m->local_addr;
w_key0.fib_index = m->fib_index;
if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
{
a = sm->addresses + i;
- clib_bitmap_set_no_check (a->busy_port_bitmap, e_port, 0);
- a->busy_ports--;
-
+ switch (proto)
+ {
+#define _(N, j, n, s) \
+ case SNAT_PROTOCOL_##N: \
+ clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
+ if (e_port > 1024) \
+ a->busy_##n##_ports--; \
+ break;
+ foreach_snat_protocol
+#undef _
+ default:
+ clib_warning("unknown_protocol");
+ return VNET_API_ERROR_INVALID_VALUE_2;
+ }
break;
}
}
m_key.addr = m->local_addr;
m_key.port = m->local_port;
+ 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 (interface->is_inside)
continue;
- snat_add_del_addr_to_fib(sm, &e_addr, interface->sw_if_index, is_add);
+ snat_add_del_addr_to_fib(&e_addr, interface->sw_if_index, is_add);
+ break;
}));
return 0;
if (m->external_addr.as_u32 == addr.as_u32)
(void) snat_add_static_mapping (m->local_addr, m->external_addr,
m->local_port, m->external_port,
- m->vrf_id, m->addr_only, ~0, 0);
+ m->vrf_id, m->addr_only, ~0,
+ m->proto, 0);
}));
}
else
}
/* Delete sessions using address */
- if (a->busy_ports)
+ if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
{
vec_foreach (tsm, sm->per_thread_data)
{
if (interface->is_inside)
continue;
- snat_add_del_addr_to_fib(sm, &addr, interface->sw_if_index, 0);
+ snat_add_del_addr_to_fib(&addr, interface->sw_if_index, 0);
+ break;
}));
return 0;
return 0;
vec_foreach (ap, sm->addresses)
- snat_add_del_addr_to_fib(sm, &ap->addr, sw_if_index, !is_del);
+ snat_add_del_addr_to_fib(&ap->addr, sw_if_index, !is_del);
pool_foreach (m, sm->static_mappings,
({
if (!(m->addr_only))
continue;
- snat_add_del_addr_to_fib(sm, &m->external_addr, sw_if_index, !is_del);
+ snat_add_del_addr_to_fib(&m->external_addr, sw_if_index, !is_del);
}));
return 0;
u16 local_port = 0, external_port = 0;
u32 vrf_id, external_sw_if_index;
int rv = 0;
+ snat_protocol_t proto;
if (mp->is_ip4 != 1)
{
}
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_snat_proto (mp->protocol);
rv = snat_add_static_mapping(local_addr, external_addr, local_port,
external_port, vrf_id, mp->addr_only,
- external_sw_if_index,
- mp->is_add);
+ external_sw_if_index, proto, mp->is_add);
send_reply:
REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY);
u8 * s;
s = format (0, "SCRIPT: snat_add_static_mapping ");
- s = format (s, "local_addr %U external_addr %U ",
+ s = format (s, "protocol %d local_addr %U external_addr %U ",
+ mp->protocol,
format_ip4_address, mp->local_ip_address,
format_ip4_address, mp->external_ip_address);
clib_memcpy (rmp->external_ip_address, &(m->external_addr), 4);
rmp->local_port = htons (m->local_port);
rmp->external_port = htons (m->external_port);
+ rmp->external_sw_if_index = ~0;
rmp->vrf_id = htonl (m->vrf_id);
+ rmp->protocol = snat_proto_to_ip_proto (m->proto);
+ rmp->context = context;
+
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+send_snat_static_map_resolve_details
+(snat_static_map_resolve_t * m, unix_shared_memory_queue_t * q, u32 context)
+{
+ vl_api_snat_static_mapping_details_t *rmp;
+ snat_main_t * sm = &snat_main;
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ memset (rmp, 0, sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_SNAT_STATIC_MAPPING_DETAILS+sm->msg_id_base);
+ rmp->is_ip4 = 1;
+ rmp->addr_only = m->addr_only;
+ clib_memcpy (rmp->local_ip_address, &(m->l_addr), 4);
+ rmp->local_port = htons (m->l_port);
+ rmp->external_port = htons (m->e_port);
+ rmp->external_sw_if_index = htonl (m->sw_if_index);
+ rmp->vrf_id = htonl (m->vrf_id);
+ rmp->protocol = snat_proto_to_ip_proto (m->proto);
rmp->context = context;
vl_msg_api_send_shmem (q, (u8 *) & rmp);
unix_shared_memory_queue_t *q;
snat_main_t * sm = &snat_main;
snat_static_mapping_t * m;
+ snat_static_map_resolve_t *rp;
+ int j;
q = vl_api_client_index_to_input_queue (mp->client_index);
if (q == 0)
({
send_snat_static_mapping_details (m, q, mp->context);
}));
+
+ for (j = 0; j < vec_len (sm->to_resolve); j++)
+ {
+ rp = sm->to_resolve + j;
+ send_snat_static_map_resolve_details (rp, q, mp->context);
+ }
}
static void *vl_api_snat_static_mapping_dump_t_print
a = sm->addresses + address_index;
- ASSERT (clib_bitmap_get_no_check (a->busy_port_bitmap,
- port_host_byte_order) == 1);
-
- clib_bitmap_set_no_check (a->busy_port_bitmap, port_host_byte_order, 0);
- a->busy_ports--;
+ switch (k->protocol)
+ {
+#define _(N, i, n, s) \
+ case SNAT_PROTOCOL_##N: \
+ ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
+ port_host_byte_order) == 1); \
+ clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
+ port_host_byte_order, 0); \
+ a->busy_##n##_ports--; \
+ break;
+ foreach_snat_protocol
+#undef _
+ default:
+ clib_warning("unknown_protocol");
+ return;
+ }
}
/**
{
clib_bihash_kv_8_8_t kv, value;
snat_static_mapping_t *m;
- snat_static_mapping_key_t m_key;
+ snat_session_key_t m_key;
clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
if (by_external)
m_key.addr = match.addr;
m_key.port = clib_net_to_host_u16 (match.port);
+ m_key.protocol = match.protocol;
m_key.fib_index = match.fib_index;
kv.key = m_key.as_u64;
{
/* Try address only mapping */
m_key.port = 0;
+ m_key.protocol = 0;
kv.key = m_key.as_u64;
if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
return 1;
for (i = 0; i < vec_len (sm->addresses); i++)
{
- if (sm->addresses[i].busy_ports < (65535-1024))
+ a = sm->addresses + i;
+ switch (k->protocol)
{
- a = sm->addresses + i;
-
- while (1)
- {
- portnum = random_u32 (&sm->random_seed);
- portnum &= 0xFFFF;
- if (portnum < 1024)
- continue;
- if (clib_bitmap_get_no_check (a->busy_port_bitmap, portnum))
- continue;
- clib_bitmap_set_no_check (a->busy_port_bitmap, portnum, 1);
- a->busy_ports++;
- /* Caller sets protocol and fib index */
- k->addr = a->addr;
- k->port = clib_host_to_net_u16(portnum);
- *address_indexp = i;
- return 0;
- }
+#define _(N, j, n, s) \
+ case SNAT_PROTOCOL_##N: \
+ if (a->busy_##n##_ports < (65535-1024)) \
+ { \
+ while (1) \
+ { \
+ portnum = random_u32 (&sm->random_seed); \
+ portnum &= 0xFFFF; \
+ if (portnum < 1024) \
+ continue; \
+ if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
+ continue; \
+ clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
+ a->busy_##n##_ports++; \
+ k->addr = a->addr; \
+ k->port = clib_host_to_net_u16(portnum); \
+ *address_indexp = i; \
+ return 0; \
+ } \
+ } \
+ break;
+ foreach_snat_protocol
+#undef _
+ default:
+ clib_warning("unknown protocol");
+ return 1;
}
+
}
/* Totally out of translations to use... */
snat_ipfix_logging_addresses_exhausted(0);
.short_help = "set interface snat in <intfc> out <intfc> [del]",
};
+uword
+unformat_snat_protocol (unformat_input_t * input, va_list * args)
+{
+ u32 *r = va_arg (*args, u32 *);
+
+ if (0);
+#define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
+ foreach_snat_protocol
+#undef _
+ else
+ return 0;
+ return 1;
+}
+
+u8 *
+format_snat_protocol (u8 * s, va_list * args)
+{
+ u32 i = va_arg (*args, u32);
+ u8 *t = 0;
+
+ switch (i)
+ {
+#define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
+ foreach_snat_protocol
+#undef _
+ default:
+ s = format (s, "unknown");
+ }
+ s = format (s, "%s", t);
+ return s;
+}
+
static clib_error_t *
add_static_mapping_command_fn (vlib_main_t * vm,
unformat_input_t * input,
u32 sw_if_index = ~0;
vnet_main_t * vnm = vnet_get_main();
int rv;
+ snat_protocol_t proto;
+ u8 proto_set = 0;
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
;
else if (unformat (line_input, "vrf %u", &vrf_id))
;
+ else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
+ proto_set = 1;
else if (unformat (line_input, "del"))
is_add = 0;
else
}
unformat_free (line_input);
+ if (!addr_only && !proto_set)
+ return clib_error_return (0, "missing protocol");
+
rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
- vrf_id, addr_only, sw_if_index, is_add);
+ vrf_id, addr_only, sw_if_index, proto, is_add);
switch (rv)
{
* Static mapping allows hosts on the external network to initiate connection
* to to the local network host.
* To create static mapping between local host address 10.0.0.3 port 6303 and
- * external address 4.4.4.4 port 3606 use:
- * vpp# snat add static mapping local 10.0.0.3 6303 external 4.4.4.4 3606
+ * external address 4.4.4.4 port 3606 for TCP protocol use:
+ * vpp# snat add static mapping local tcp 10.0.0.3 6303 external 4.4.4.4 3606
* If not runnig "static mapping only" S-NAT plugin mode use before:
* vpp# snat add address 4.4.4.4
* To create static mapping between local and external address use:
.path = "snat add static mapping",
.function = add_static_mapping_command_fn,
.short_help =
- "snat add static mapping local <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
+ "snat add static mapping local tcp|udp|icmp <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
};
static clib_error_t *
sm->user_memory_size = user_memory_size;
sm->max_translations_per_user = max_translations_per_user;
sm->outside_vrf_id = outside_vrf_id;
- sm->outside_fib_index = ~0;
+ sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
+ outside_vrf_id);
sm->inside_vrf_id = inside_vrf_id;
- sm->inside_fib_index = ~0;
+ sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
+ inside_vrf_id);
sm->static_mapping_only = static_mapping_only;
sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
format_ip4_address, &m->external_addr,
m->vrf_id);
else
- s = format (s, "local %U:%d external %U:%d vrf %d",
+ s = format (s, "%U local %U:%d external %U:%d vrf %d",
+ 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);
return s;
}
+u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
+{
+ snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
+ vnet_main_t *vnm = vnet_get_main();
+
+ if (m->addr_only)
+ s = format (s, "local %U external %U vrf %d",
+ format_ip4_address, &m->l_addr,
+ format_vnet_sw_interface_name, vnm,
+ vnet_get_sw_interface (vnm, m->sw_if_index),
+ m->vrf_id);
+ else
+ s = format (s, "%U local %U:%d external %U:%d vrf %d",
+ format_snat_protocol, m->proto,
+ format_ip4_address, &m->l_addr, m->l_port,
+ format_vnet_sw_interface_name, vnm,
+ vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port,
+ m->vrf_id);
+
+ return s;
+}
+
static clib_error_t *
show_snat_command_fn (vlib_main_t * vm,
unformat_input_t * input,
snat_main_per_thread_data_t *tsm;
u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
uword j = 0;
+ snat_static_map_resolve_t *rp;
if (unformat (input, "detail"))
verbose = 1;
vec_foreach (ap, sm->addresses)
{
- u8 * s = format (0, "");
vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
- clib_bitmap_foreach (j, ap->busy_port_bitmap,
- ({
- s = format (s, " %d", j);
- }));
- vlib_cli_output (vm, " %d busy ports:%s", ap->busy_ports, s);
+#define _(N, i, n, s) \
+ vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
+ foreach_snat_protocol
+#undef _
}
}
}));
}
- if (pool_elts (sm->static_mappings))
+ if (pool_elts (sm->static_mappings) || vec_len (sm->to_resolve))
{
vlib_cli_output (vm, "static mappings:");
pool_foreach (m, sm->static_mappings,
({
vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
}));
+ for (j = 0; j < vec_len (sm->to_resolve); j++)
+ {
+ rp = sm->to_resolve + j;
+ vlib_cli_output (vm, "%U", format_snat_static_map_to_resolve,
+ rp);
+ }
}
}
}
rp->vrf_id,
rp->addr_only,
~0 /* sw_if_index */,
+ rp->proto,
rp->is_add);
if (rv)
clib_warning ("snat_add_static_mapping returned %d",