cnat: Add DHCP support
Type: feature Change-Id: I4bd50fd672ac35cf14ebda2b0b10ec0b9a208628 Signed-off-by: Nathan Skrzypczak <nathan.skrzypczak@gmail.com>
This commit is contained in:
Nathan Skrzypczak
committed by
Dave Barach
parent
ce25b60de5
commit
af897c5e3f
@ -22,15 +22,21 @@
|
||||
option version = "0.1.0";
|
||||
import "vnet/ip/ip_types.api";
|
||||
import "vnet/fib/fib_types.api";
|
||||
import "vnet/interface_types.api";
|
||||
|
||||
enum cnat_translation_flags:u8
|
||||
{
|
||||
CNAT_TRANSLATION_ALLOC_PORT = 1,
|
||||
};
|
||||
|
||||
/* An enpoint is either
|
||||
* An IP & a port
|
||||
* An interface, an address familiy and a port */
|
||||
typedef cnat_endpoint
|
||||
{
|
||||
vl_api_address_t addr;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
vl_api_address_family_t if_af;
|
||||
u16 port;
|
||||
};
|
||||
|
||||
@ -117,6 +123,23 @@ autoreply define cnat_set_snat_addresses
|
||||
u32 context;
|
||||
vl_api_ip4_address_t snat_ip4;
|
||||
vl_api_ip6_address_t snat_ip6;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
};
|
||||
|
||||
define cnat_get_snat_addresses
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
};
|
||||
|
||||
define cnat_get_snat_addresses_reply
|
||||
{
|
||||
u32 context;
|
||||
i32 retval;
|
||||
u32 id;
|
||||
vl_api_ip4_address_t snat_ip4;
|
||||
vl_api_ip6_address_t snat_ip6;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
};
|
||||
|
||||
autoreply define cnat_add_del_snat_prefix
|
||||
|
@ -47,8 +47,13 @@ static void
|
||||
cnat_endpoint_decode (const vl_api_cnat_endpoint_t * in,
|
||||
cnat_endpoint_t * out)
|
||||
{
|
||||
ip_address_decode2 (&in->addr, &out->ce_ip);
|
||||
out->ce_port = clib_net_to_host_u16 (in->port);
|
||||
out->ce_sw_if_index = clib_net_to_host_u32 (in->sw_if_index);
|
||||
out->ce_flags = 0;
|
||||
if (out->ce_sw_if_index == INDEX_INVALID)
|
||||
ip_address_decode2 (&in->addr, &out->ce_ip);
|
||||
else
|
||||
ip_address_family_decode (in->if_af, &out->ce_ip.version);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -63,8 +68,13 @@ static void
|
||||
cnat_endpoint_encode (const cnat_endpoint_t * in,
|
||||
vl_api_cnat_endpoint_t * out)
|
||||
{
|
||||
ip_address_encode2 (&in->ce_ip, &out->addr);
|
||||
out->port = clib_net_to_host_u16 (in->ce_port);
|
||||
out->sw_if_index = clib_net_to_host_u32 (in->ce_sw_if_index);
|
||||
out->if_af = ip_address_family_encode (in->ce_ip.version);
|
||||
if (in->ce_flags & CNAT_EP_FLAG_RESOLVED)
|
||||
ip_address_encode2 (&in->ce_ip, &out->addr);
|
||||
else
|
||||
clib_memset ((void *) &in->ce_ip, 0, sizeof (in->ce_ip));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -258,17 +268,37 @@ vl_api_cnat_session_purge_t_handler (vl_api_cnat_session_purge_t * mp)
|
||||
REPLY_MACRO (VL_API_CNAT_SESSION_PURGE_REPLY);
|
||||
}
|
||||
|
||||
static void
|
||||
vl_api_cnat_get_snat_addresses_t_handler (vl_api_cnat_get_snat_addresses_t
|
||||
* mp)
|
||||
{
|
||||
vl_api_cnat_get_snat_addresses_reply_t *rmp;
|
||||
int rv = 0;
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
REPLY_MACRO2 (VL_API_CNAT_GET_SNAT_ADDRESSES_REPLY,
|
||||
({
|
||||
ip6_address_encode (&ip_addr_v6(&cnat_main.snat_ip6.ce_ip), rmp->snat_ip6);
|
||||
ip4_address_encode (&ip_addr_v4(&cnat_main.snat_ip4.ce_ip), rmp->snat_ip4);
|
||||
rmp->sw_if_index = clib_host_to_net_u32 (cnat_main.snat_ip6.ce_sw_if_index);
|
||||
}));
|
||||
/* *INDENT-ON* */
|
||||
}
|
||||
|
||||
static void
|
||||
vl_api_cnat_set_snat_addresses_t_handler (vl_api_cnat_set_snat_addresses_t
|
||||
* mp)
|
||||
{
|
||||
vl_api_cnat_set_snat_addresses_reply_t *rmp;
|
||||
u32 sw_if_index = clib_net_to_host_u32 (mp->sw_if_index);
|
||||
ip4_address_t ip4;
|
||||
ip6_address_t ip6;
|
||||
int rv = 0;
|
||||
|
||||
cnat_lazy_init ();
|
||||
ip4_address_decode (mp->snat_ip4, &ip4);
|
||||
ip6_address_decode (mp->snat_ip6, &ip6);
|
||||
|
||||
ip4_address_decode (mp->snat_ip4, &cnat_main.snat_ip4);
|
||||
ip6_address_decode (mp->snat_ip6, &cnat_main.snat_ip6);
|
||||
cnat_set_snat (&ip4, &ip6, sw_if_index);
|
||||
|
||||
REPLY_MACRO (VL_API_CNAT_SET_SNAT_ADDRESSES_REPLY);
|
||||
}
|
||||
|
@ -48,7 +48,6 @@ cnat_client_destroy (cnat_client_t * cc)
|
||||
{
|
||||
ASSERT (fib_entry_is_sourced (cc->cc_fei, cnat_fib_source));
|
||||
fib_table_entry_delete_index (cc->cc_fei, cnat_fib_source);
|
||||
ASSERT (!fib_entry_is_sourced (cc->cc_fei, cnat_fib_source));
|
||||
}
|
||||
cnat_client_db_remove (cc);
|
||||
dpo_reset (&cc->cc_parent);
|
||||
@ -110,6 +109,9 @@ void
|
||||
cnat_client_translation_added (index_t cci)
|
||||
{
|
||||
cnat_client_t *cc;
|
||||
if (INDEX_INVALID == cci)
|
||||
return;
|
||||
|
||||
cc = cnat_client_get (cci);
|
||||
ASSERT (!(cc->flags & CNAT_FLAG_EXPIRES));
|
||||
cc->tr_refcnt++;
|
||||
@ -119,6 +121,8 @@ void
|
||||
cnat_client_translation_deleted (index_t cci)
|
||||
{
|
||||
cnat_client_t *cc;
|
||||
if (INDEX_INVALID == cci)
|
||||
return;
|
||||
|
||||
cc = cnat_client_get (cci);
|
||||
ASSERT (!(cc->flags & CNAT_FLAG_EXPIRES));
|
||||
|
@ -121,14 +121,14 @@ cnat_snat_inline (vlib_main_t * vm,
|
||||
if (AF_IP4 == ctx->af)
|
||||
{
|
||||
ip46_address_set_ip4 (&session->value.cs_ip[VLIB_RX],
|
||||
&cm->snat_ip4);
|
||||
&ip_addr_v4 (&cm->snat_ip4.ce_ip));
|
||||
ip46_address_set_ip4 (&session->value.cs_ip[VLIB_TX],
|
||||
&ip4->dst_address);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip46_address_set_ip6 (&session->value.cs_ip[VLIB_RX],
|
||||
&cm->snat_ip6);
|
||||
&ip_addr_v6 (&cm->snat_ip6.ce_ip));
|
||||
ip46_address_set_ip6 (&session->value.cs_ip[VLIB_TX],
|
||||
&ip6->dst_address);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include <vnet/ip/ip.h>
|
||||
#include <cnat/cnat_snat.h>
|
||||
#include <cnat/cnat_translation.h>
|
||||
|
||||
static void
|
||||
cnat_compute_prefix_lengths_in_search_order (cnat_snat_pfx_table_t *
|
||||
@ -157,13 +158,36 @@ format_cnat_snat_prefix (u8 * s, va_list * args)
|
||||
return (s);
|
||||
}
|
||||
|
||||
void
|
||||
cnat_set_snat (ip4_address_t * ip4, ip6_address_t * ip6, u32 sw_if_index)
|
||||
{
|
||||
cnat_lazy_init ();
|
||||
|
||||
cnat_translation_unwatch_addr (INDEX_INVALID, CNAT_RESOLV_ADDR_SNAT);
|
||||
|
||||
ip_address_set (&cnat_main.snat_ip4.ce_ip, ip4, AF_IP4);
|
||||
ip_address_set (&cnat_main.snat_ip6.ce_ip, ip6, AF_IP6);
|
||||
cnat_main.snat_ip4.ce_sw_if_index = sw_if_index;
|
||||
cnat_main.snat_ip6.ce_sw_if_index = sw_if_index;
|
||||
|
||||
cnat_resolve_ep (&cnat_main.snat_ip4);
|
||||
cnat_resolve_ep (&cnat_main.snat_ip6);
|
||||
cnat_translation_watch_addr (INDEX_INVALID, 0, &cnat_main.snat_ip4,
|
||||
CNAT_RESOLV_ADDR_SNAT);
|
||||
cnat_translation_watch_addr (INDEX_INVALID, 0, &cnat_main.snat_ip6,
|
||||
CNAT_RESOLV_ADDR_SNAT);
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
cnat_set_snat (vlib_main_t * vm,
|
||||
unformat_input_t * input, vlib_cli_command_t * cmd)
|
||||
cnat_set_snat_cli (vlib_main_t * vm,
|
||||
unformat_input_t * input, vlib_cli_command_t * cmd)
|
||||
{
|
||||
unformat_input_t _line_input, *line_input = &_line_input;
|
||||
vnet_main_t *vnm = vnet_get_main ();
|
||||
ip4_address_t ip4 = { {0} };
|
||||
ip6_address_t ip6 = { {0} };
|
||||
clib_error_t *e = 0;
|
||||
ip_address_t addr;
|
||||
u32 sw_if_index = INDEX_INVALID;
|
||||
|
||||
cnat_lazy_init ();
|
||||
|
||||
@ -173,15 +197,13 @@ cnat_set_snat (vlib_main_t * vm,
|
||||
|
||||
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
|
||||
{
|
||||
if (unformat (line_input, "%U", unformat_ip_address, &addr))
|
||||
{
|
||||
if (ip_addr_version (&addr) == AF_IP4)
|
||||
clib_memcpy (&cnat_main.snat_ip4, &ip_addr_v4 (&addr),
|
||||
sizeof (ip4_address_t));
|
||||
else
|
||||
clib_memcpy (&cnat_main.snat_ip6, &ip_addr_v6 (&addr),
|
||||
sizeof (ip6_address_t));
|
||||
}
|
||||
if (unformat_user (line_input, unformat_ip4_address, &ip4))
|
||||
;
|
||||
else if (unformat_user (line_input, unformat_ip6_address, &ip6))
|
||||
;
|
||||
else if (unformat_user (line_input, unformat_vnet_sw_interface,
|
||||
vnm, &sw_if_index))
|
||||
;
|
||||
else
|
||||
{
|
||||
e = clib_error_return (0, "unknown input '%U'",
|
||||
@ -190,6 +212,8 @@ cnat_set_snat (vlib_main_t * vm,
|
||||
}
|
||||
}
|
||||
|
||||
cnat_set_snat (&ip4, &ip6, sw_if_index);
|
||||
|
||||
done:
|
||||
unformat_free (line_input);
|
||||
|
||||
@ -200,8 +224,8 @@ done:
|
||||
VLIB_CLI_COMMAND (cnat_set_snat_command, static) =
|
||||
{
|
||||
.path = "cnat snat with",
|
||||
.short_help = "cnat snat with [<ip4-address>][<ip6-address>]",
|
||||
.function = cnat_set_snat,
|
||||
.short_help = "cnat snat with [<ip4-address>][<ip6-address>][sw_if_index]",
|
||||
.function = cnat_set_snat_cli,
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
@ -252,8 +276,8 @@ cnat_show_snat (vlib_main_t * vm,
|
||||
{
|
||||
cnat_snat_pfx_table_t *table = &cnat_main.snat_pfx_table;
|
||||
vlib_cli_output (vm, "Source NAT\nip4: %U\nip6: %U\n",
|
||||
format_ip4_address, &cnat_main.snat_ip4,
|
||||
format_ip6_address, &cnat_main.snat_ip6);
|
||||
format_cnat_endpoint, &cnat_main.snat_ip4,
|
||||
format_cnat_endpoint, &cnat_main.snat_ip6);
|
||||
vlib_cli_output (vm, "Prefixes:\n%U\n",
|
||||
format_bihash_24_8, &table->ip_hash, 1);
|
||||
return (NULL);
|
||||
|
@ -18,6 +18,9 @@
|
||||
|
||||
#include <cnat/cnat_types.h>
|
||||
|
||||
|
||||
extern void cnat_set_snat (ip4_address_t * ip4, ip6_address_t * ip6,
|
||||
u32 sw_if_index);
|
||||
extern int cnat_add_snat_prefix (ip_prefix_t * pfx);
|
||||
extern int cnat_del_snat_prefix (ip_prefix_t * pfx);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -49,6 +49,11 @@ typedef struct cnat_ep_trk_t_
|
||||
* The forwarding contributed by the entry
|
||||
*/
|
||||
dpo_id_t ct_dpo;
|
||||
|
||||
/**
|
||||
* Allows to disable if not resolved yet
|
||||
*/
|
||||
u8 is_active;
|
||||
} cnat_ep_trk_t;
|
||||
|
||||
typedef enum cnat_translation_flag_t_
|
||||
@ -56,6 +61,43 @@ typedef enum cnat_translation_flag_t_
|
||||
CNAT_TRANSLATION_FLAG_ALLOCATE_PORT = (1 << 0),
|
||||
} cnat_translation_flag_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CNAT_RESOLV_ADDR_ANY,
|
||||
CNAT_RESOLV_ADDR_BACKEND,
|
||||
CNAT_RESOLV_ADDR_SNAT,
|
||||
CNAT_RESOLV_ADDR_TRANSLATION,
|
||||
CNAT_ADDR_N_RESOLUTIONS,
|
||||
} cnat_addr_resol_type_t;
|
||||
|
||||
/**
|
||||
* Entry used to account for a translation's backend
|
||||
* waiting for address resolution
|
||||
*/
|
||||
typedef struct addr_resolution_t_
|
||||
{
|
||||
/**
|
||||
* The interface index to resolve
|
||||
*/
|
||||
u32 sw_if_index;
|
||||
/**
|
||||
* ip4 or ip6 resolution
|
||||
*/
|
||||
ip_address_family_t af;
|
||||
/**
|
||||
* The cnat_addr_resolution_t
|
||||
*/
|
||||
cnat_addr_resol_type_t type;
|
||||
/**
|
||||
* Translation index
|
||||
*/
|
||||
index_t cti;
|
||||
/**
|
||||
* Callback data
|
||||
*/
|
||||
u64 opaque;
|
||||
} addr_resolution_t;
|
||||
|
||||
/**
|
||||
* A Translation represents the translation of a VEP to one of a set
|
||||
* of real server addresses
|
||||
@ -89,6 +131,7 @@ typedef struct cnat_translation_t_
|
||||
|
||||
/**
|
||||
* The client object this translation belongs on
|
||||
* INDEX_INVALID if vip is unresolved
|
||||
*/
|
||||
index_t ct_cci;
|
||||
|
||||
@ -116,32 +159,11 @@ extern u8 *format_cnat_translation (u8 * s, va_list * args);
|
||||
*
|
||||
* @return the ID of the translation. used to delete and gather stats
|
||||
*/
|
||||
extern u32 cnat_translation_update (const cnat_endpoint_t * vip,
|
||||
extern u32 cnat_translation_update (cnat_endpoint_t * vip,
|
||||
ip_protocol_t ip_proto,
|
||||
const cnat_endpoint_tuple_t *
|
||||
cnat_endpoint_tuple_t *
|
||||
backends, u8 flags);
|
||||
|
||||
/**
|
||||
* Add a translation to the bihash
|
||||
*
|
||||
* @param cci the ID of the parent client
|
||||
* @param port the translation port
|
||||
* @param proto the translation proto
|
||||
* @param cti the translation index to be used as value
|
||||
*/
|
||||
extern void cnat_add_translation_to_db (index_t cci, u16 port,
|
||||
ip_protocol_t proto, index_t cti);
|
||||
|
||||
/**
|
||||
* Remove a translation from the bihash
|
||||
*
|
||||
* @param cci the ID of the parent client
|
||||
* @param port the translation port
|
||||
* @param proto the translation proto
|
||||
*/
|
||||
extern void cnat_remove_translation_from_db (index_t cci, u16 port,
|
||||
ip_protocol_t proto);
|
||||
|
||||
/**
|
||||
* Delete a translation
|
||||
*
|
||||
@ -164,6 +186,19 @@ extern void cnat_translation_walk (cnat_translation_walk_cb_t cb, void *ctx);
|
||||
*/
|
||||
extern int cnat_translation_purge (void);
|
||||
|
||||
/**
|
||||
* Add an address resolution request
|
||||
*/
|
||||
extern void cnat_translation_watch_addr (index_t cti, u64 opaque,
|
||||
cnat_endpoint_t * ep,
|
||||
cnat_addr_resol_type_t type);
|
||||
|
||||
/**
|
||||
* Cleanup matching addr resolution requests
|
||||
*/
|
||||
extern void cnat_translation_unwatch_addr (u32 cti,
|
||||
cnat_addr_resol_type_t type);
|
||||
|
||||
/*
|
||||
* Data plane functions
|
||||
*/
|
||||
@ -182,7 +217,7 @@ cnat_find_translation (index_t cti, u16 port, ip_protocol_t proto)
|
||||
u64 key;
|
||||
int rv;
|
||||
|
||||
key = (proto << 16) | port;
|
||||
key = (proto << 24) | port;
|
||||
key = key << 32 | (u32) cti;
|
||||
|
||||
bkey.key = key;
|
||||
|
@ -26,17 +26,75 @@ char *cnat_error_strings[] = {
|
||||
#undef cnat_error
|
||||
};
|
||||
|
||||
u8
|
||||
cnat_resolve_addr (u32 sw_if_index, ip_address_family_t af,
|
||||
ip_address_t * addr)
|
||||
{
|
||||
/* Tries to resolve IP from sw_if_index
|
||||
* returns 1 if we need to schedule DHCP */
|
||||
if (INDEX_INVALID == sw_if_index)
|
||||
return 0;
|
||||
if (af == AF_IP6)
|
||||
{
|
||||
ip6_address_t *ip6 = 0;
|
||||
ip6 = ip6_interface_first_address (&ip6_main, sw_if_index);
|
||||
if (ip6)
|
||||
{
|
||||
ip_address_set (addr, ip6, AF_IP6);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ip4_address_t *ip4 = 0;
|
||||
ip4 = ip4_interface_first_address (&ip4_main, sw_if_index, 0);
|
||||
if (ip4)
|
||||
{
|
||||
ip_address_set (addr, ip4, AF_IP4);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
u8
|
||||
cnat_resolve_ep (cnat_endpoint_t * ep)
|
||||
{
|
||||
int rv;
|
||||
rv = cnat_resolve_addr (ep->ce_sw_if_index, ep->ce_ip.version, &ep->ce_ip);
|
||||
if (0 == rv)
|
||||
ep->ce_flags |= CNAT_EP_FLAG_RESOLVED;
|
||||
return rv;
|
||||
}
|
||||
|
||||
uword
|
||||
unformat_cnat_ep (unformat_input_t * input, va_list * args)
|
||||
{
|
||||
cnat_endpoint_t *a = va_arg (*args, cnat_endpoint_t *);
|
||||
vnet_main_t *vnm = vnet_get_main ();
|
||||
int port = 0;
|
||||
|
||||
clib_memset (a, 0, sizeof (*a));
|
||||
a->ce_sw_if_index = INDEX_INVALID;
|
||||
if (unformat (input, "%U %d", unformat_ip_address, &a->ce_ip, &port))
|
||||
;
|
||||
else if (unformat_user (input, unformat_ip_address, &a->ce_ip))
|
||||
;
|
||||
else if (unformat (input, "%U v6 %d", unformat_vnet_sw_interface,
|
||||
vnm, &a->ce_sw_if_index, &port))
|
||||
a->ce_ip.version = AF_IP6;
|
||||
else if (unformat (input, "%U v6", unformat_vnet_sw_interface,
|
||||
vnm, &a->ce_sw_if_index))
|
||||
a->ce_ip.version = AF_IP6;
|
||||
else if (unformat (input, "%U %d", unformat_vnet_sw_interface,
|
||||
vnm, &a->ce_sw_if_index, &port))
|
||||
a->ce_ip.version = AF_IP4;
|
||||
else if (unformat_user (input, unformat_vnet_sw_interface,
|
||||
vnm, &a->ce_sw_if_index))
|
||||
a->ce_ip.version = AF_IP4;
|
||||
else if (unformat (input, "%d", &port))
|
||||
;
|
||||
else
|
||||
@ -65,9 +123,21 @@ u8 *
|
||||
format_cnat_endpoint (u8 * s, va_list * args)
|
||||
{
|
||||
cnat_endpoint_t *cep = va_arg (*args, cnat_endpoint_t *);
|
||||
|
||||
s = format (s, "%U;%d", format_ip_address, &cep->ce_ip, cep->ce_port);
|
||||
|
||||
vnet_main_t *vnm = vnet_get_main ();
|
||||
if (INDEX_INVALID == cep->ce_sw_if_index)
|
||||
s = format (s, "%U;%d", format_ip_address, &cep->ce_ip, cep->ce_port);
|
||||
else
|
||||
{
|
||||
if (cep->ce_flags & CNAT_EP_FLAG_RESOLVED)
|
||||
s = format (s, "%U (%U);%d", format_vnet_sw_if_index_name, vnm,
|
||||
cep->ce_sw_if_index, format_ip_address, &cep->ce_ip,
|
||||
cep->ce_port);
|
||||
else
|
||||
s =
|
||||
format (s, "%U (%U);%d", format_vnet_sw_if_index_name, vnm,
|
||||
cep->ce_sw_if_index, format_ip_address_family,
|
||||
cep->ce_ip.version, cep->ce_port);
|
||||
}
|
||||
return (s);
|
||||
}
|
||||
|
||||
|
@ -49,10 +49,18 @@
|
||||
|
||||
#define MIN_SRC_PORT ((u16) 0xC000)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/* Endpoint addr has been resolved */
|
||||
CNAT_EP_FLAG_RESOLVED = 1,
|
||||
} cnat_ep_flag_t;
|
||||
|
||||
typedef struct cnat_endpoint_t_
|
||||
{
|
||||
ip_address_t ce_ip;
|
||||
u32 ce_sw_if_index;
|
||||
u16 ce_port;
|
||||
u8 ce_flags;
|
||||
} cnat_endpoint_t;
|
||||
|
||||
typedef struct cnat_endpoint_tuple_t_
|
||||
@ -118,10 +126,10 @@ typedef struct cnat_main_
|
||||
clib_rwlock_t ts_lock;
|
||||
|
||||
/* Ip4 Address to use for source NATing */
|
||||
ip4_address_t snat_ip4;
|
||||
cnat_endpoint_t snat_ip4;
|
||||
|
||||
/* Ip6 Address to use for source NATing */
|
||||
ip6_address_t snat_ip6;
|
||||
cnat_endpoint_t snat_ip6;
|
||||
|
||||
/* Longest prefix Match table for source NATing */
|
||||
cnat_snat_pfx_table_t snat_pfx_table;
|
||||
@ -192,6 +200,14 @@ extern void cnat_lazy_init ();
|
||||
*/
|
||||
extern void cnat_enable_disable_scanner (cnat_scanner_cmd_t event_type);
|
||||
|
||||
/**
|
||||
* Resolve endpoint address
|
||||
*/
|
||||
extern u8 cnat_resolve_ep (cnat_endpoint_t * ep);
|
||||
extern u8 cnat_resolve_addr (u32 sw_if_index, ip_address_family_t af,
|
||||
ip_address_t * addr);
|
||||
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
|
@ -3,7 +3,8 @@
|
||||
import unittest
|
||||
|
||||
from framework import VppTestCase, VppTestRunner
|
||||
from vpp_ip import DpoProto
|
||||
from vpp_ip import DpoProto, INVALID_INDEX
|
||||
from itertools import product
|
||||
|
||||
from scapy.packet import Raw
|
||||
from scapy.layers.l2 import Ether
|
||||
@ -23,25 +24,34 @@ from vpp_papi import VppEnum
|
||||
N_PKTS = 15
|
||||
|
||||
|
||||
def find_cnat_translation(test, id):
|
||||
ts = test.vapi.cnat_translation_dump()
|
||||
for t in ts:
|
||||
if id == t.translation.id:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Ep(object):
|
||||
""" CNat endpoint """
|
||||
|
||||
def __init__(self, ip, port, l4p=TCP):
|
||||
def __init__(self, ip=None, port=0, l4p=TCP,
|
||||
sw_if_index=INVALID_INDEX, is_v6=False):
|
||||
self.ip = ip
|
||||
if ip is None:
|
||||
self.ip = "::" if is_v6 else "0.0.0.0"
|
||||
self.port = port
|
||||
self.l4p = l4p
|
||||
self.sw_if_index = sw_if_index
|
||||
if is_v6:
|
||||
self.if_af = VppEnum.vl_api_address_family_t.ADDRESS_IP6
|
||||
else:
|
||||
self.if_af = VppEnum.vl_api_address_family_t.ADDRESS_IP4
|
||||
|
||||
def encode(self):
|
||||
return {'addr': self.ip,
|
||||
'port': self.port}
|
||||
'port': self.port,
|
||||
'sw_if_index': self.sw_if_index,
|
||||
'if_af': self.if_af}
|
||||
|
||||
@classmethod
|
||||
def from_pg(cls, pg, is_v6=False):
|
||||
if pg is None:
|
||||
return cls(is_v6=is_v6)
|
||||
else:
|
||||
return cls(sw_if_index=pg.sw_if_index, is_v6=is_v6)
|
||||
|
||||
@property
|
||||
def isV6(self):
|
||||
@ -77,6 +87,9 @@ class VppCNatTranslation(VppObject):
|
||||
for path in self.paths:
|
||||
self.encoded_paths.append(path.encode())
|
||||
|
||||
def __str__(self):
|
||||
return ("%s %s %s" % (self.vip, self.iproto, self.paths))
|
||||
|
||||
@property
|
||||
def vl4_proto(self):
|
||||
ip_proto = VppEnum.vl_api_ip_proto_t
|
||||
@ -85,9 +98,6 @@ class VppCNatTranslation(VppObject):
|
||||
TCP: ip_proto.IP_API_PROTO_TCP,
|
||||
}[self.iproto]
|
||||
|
||||
def delete(self):
|
||||
r = self._test.vapi.cnat_translation_del(id=self.id)
|
||||
|
||||
def add_vpp_config(self):
|
||||
r = self._test.vapi.cnat_translation_update(
|
||||
{'vip': self.vip.encode(),
|
||||
@ -111,10 +121,13 @@ class VppCNatTranslation(VppObject):
|
||||
self._test.registry.register(self, self._test.logger)
|
||||
|
||||
def remove_vpp_config(self):
|
||||
self._test.vapi.cnat_translation_del(self.id)
|
||||
self._test.vapi.cnat_translation_del(id=self.id)
|
||||
|
||||
def query_vpp_config(self):
|
||||
return find_cnat_translation(self._test, self.id)
|
||||
for t in self._test.vapi.cnat_translation_dump():
|
||||
if self.id == t.translation.id:
|
||||
return t.translation
|
||||
return None
|
||||
|
||||
def object_id(self):
|
||||
return ("cnat-translation-%s" % (self.vip))
|
||||
@ -191,6 +204,7 @@ class TestCNatTranslation(VppTestCase):
|
||||
rxs = self.send_and_expect(self.pg0,
|
||||
p1 * N_PKTS,
|
||||
self.pg1)
|
||||
self.logger.info(self.vapi.cli("show trace max 1"))
|
||||
|
||||
for rx in rxs:
|
||||
self.assert_packet_checksums_valid(rx)
|
||||
@ -352,7 +366,7 @@ class TestCNatTranslation(VppTestCase):
|
||||
n_tries += 1
|
||||
sessions = self.vapi.cnat_session_dump()
|
||||
self.sleep(2)
|
||||
print(self.vapi.cli("show cnat session verbose"))
|
||||
self.logger.info(self.vapi.cli("show cnat session verbose"))
|
||||
|
||||
self.assertTrue(n_tries < 100)
|
||||
self.vapi.cli("test cnat scanner off")
|
||||
@ -374,7 +388,7 @@ class TestCNatTranslation(VppTestCase):
|
||||
self.pg2)
|
||||
|
||||
for tr in trs:
|
||||
tr.delete()
|
||||
tr.remove_vpp_config()
|
||||
|
||||
self.assertTrue(self.vapi.cnat_session_dump())
|
||||
self.vapi.cnat_session_purge()
|
||||
@ -762,10 +776,13 @@ class TestCNatSourceNAT(VppTestCase):
|
||||
l4p(sport=sports[nbr], dport=dports[nbr]) /
|
||||
Raw())
|
||||
|
||||
self.vapi.cli("trace add pg-input 1")
|
||||
rxs = self.send_and_expect(
|
||||
self.pg0,
|
||||
p1 * N_PKTS,
|
||||
self.pg1)
|
||||
self.logger.info(self.vapi.cli("show trace max 1"))
|
||||
|
||||
for rx in rxs:
|
||||
self.assert_packet_checksums_valid(rx)
|
||||
self.assertEqual(rx[IP46].dst, remote_addr)
|
||||
@ -825,5 +842,123 @@ class TestCNatSourceNAT(VppTestCase):
|
||||
self.vapi.cnat_session_purge()
|
||||
|
||||
|
||||
class TestCNatDHCP(VppTestCase):
|
||||
""" CNat Translation """
|
||||
extra_vpp_punt_config = ["cnat", "{",
|
||||
"session-db-buckets", "64",
|
||||
"session-cleanup-timeout", "0.1",
|
||||
"session-max-age", "1",
|
||||
"tcp-max-age", "1",
|
||||
"scanner", "off", "}"]
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestCNatDHCP, cls).setUpClass()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(TestCNatDHCP, cls).tearDownClass()
|
||||
|
||||
def tearDown(self):
|
||||
for i in self.pg_interfaces:
|
||||
i.admin_down()
|
||||
super(TestCNatDHCP, self).tearDown()
|
||||
|
||||
def create_translation(self, vip_pg, *args, is_v6=False):
|
||||
vip = Ep(sw_if_index=vip_pg.sw_if_index, is_v6=is_v6)
|
||||
paths = []
|
||||
for (src_pg, dst_pg) in args:
|
||||
paths.append(EpTuple(
|
||||
Ep.from_pg(src_pg, is_v6=is_v6),
|
||||
Ep.from_pg(dst_pg, is_v6=is_v6)
|
||||
))
|
||||
t1 = VppCNatTranslation(self, TCP, vip, paths)
|
||||
t1.add_vpp_config()
|
||||
return t1
|
||||
|
||||
def make_addr(self, sw_if_index, i, is_v6):
|
||||
if is_v6:
|
||||
return "fd01:%x::%u" % (sw_if_index, i + 1)
|
||||
else:
|
||||
return "172.16.%u.%u" % (sw_if_index, i)
|
||||
|
||||
def make_prefix(self, sw_if_index, i, is_v6):
|
||||
if is_v6:
|
||||
return "%s/128" % self.make_addr(sw_if_index, i, is_v6)
|
||||
else:
|
||||
return "%s/32" % self.make_addr(sw_if_index, i, is_v6)
|
||||
|
||||
def check_resolved(self, tr, vip_pg, *args, i=0, is_v6=False):
|
||||
qt1 = tr.query_vpp_config()
|
||||
self.assertEqual(str(qt1.vip.addr), self.make_addr(
|
||||
vip_pg.sw_if_index, i, is_v6))
|
||||
for (src_pg, dst_pg), path in zip(args, qt1.paths):
|
||||
if src_pg:
|
||||
self.assertEqual(str(path.src_ep.addr), self.make_addr(
|
||||
src_pg.sw_if_index, i, is_v6))
|
||||
if dst_pg:
|
||||
self.assertEqual(str(path.dst_ep.addr), self.make_addr(
|
||||
dst_pg.sw_if_index, i, is_v6))
|
||||
|
||||
def config_ips(self, rng, is_add=1, is_v6=False):
|
||||
for pg, i in product(self.pg_interfaces, rng):
|
||||
self.vapi.sw_interface_add_del_address(
|
||||
sw_if_index=pg.sw_if_index,
|
||||
prefix=self.make_prefix(pg.sw_if_index, i, is_v6),
|
||||
is_add=is_add)
|
||||
|
||||
def test_dhcp_v4(self):
|
||||
self.create_pg_interfaces(range(5))
|
||||
for i in self.pg_interfaces:
|
||||
i.admin_up()
|
||||
pglist = (self.pg0, (self.pg1, self.pg2), (self.pg1, self.pg4))
|
||||
t1 = self.create_translation(*pglist)
|
||||
self.config_ips([0])
|
||||
self.check_resolved(t1, *pglist)
|
||||
self.config_ips([1])
|
||||
self.config_ips([0], is_add=0)
|
||||
self.check_resolved(t1, *pglist, i=1)
|
||||
self.config_ips([1], is_add=0)
|
||||
t1.remove_vpp_config()
|
||||
|
||||
def test_dhcp_v6(self):
|
||||
self.create_pg_interfaces(range(5))
|
||||
for i in self.pg_interfaces:
|
||||
i.admin_up()
|
||||
pglist = (self.pg0, (self.pg1, self.pg2), (self.pg1, self.pg4))
|
||||
t1 = self.create_translation(*pglist, is_v6=True)
|
||||
self.config_ips([0], is_v6=True)
|
||||
self.check_resolved(t1, *pglist, is_v6=True)
|
||||
self.config_ips([1], is_v6=True)
|
||||
self.config_ips([0], is_add=0, is_v6=True)
|
||||
self.check_resolved(t1, *pglist, i=1, is_v6=True)
|
||||
self.config_ips([1], is_add=0, is_v6=True)
|
||||
t1.remove_vpp_config()
|
||||
|
||||
def test_dhcp_snat(self):
|
||||
self.create_pg_interfaces(range(1))
|
||||
for i in self.pg_interfaces:
|
||||
i.admin_up()
|
||||
self.vapi.cnat_set_snat_addresses(sw_if_index=self.pg0.sw_if_index)
|
||||
self.config_ips([0], is_v6=False)
|
||||
self.config_ips([0], is_v6=True)
|
||||
r = self.vapi.cnat_get_snat_addresses()
|
||||
self.assertEqual(str(r.snat_ip4), self.make_addr(
|
||||
self.pg0.sw_if_index, 0, False))
|
||||
self.assertEqual(str(r.snat_ip6), self.make_addr(
|
||||
self.pg0.sw_if_index, 0, True))
|
||||
self.config_ips([1], is_v6=False)
|
||||
self.config_ips([1], is_v6=True)
|
||||
self.config_ips([0], is_add=0, is_v6=False)
|
||||
self.config_ips([0], is_add=0, is_v6=True)
|
||||
r = self.vapi.cnat_get_snat_addresses()
|
||||
self.assertEqual(str(r.snat_ip4), self.make_addr(
|
||||
self.pg0.sw_if_index, 1, False))
|
||||
self.assertEqual(str(r.snat_ip6), self.make_addr(
|
||||
self.pg0.sw_if_index, 1, True))
|
||||
self.config_ips([1], is_add=0, is_v6=False)
|
||||
self.config_ips([1], is_add=0, is_v6=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(testRunner=VppTestRunner)
|
||||
|
Reference in New Issue
Block a user