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
2020-09-21 19:14:08 +02:00
committed by Dave Barach
parent ce25b60de5
commit af897c5e3f
11 changed files with 716 additions and 109 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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));

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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
*

View File

@ -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)