(sm, &s->out2in, s->outside_address_index);
s->outside_address_index = ~0;
- if (snat_alloc_outside_address_and_port (sm, &key1, &address_index))
+ if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, &key1,
+ &address_index))
{
ASSERT(0);
{
static_mapping = 0;
/* Try to create dynamic translation */
- if (snat_alloc_outside_address_and_port (sm, &key1, &address_index))
+ if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, &key1,
+ &address_index))
{
b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
return SNAT_IN2OUT_NEXT_DROP;
@param is_ip4 - 1 if address type is IPv4
@param first_ip_address - first IP address
@param last_ip_address - last IP address
+ @param vrf_id - VRF id of tenant, ~0 means independent of VRF
@param is_add - 1 if add, 0 if delete
*/
define snat_add_address_range {
u8 is_ip4;
u8 first_ip_address[16];
u8 last_ip_address[16];
+ u32 vrf_id;
u8 is_add;
};
@param context - sender context, to match reply w/ request
@param is_ip4 - 1 if address type is IPv4
@param ip_address - IP address
+ @param vrf_id - VRF id of tenant, ~0 means independent of VRF
*/
define snat_address_details {
u32 context;
u8 is_ip4;
u8 ip_address[16];
+ u32 vrf_id;
};
/** \brief Enable/disable S-NAT feature on the interface
FIB_SOURCE_PLUGIN_HI);
}
-void snat_add_address (snat_main_t *sm, ip4_address_t *addr)
+void snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id)
{
snat_address_t * ap;
snat_interface_t *i;
+ if (vrf_id != ~0)
+ sm->vrf_mode = 1;
+
/* Check if address already exists */
vec_foreach (ap, sm->addresses)
{
vec_add2 (sm->addresses, ap, 1);
ap->addr = *addr;
+ ap->fib_index = ip4_fib_index_from_table_id(vrf_id);
#define _(N, i, n, s) \
clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535);
foreach_snat_protocol
vl_api_snat_add_address_range_reply_t * rmp;
ip4_address_t this_addr;
u32 start_host_order, end_host_order;
+ u32 vrf_id;
int i, count;
int rv = 0;
u32 * tmp;
count = (end_host_order - start_host_order) + 1;
+ vrf_id = clib_host_to_net_u32 (mp->vrf_id);
+
if (count > 1024)
clib_warning ("%U - %U, %d addresses...",
format_ip4_address, mp->first_ip_address,
for (i = 0; i < count; i++)
{
if (mp->is_add)
- snat_add_address (sm, &this_addr);
+ snat_add_address (sm, &this_addr, vrf_id);
else
rv = snat_del_address (sm, this_addr, 0);
rmp->_vl_msg_id = ntohs (VL_API_SNAT_ADDRESS_DETAILS+sm->msg_id_base);
rmp->is_ip4 = 1;
clib_memcpy (rmp->ip_address, &(a->addr), 4);
+ if (a->fib_index != ~0)
+ rmp->vrf_id = ntohl(ip4_fib_get(a->fib_index)->table_id);
+ else
+ rmp->vrf_id = ~0;
rmp->context = context;
vl_msg_api_send_shmem (q, (u8 *) & rmp);
}
int snat_alloc_outside_address_and_port (snat_main_t * sm,
+ u32 fib_index,
snat_session_key_t * k,
u32 * address_indexp)
{
for (i = 0; i < vec_len (sm->addresses); i++)
{
a = sm->addresses + i;
+ if (sm->vrf_mode && a->fib_index != ~0 && a->fib_index != fib_index)
+ continue;
switch (k->protocol)
{
#define _(N, j, n, s) \
snat_main_t * sm = &snat_main;
ip4_address_t start_addr, end_addr, this_addr;
u32 start_host_order, end_host_order;
+ u32 vrf_id = ~0;
int i, count;
int is_add = 1;
int rv = 0;
unformat_ip4_address, &start_addr,
unformat_ip4_address, &end_addr))
;
+ else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
+ ;
else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
end_addr = start_addr;
else if (unformat (line_input, "del"))
for (i = 0; i < count; i++)
{
if (is_add)
- snat_add_address (sm, &this_addr);
+ snat_add_address (sm, &this_addr, vrf_id);
else
rv = snat_del_address (sm, this_addr, 0);
VLIB_CLI_COMMAND (add_address_command, static) = {
.path = "snat add address",
- .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>] [del]",
+ .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>] "
+ "[tenant-vrf <vrf-id>] [del]",
.function = add_address_command_fn,
};
vec_foreach (ap, sm->addresses)
{
vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
+ if (ap->fib_index != ~0)
+ vlib_cli_output (vm, " tenant VRF: %u",
+ ip4_fib_get(ap->fib_index)->table_id);
+ else
+ vlib_cli_output (vm, " tenant VRF independent");
#define _(N, i, n, s) \
vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
foreach_snat_protocol
if (sm->addresses[j].addr.as_u32 == address->as_u32)
return;
- snat_add_address (sm, address);
+ snat_add_address (sm, address, ~0);
/* Scan static map resolution vector */
for (j = 0; j < vec_len (sm->to_resolve); j++)
{
/* If the address is already bound - or static - add it now */
if (first_int_addr)
- snat_add_address (sm, first_int_addr);
+ snat_add_address (sm, first_int_addr, ~0);
return 0;
}
typedef struct {
ip4_address_t addr;
+ u32 fib_index;
#define _(N, i, n, s) \
u32 busy_##n##_ports; \
uword * busy_##n##_port_bitmap;
u32 inside_vrf_id;
u32 inside_fib_index;
+ /* tenant VRF aware address pool activation flag */
+ u8 vrf_mode;
+
/* API message ID base */
u16 msg_id_base;
u32 address_index);
int snat_alloc_outside_address_and_port (snat_main_t * sm,
+ u32 fib_index,
snat_session_key_t * k,
u32 * address_indexp);
proto,
is_add)
- def snat_add_address(self, ip, is_add=1):
+ def snat_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF):
"""
Add/delete S-NAT address
:param is_add: 1 if add, 0 if delete (Default add)
"""
snat_addr = socket.inet_pton(socket.AF_INET, ip)
- self.vapi.snat_add_address_range(snat_addr, snat_addr, is_add)
+ self.vapi.snat_add_address_range(snat_addr, snat_addr, is_add,
+ vrf_id=vrf_id)
def test_dynamic(self):
""" SNAT dynamic translation test """
self.pg_start()
capture = self.pg1.get_capture(0)
+ def test_vrf_mode(self):
+ """ S-NAT tenant VRF aware address pool mode """
+
+ vrf_id1 = 1
+ vrf_id2 = 2
+ nat_ip1 = "10.0.0.10"
+ nat_ip2 = "10.0.0.11"
+
+ self.pg0.unconfig_ip4()
+ self.pg1.unconfig_ip4()
+ self.pg0.set_table_ip4(vrf_id1)
+ self.pg1.set_table_ip4(vrf_id2)
+ self.pg0.config_ip4()
+ self.pg1.config_ip4()
+
+ self.snat_add_address(nat_ip1, vrf_id=vrf_id1)
+ self.snat_add_address(nat_ip2, vrf_id=vrf_id2)
+ self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
+ self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index)
+ self.vapi.snat_interface_add_del_feature(self.pg2.sw_if_index,
+ is_inside=0)
+
+ # first VRF
+ pkts = self.create_stream_in(self.pg0, self.pg2)
+ self.pg0.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ capture = self.pg2.get_capture(len(pkts))
+ self.verify_capture_out(capture, nat_ip1)
+
+ # second VRF
+ pkts = self.create_stream_in(self.pg1, self.pg2)
+ self.pg1.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ capture = self.pg2.get_capture(len(pkts))
+ self.verify_capture_out(capture, nat_ip2)
+
+ def test_vrf_feature_independent(self):
+ """ S-NAT tenant VRF independent address pool mode """
+
+ nat_ip1 = "10.0.0.10"
+ nat_ip2 = "10.0.0.11"
+
+ self.snat_add_address(nat_ip1)
+ self.snat_add_address(nat_ip2)
+ self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index)
+ self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index)
+ self.vapi.snat_interface_add_del_feature(self.pg2.sw_if_index,
+ is_inside=0)
+
+ # first VRF
+ pkts = self.create_stream_in(self.pg0, self.pg2)
+ self.pg0.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ capture = self.pg2.get_capture(len(pkts))
+ self.verify_capture_out(capture, nat_ip1)
+
+ # second VRF
+ pkts = self.create_stream_in(self.pg1, self.pg2)
+ self.pg1.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ capture = self.pg2.get_capture(len(pkts))
+ self.verify_capture_out(capture, nat_ip1)
+
def tearDown(self):
super(TestSNAT, self).tearDown()
if not self.vpp_dead:
first_ip_address,
last_ip_address,
is_add=1,
- is_ip4=1):
+ is_ip4=1,
+ vrf_id=0xFFFFFFFF):
"""Add/del S-NAT address range
:param first_ip_address: First IP address
:param last_ip_address: Last IP address
+ :param vrf_id: VRF id for the address range
:param is_add: 1 if add, 0 if delete (Default value = 1)
:param is_ip4: 1 if address type is IPv4 (Default value = 1)
"""
{'is_ip4': is_ip4,
'first_ip_address': first_ip_address,
'last_ip_address': last_ip_address,
+ 'vrf_id': vrf_id,
'is_add': is_add})
def snat_address_dump(self):