aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/snat/snat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/snat/snat.c')
-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;
}