summaryrefslogtreecommitdiffstats
path: root/src/plugins/snat
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2017-01-27 00:47:58 -0800
committerOle Trøan <otroan@employees.org>2017-01-31 18:47:47 +0000
commite1ae29a3f7a7bd79bb266803982fd0259b040922 (patch)
tree88f07c8d4377f8c00d4925db98d170f7eea5160b /src/plugins/snat
parentd9b74a964458ed31e7acb567a5f40259c671025a (diff)
SNAT: Add outbound addresses to FIB (VPP-613)
Add the external NAT address to the FIB as receive entries. This ensures that VPP will reply to ARP for these addresses and we don't need to enable proxy ARP on the outside interface. Change-Id: I1db153373c43fec4808845449a17085509ca588c Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'src/plugins/snat')
-rw-r--r--src/plugins/snat/snat.c111
1 files changed, 110 insertions, 1 deletions
diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c
index fb566598730..6149411887a 100644
--- a/src/plugins/snat/snat.c
+++ b/src/plugins/snat/snat.c
@@ -22,6 +22,8 @@
#include <vlibapi/api.h>
#include <snat/snat.h>
#include <snat/snat_ipfix_logging.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/fib/ip4_fib.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
@@ -211,9 +213,66 @@ bad_tx_sw_if_index: \
#endif /* CLIB_DEBUG > 0 */
+/**
+ * @brief Add/del NAT address to FIB.
+ *
+ * Add the external NAT address to the FIB as receive entries. This ensures
+ * 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)
+{
+ 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,
+ .fp_addr = {
+ .ip4.as_u32 = addr->as_u32,
+ },
+ };
+ 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_ENTRY_FLAG_CONNECTED |
+ FIB_ENTRY_FLAG_LOCAL |
+ FIB_ENTRY_FLAG_EXCLUSIVE),
+ FIB_PROTOCOL_IP4,
+ NULL,
+ sw_if_index,
+ ~0,
+ 1,
+ NULL,
+ FIB_ROUTE_PATH_FLAG_NONE);
+ else
+ fib_table_entry_delete(fib_index,
+ &prefix,
+ FIB_SOURCE_INTERFACE);
+}
+
void snat_add_address (snat_main_t *sm, ip4_address_t *addr)
{
snat_address_t * ap;
+ snat_interface_t *i;
/* Check if address already exists */
vec_foreach (ap, sm->addresses)
@@ -225,6 +284,15 @@ 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);
+
+ /* 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);
+ }));
}
static int is_snat_address_used_in_static_mapping (snat_main_t *sm,
@@ -297,6 +365,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
snat_address_t *a = 0;
u32 fib_index = ~0;
uword * p;
+ snat_interface_t *interface;
int i;
/* If outside FIB index is not resolved yet */
@@ -561,6 +630,18 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
pool_put (sm->static_mappings, m);
}
+ if (!addr_only)
+ return 0;
+
+ /* Add/delete external address to FIB */
+ pool_foreach (interface, sm->interfaces,
+ ({
+ if (interface->is_inside)
+ continue;
+
+ snat_add_del_addr_to_fib(sm, &e_addr, interface->sw_if_index, is_add);
+ }));
+
return 0;
}
@@ -574,6 +655,7 @@ int snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm)
snat_user_t *u;
snat_main_per_thread_data_t *tsm;
snat_static_mapping_t *m;
+ snat_interface_t *interface;
int i;
/* Find SNAT address */
@@ -649,6 +731,15 @@ int snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm)
vec_del1 (sm->addresses, i);
+ /* Delete external address from FIB */
+ pool_foreach (interface, sm->interfaces,
+ ({
+ if (interface->is_inside)
+ continue;
+
+ snat_add_del_addr_to_fib(sm, &addr, interface->sw_if_index, 0);
+ }));
+
return 0;
}
@@ -657,6 +748,8 @@ static int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
snat_main_t *sm = &snat_main;
snat_interface_t *i;
const char * feature_name;
+ snat_address_t * ap;
+ snat_static_mapping_t * m;
if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
feature_name = is_inside ? "snat-in2out-fast" : "snat-out2in-fast";
@@ -686,7 +779,7 @@ static int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
else
return VNET_API_ERROR_VALUE_EXIST;
- return 0;
+ goto fib;
}
}));
@@ -697,6 +790,22 @@ static int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
i->sw_if_index = sw_if_index;
i->is_inside = is_inside;
+ /* Add/delete external addresses to FIB */
+fib:
+ if (is_inside)
+ return 0;
+
+ vec_foreach (ap, sm->addresses)
+ snat_add_del_addr_to_fib(sm, &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);
+ }));
+
return 0;
}