#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;
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))
{
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);
rmp->local_port = htons (m->local_port);
rmp->external_port = htons (m->external_port);
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);
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;
/* 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))
+ ;
else if (unformat (line_input, "del"))
is_add = 0;
else
unformat_free (line_input);
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)
{
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);
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 _
}
}
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",