aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2017-02-16 07:45:03 -0800
committerDamjan Marion <dmarion.lists@gmail.com>2017-03-07 21:21:41 +0000
commit3466c30261950823828d1dad0d2fb170ee2f9aaf (patch)
tree1eb304758c8bc5e53e347ba54ba8949ac8228e70
parent09a38a6db4235dcacbfb6d5e3686faaeb1c25a37 (diff)
DHCP Multiple Servers (VPP-602, VPP-605)
Multiple DHCP (4 and/or 6) servers can be added and removed through multiple calls to the 'set dhcp server' API. All 4/6/ discover/solicit messages will then be replicated to all servers in the list. The expectation is that the servers/system is configured in such a way that this is viable. If VSS information is providied for the clinet VRF which also has multiple servers configured, then the same VSS information is sent to each server. Likewise the source address of packets sent to from VPP to each server is the same. Change-Id: I3287cb084c84b3f612b78bc69cfcb5b9c1f8934d Signed-off-by: Neale Ranns <nranns@cisco.com>
-rw-r--r--src/scripts/vnet/dhcp/proxy3
-rw-r--r--src/vat/api_format.c56
-rw-r--r--src/vnet/dhcp/client.c2
-rw-r--r--src/vnet/dhcp/dhcp.api12
-rw-r--r--src/vnet/dhcp/dhcp4_packet.h5
-rw-r--r--src/vnet/dhcp/dhcp4_proxy_node.c151
-rw-r--r--src/vnet/dhcp/dhcp6_proxy_node.c158
-rw-r--r--src/vnet/dhcp/dhcp_api.c66
-rw-r--r--src/vnet/dhcp/dhcp_proxy.c129
-rw-r--r--src/vnet/dhcp/dhcp_proxy.h85
-rw-r--r--src/vnet/ip/ip6_packet.h2
-rw-r--r--src/vnet/pg/input.c6
-rw-r--r--test/test_dhcp.py356
13 files changed, 796 insertions, 235 deletions
diff --git a/src/scripts/vnet/dhcp/proxy b/src/scripts/vnet/dhcp/proxy
index c709d87dbe7..42dff2a0be8 100644
--- a/src/scripts/vnet/dhcp/proxy
+++ b/src/scripts/vnet/dhcp/proxy
@@ -14,7 +14,8 @@ set int ip addr loop0 2001::1/64
set int ip addr loop0 2001:1::1/64
set dhcp proxy server 10.255.0.1 src-address 10.0.0.1 server-fib-id 0 rx-fib-id 0
-set dhcp proxy server 10.255.0.2 src-address 10.0.1.1 server-fib-id 1 rx-fib-id 1
+set dhcp proxy server 10.255.0.2 src-address 10.0.0.1 server-fib-id 0 rx-fib-id 0
+set dhcp proxy server 10.255.1.2 src-address 10.0.1.1 server-fib-id 1 rx-fib-id 1
set dhcpv6 proxy server 3001::1 src-address 2001::1 server-fib-id 0 rx-fib-id 0
set dhcpv6 proxy server 3002::1 src-address 2001:1::1 server-fib-id 1 rx-fib-id 1
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index 0b60b91090d..b5943f030a6 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -7573,23 +7573,35 @@ static void
vl_api_dhcp_proxy_details_t_handler (vl_api_dhcp_proxy_details_t * mp)
{
vat_main_t *vam = &vat_main;
+ u32 i, count = mp->count;
+ vl_api_dhcp_server_t *s;
if (mp->is_ipv6)
print (vam->ofp,
- "RX Table-ID %d, Server Table-ID %d, Server Address %U, Source Address %U, VSS FIB-ID %d, VSS OUI %d",
+ "RX Table-ID %d, Source Address %U, VSS FIB-ID %d, VSS OUI %d",
ntohl (mp->rx_vrf_id),
- ntohl (mp->server_vrf_id),
- format_ip6_address, mp->dhcp_server,
format_ip6_address, mp->dhcp_src_address,
ntohl (mp->vss_oui), ntohl (mp->vss_fib_id));
else
print (vam->ofp,
- "RX Table-ID %d, Server Table-ID %d, Server Address %U, Source Address %U, VSS FIB-ID %d, VSS OUI %d",
+ "RX Table-ID %d, Source Address %U, VSS FIB-ID %d, VSS OUI %d",
ntohl (mp->rx_vrf_id),
- ntohl (mp->server_vrf_id),
- format_ip4_address, mp->dhcp_server,
format_ip4_address, mp->dhcp_src_address,
ntohl (mp->vss_oui), ntohl (mp->vss_fib_id));
+
+ for (i = 0; i < count; i++)
+ {
+ s = &mp->servers[i];
+
+ if (mp->is_ipv6)
+ print (vam->ofp,
+ " Server Table-ID %d, Server Address %U",
+ ntohl (s->server_vrf_id), format_ip6_address, s->dhcp_server);
+ else
+ print (vam->ofp,
+ " Server Table-ID %d, Server Address %U",
+ ntohl (s->server_vrf_id), format_ip4_address, s->dhcp_server);
+ }
}
static void vl_api_dhcp_proxy_details_t_handler_json
@@ -7597,8 +7609,10 @@ static void vl_api_dhcp_proxy_details_t_handler_json
{
vat_main_t *vam = &vat_main;
vat_json_node_t *node = NULL;
+ u32 i, count = mp->count;
struct in_addr ip4;
struct in6_addr ip6;
+ vl_api_dhcp_server_t *s;
if (VAT_JSON_ARRAY != vam->json_tree.type)
{
@@ -7609,24 +7623,38 @@ static void vl_api_dhcp_proxy_details_t_handler_json
vat_json_init_object (node);
vat_json_object_add_uint (node, "rx-table-id", ntohl (mp->rx_vrf_id));
- vat_json_object_add_uint (node, "server-table-id",
- ntohl (mp->server_vrf_id));
+ vat_json_object_add_uint (node, "vss-fib-id", ntohl (mp->vss_fib_id));
+ vat_json_object_add_uint (node, "vss-oui", ntohl (mp->vss_oui));
+
if (mp->is_ipv6)
{
- clib_memcpy (&ip6, &mp->dhcp_server, sizeof (ip6));
- vat_json_object_add_ip6 (node, "server_address", ip6);
clib_memcpy (&ip6, &mp->dhcp_src_address, sizeof (ip6));
vat_json_object_add_ip6 (node, "src_address", ip6);
}
else
{
- clib_memcpy (&ip4, &mp->dhcp_server, sizeof (ip4));
- vat_json_object_add_ip4 (node, "server_address", ip4);
clib_memcpy (&ip4, &mp->dhcp_src_address, sizeof (ip4));
vat_json_object_add_ip4 (node, "src_address", ip4);
}
- vat_json_object_add_uint (node, "vss-fib-id", ntohl (mp->vss_fib_id));
- vat_json_object_add_uint (node, "vss-oui", ntohl (mp->vss_oui));
+
+ for (i = 0; i < count; i++)
+ {
+ s = &mp->servers[i];
+
+ vat_json_object_add_uint (node, "server-table-id",
+ ntohl (s->server_vrf_id));
+
+ if (mp->is_ipv6)
+ {
+ clib_memcpy (&ip4, &s->dhcp_server, sizeof (ip4));
+ vat_json_object_add_ip4 (node, "src_address", ip4);
+ }
+ else
+ {
+ clib_memcpy (&ip6, &s->dhcp_server, sizeof (ip6));
+ vat_json_object_add_ip6 (node, "server_address", ip6);
+ }
+ }
}
static int
diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c
index d34c5a645eb..29749a33737 100644
--- a/src/vnet/dhcp/client.c
+++ b/src/vnet/dhcp/client.c
@@ -366,7 +366,7 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c,
o = (dhcp_option_t * )dhcp->options;
/* Send option 53, the DHCP message type */
- o->option = 53;
+ o->option = DHCP_PACKET_OPTION_MSG_TYPE;
o->length = 1;
o->data[0] = type;
o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api
index 8daadd8c77a..2db85a797e9 100644
--- a/src/vnet/dhcp/dhcp.api
+++ b/src/vnet/dhcp/dhcp.api
@@ -137,19 +137,25 @@ define dhcp_proxy_dump
u8 is_ip6;
};
+typeonly manual_print manual_endian define dhcp_server
+{
+ u32 server_vrf_id;
+ u8 dhcp_server[16];
+};
+
/** \brief Tell client about a DHCP completion event
@param client_index - opaque cookie to identify the sender
*/
-define dhcp_proxy_details
+manual_endian manual_print define dhcp_proxy_details
{
u32 context;
u32 rx_vrf_id;
- u32 server_vrf_id;
u32 vss_oui;
u32 vss_fib_id;
u8 is_ipv6;
- u8 dhcp_server[16];
u8 dhcp_src_address[16];
+ u8 count;
+ vl_api_dhcp_server_t servers[count];
};
/*
diff --git a/src/vnet/dhcp/dhcp4_packet.h b/src/vnet/dhcp/dhcp4_packet.h
index 28c4b156e5c..07829f4823c 100644
--- a/src/vnet/dhcp/dhcp4_packet.h
+++ b/src/vnet/dhcp/dhcp4_packet.h
@@ -55,6 +55,11 @@ typedef enum {
DHCP_PACKET_ACK=5,
} dhcp_packet_type_t;
+typedef enum dhcp_packet_option_t_
+{
+ DHCP_PACKET_OPTION_MSG_TYPE = 53,
+} dhcp_packet_option_t;
+
/* charming antique: 99.130.83.99 is the dhcp magic cookie */
#define DHCP_MAGIC (clib_host_to_net_u32(0x63825363))
diff --git a/src/vnet/dhcp/dhcp4_proxy_node.c b/src/vnet/dhcp/dhcp4_proxy_node.c
index 88a99249684..1c84881a520 100644
--- a/src/vnet/dhcp/dhcp4_proxy_node.c
+++ b/src/vnet/dhcp/dhcp4_proxy_node.c
@@ -135,18 +135,17 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
u32 original_sw_if_index = 0;
u8 *end = NULL;
u32 fib_index;
- dhcp_server_t * server;
+ dhcp_proxy_t *proxy;
+ dhcp_server_t *server;
u32 rx_sw_if_index;
dhcp_option_t *o;
u32 len = 0;
vlib_buffer_free_list_t *fl;
+ u8 is_discover = 0;
bi0 = from[0];
- to_next[0] = bi0;
from += 1;
- to_next += 1;
n_left_from -= 1;
- n_left_to_next -= 1;
b0 = vlib_get_buffer (vm, bi0);
@@ -172,16 +171,17 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
rx_sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
fib_index = im->fib_index_by_sw_if_index [rx_sw_if_index];
- server = dhcp_get_server(dpm, fib_index, FIB_PROTOCOL_IP4);
-
- if (PREDICT_FALSE (NULL == server))
+ proxy = dhcp_get_proxy(dpm, fib_index, FIB_PROTOCOL_IP4);
+
+ if (PREDICT_FALSE (NULL == proxy))
{
error0 = DHCP_PROXY_ERROR_NO_SERVER;
next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP;
pkts_no_server++;
goto do_trace;
}
-
+
+ server = &proxy->dhcp_servers[0];
vlib_buffer_advance (b0, -(sizeof(*ip0)));
ip0 = vlib_buffer_get_current (b0);
@@ -198,7 +198,7 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
sum0 = ip0->checksum;
old0 = ip0->src_address.as_u32;
- new0 = server->dhcp_src_address.ip4.as_u32;
+ new0 = proxy->dhcp_src_address.ip4.as_u32;
ip0->src_address.as_u32 = new0;
sum0 = ip_csum_update (sum0, old0, new0,
ip4_header_t /* structure */,
@@ -209,7 +209,7 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
vnet_buffer(b0)->sw_if_index[VLIB_TX] =
server->server_fib_index;
- h0->gateway_ip_address.as_u32 = server->dhcp_src_address.ip4.as_u32;
+ h0->gateway_ip_address.as_u32 = proxy->dhcp_src_address.ip4.as_u32;
pkts_to_server++;
o = (dhcp_option_t *) h0->options;
@@ -220,7 +220,16 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
end = b0->data + b0->current_data + b0->current_length;
/* TLVs are not performance-friendly... */
while (o->option != 0xFF /* end of options */ && (u8 *)o < end)
+ {
+ if (DHCP_PACKET_OPTION_MSG_TYPE == o->option)
+ {
+ if (DHCP_PACKET_DISCOVER == o->data[0])
+ {
+ is_discover = 1;
+ }
+ }
o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
+ }
fl = vlib_buffer_get_free_list (vm, b0->free_list_index);
// start write at (option*)o, some packets have padding
@@ -340,6 +349,65 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP;
+ /*
+ * If we have multiple servers configured and this is the
+ * client's discover message, then send copies to each of
+ * those servers
+ */
+ if (is_discover && vec_len(proxy->dhcp_servers) > 1)
+ {
+ u32 ii;
+
+ for (ii = 1; ii < vec_len(proxy->dhcp_servers); ii++)
+ {
+ vlib_buffer_t *c0;
+ u32 ci0;
+
+ c0 = vlib_buffer_copy(vm, b0);
+ ci0 = vlib_get_buffer_index(vm, c0);
+ server = &proxy->dhcp_servers[ii];
+
+ ip0 = vlib_buffer_get_current (c0);
+
+ sum0 = ip0->checksum;
+ old0 = ip0->dst_address.as_u32;
+ new0 = server->dhcp_server.ip4.as_u32;
+ ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32;
+ sum0 = ip_csum_update (sum0, old0, new0,
+ ip4_header_t /* structure */,
+ dst_address /* changed member */);
+ ip0->checksum = ip_csum_fold (sum0);
+
+ to_next[0] = ci0;
+ to_next += 1;
+ n_left_to_next -= 1;
+
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+ to_next, n_left_to_next,
+ ci0, next0);
+
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ dhcp_proxy_trace_t *tr;
+
+ tr = vlib_add_trace (vm, node, c0, sizeof (*tr));
+ tr->which = 0; /* to server */
+ tr->error = error0;
+ tr->original_sw_if_index = original_sw_if_index;
+ tr->sw_if_index = sw_if_index;
+ if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP)
+ tr->trace_ip4_address.as_u32 = server->dhcp_server.ip4.as_u32;
+ }
+
+ if (PREDICT_FALSE(0 == n_left_to_next))
+ {
+ vlib_put_next_frame (vm, node, next_index,
+ n_left_to_next);
+ vlib_get_next_frame (vm, node, next_index,
+ to_next, n_left_to_next);
+ }
+ }
+ }
do_trace:
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
{
@@ -350,10 +418,15 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
tr->original_sw_if_index = original_sw_if_index;
tr->sw_if_index = sw_if_index;
if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP)
- tr->trace_ip4_address.as_u32 = server->dhcp_server.ip4.as_u32;
+ tr->trace_ip4_address.as_u32 =
+ proxy->dhcp_servers[0].dhcp_server.ip4.as_u32;
}
do_enqueue:
+ to_next[0] = bi0;
+ to_next += 1;
+ n_left_to_next -= 1;
+
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
to_next, n_left_to_next,
bi0, next0);
@@ -437,7 +510,8 @@ dhcp_proxy_to_client_input (vlib_main_t * vm,
u32 error0 = (u32)~0;
vnet_sw_interface_t *swif;
u32 fib_index;
- dhcp_server_t * server;
+ dhcp_proxy_t *proxy;
+ dhcp_server_t *server;
u32 original_sw_if_index = (u32) ~0;
ip4_address_t relay_addr = {
.as_u32 = 0,
@@ -547,20 +621,26 @@ dhcp_proxy_to_client_input (vlib_main_t * vm,
}
fib_index = im->fib_index_by_sw_if_index [sw_if_index];
- server = dhcp_get_server(dpm, fib_index, FIB_PROTOCOL_IP4);
+ proxy = dhcp_get_proxy(dpm, fib_index, FIB_PROTOCOL_IP4);
- if (PREDICT_FALSE (NULL == server))
+ if (PREDICT_FALSE (NULL == proxy))
{
error0 = DHCP_PROXY_ERROR_NO_SERVER;
goto drop_packet;
}
- if (ip0->src_address.as_u32 != server->dhcp_server.ip4.as_u32)
- {
- error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS;
- goto drop_packet;
+ vec_foreach(server, proxy->dhcp_servers)
+ {
+ if (ip0->src_address.as_u32 == server->dhcp_server.ip4.as_u32)
+ {
+ goto server_found;
+ }
}
+ error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS;
+ goto drop_packet;
+
+ server_found:
vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index;
swif = vnet_get_sw_interface (vnm, sw_if_index);
@@ -709,9 +789,8 @@ dhcp4_proxy_set_server (ip46_address_t *addr,
if (is_del)
{
- rc = dhcp_proxy_server_del (FIB_PROTOCOL_IP4, rx_fib_index);
-
- if (0 == rc)
+ if (dhcp_proxy_server_del (FIB_PROTOCOL_IP4, rx_fib_index,
+ addr, server_table_id))
{
fib_table_entry_special_remove(rx_fib_index,
&all_1s,
@@ -809,29 +888,35 @@ VLIB_CLI_COMMAND (dhcp_proxy_set_command, static) = {
static u8 *
format_dhcp4_proxy_server (u8 * s, va_list * args)
{
- dhcp_server_t * server = va_arg (*args, dhcp_server_t *);
+ dhcp_proxy_t *proxy = va_arg (*args, dhcp_proxy_t *);
ip4_fib_t * rx_fib, * server_fib;
+ dhcp_server_t *server;
- if (server == 0)
+ if (proxy == 0)
{
- s = format (s, "%=16s%=16s%=14s%=14s", "Server", "Src Address",
- "Server FIB", "RX FIB");
+ s = format (s, "%=14s%=16s%s", "RX FIB", "Src Address",
+ "Servers FIB,Address");
return s;
}
- server_fib = ip4_fib_get(server->server_fib_index);
- rx_fib = ip4_fib_get(server->rx_fib_index);
+ rx_fib = ip4_fib_get(proxy->rx_fib_index);
+
+ s = format (s, "%=14u%=16U",
+ rx_fib->table_id,
+ format_ip46_address, &proxy->dhcp_src_address, IP46_TYPE_ANY);
- s = format (s, "%=16U%=16U%=14u%=14u",
- format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY,
- format_ip46_address, &server->dhcp_src_address, IP46_TYPE_ANY,
- server_fib->table_id,
- rx_fib->table_id);
+ vec_foreach(server, proxy->dhcp_servers)
+ {
+ server_fib = ip4_fib_get(server->server_fib_index);
+ s = format (s, "%u,%U ",
+ server_fib->table_id,
+ format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY);
+ }
return s;
}
static int
-dhcp4_proxy_show_walk (dhcp_server_t *server,
+dhcp4_proxy_show_walk (dhcp_proxy_t *server,
void *ctx)
{
vlib_main_t * vm = ctx;
diff --git a/src/vnet/dhcp/dhcp6_proxy_node.c b/src/vnet/dhcp/dhcp6_proxy_node.c
index 58674209ca7..524cb095357 100644
--- a/src/vnet/dhcp/dhcp6_proxy_node.c
+++ b/src/vnet/dhcp/dhcp6_proxy_node.c
@@ -140,7 +140,8 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm,
ip6_main_t * im = &ip6_main;
ip6_address_t * src;
int bogus_length;
- dhcp_server_t * server;
+ dhcp_proxy_t *proxy;
+ dhcp_server_t *server;
u32 rx_fib_idx = 0, server_fib_idx = 0;
next_index = node->cached_next_index;
@@ -176,13 +177,11 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm,
u8 client_src_mac[6];
vlib_buffer_free_list_t *fl;
dhcp_vss_t *vss;
+ u8 is_solicit = 0;
bi0 = from[0];
- to_next[0] = bi0;
from += 1;
- to_next += 1;
n_left_from -= 1;
- n_left_to_next -= 1;
b0 = vlib_get_buffer (vm, bi0);
@@ -227,9 +226,9 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm,
/* Send to DHCPV6 server via the configured FIB */
rx_sw_if_index = sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
rx_fib_idx = im->mfib_index_by_sw_if_index [rx_sw_if_index];
- server = dhcp_get_server(dpm, rx_fib_idx, FIB_PROTOCOL_IP6);
+ proxy = dhcp_get_proxy(dpm, rx_fib_idx, FIB_PROTOCOL_IP6);
- if (PREDICT_FALSE (NULL == server))
+ if (PREDICT_FALSE (NULL == proxy))
{
error0 = DHCPV6_PROXY_ERROR_NO_SERVER;
next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
@@ -237,6 +236,7 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm,
goto do_trace;
}
+ server = &proxy->dhcp_servers[0];
server_fib_idx = server->server_fib_index;
vnet_buffer(b0)->sw_if_index[VLIB_TX] = server_fib_idx;
@@ -371,18 +371,19 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm,
ip1->payload_length = u1->length;
ip1->protocol = PROTO_UDP;
ip1->hop_limit = HOP_COUNT_LIMIT;
- src = (server->dhcp_server.ip6.as_u64[0] ||
- server->dhcp_server.ip6.as_u64[1]) ?
- &server->dhcp_server.ip6 : &all_dhcpv6_server_address;
+ src = ((server->dhcp_server.ip6.as_u64[0] ||
+ server->dhcp_server.ip6.as_u64[1]) ?
+ &server->dhcp_server.ip6 :
+ &all_dhcpv6_server_address);
copy_ip6_address(&ip1->dst_address, src);
ia0 = ip6_interface_first_global_or_site_address
(&ip6_main, vnet_buffer(b0)->sw_if_index[VLIB_RX]);
- src = (server->dhcp_src_address.ip6.as_u64[0] ||
- server->dhcp_src_address.ip6.as_u64[1]) ?
- &server->dhcp_src_address.ip6 : ia0;
+ src = (proxy->dhcp_src_address.ip6.as_u64[0] ||
+ proxy->dhcp_src_address.ip6.as_u64[1]) ?
+ &proxy->dhcp_src_address.ip6 : ia0;
if (ia0 == 0)
{
error0 = DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS;
@@ -400,6 +401,66 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm,
next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP;
+ is_solicit = (DHCPV6_MSG_SOLICIT == h0->u.msg_type);
+
+ /*
+ * If we have multiple servers configured and this is the
+ * client's discover message, then send copies to each of
+ * those servers
+ */
+ if (is_solicit && vec_len(proxy->dhcp_servers) > 1)
+ {
+ u32 ii;
+
+ for (ii = 1; ii < vec_len(proxy->dhcp_servers); ii++)
+ {
+ vlib_buffer_t *c0;
+ u32 ci0;
+
+ c0 = vlib_buffer_copy(vm, b0);
+ ci0 = vlib_get_buffer_index(vm, c0);
+ server = &proxy->dhcp_servers[ii];
+
+ ip0 = vlib_buffer_get_current (c0);
+
+ src = ((server->dhcp_server.ip6.as_u64[0] ||
+ server->dhcp_server.ip6.as_u64[1]) ?
+ &server->dhcp_server.ip6 :
+ &all_dhcpv6_server_address);
+ copy_ip6_address(&ip1->dst_address, src);
+
+ to_next[0] = ci0;
+ to_next += 1;
+ n_left_to_next -= 1;
+
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+ to_next, n_left_to_next,
+ ci0, next0);
+
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ dhcpv6_proxy_trace_t *tr;
+
+ tr = vlib_add_trace (vm, node, c0, sizeof (*tr));
+ tr->which = 0; /* to server */
+ tr->error = error0;
+ tr->original_sw_if_index = rx_sw_if_index;
+ tr->sw_if_index = sw_if_index;
+ if (next0 == DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP)
+ copy_ip6_address((ip6_address_t *)&tr->packet_data[0],
+ &server->dhcp_server.ip6);
+ }
+
+ if (PREDICT_FALSE(0 == n_left_to_next))
+ {
+ vlib_put_next_frame (vm, node, next_index,
+ n_left_to_next);
+ vlib_get_next_frame (vm, node, next_index,
+ to_next, n_left_to_next);
+ }
+ }
+ }
+
do_trace:
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
{
@@ -414,6 +475,10 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm,
}
do_enqueue:
+ to_next[0] = bi0;
+ to_next += 1;
+ n_left_to_next -= 1;
+
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
to_next, n_left_to_next,
bi0, next0);
@@ -475,7 +540,8 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm,
u32 n_left_from, * from;
ethernet_main_t *em = ethernet_get_main (vm);
dhcp_proxy_main_t * dm = &dhcp_proxy_main;
- dhcp_server_t * server;
+ dhcp_proxy_t *proxy;
+ dhcp_server_t *server;
vnet_main_t * vnm = vnet_get_main();
int bogus_length;
@@ -588,9 +654,9 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm,
vlib_buffer_advance (b0, sizeof(*r0));
client_fib_idx = im->mfib_index_by_sw_if_index[sw_if_index];
- server = dhcp_get_server(dm, client_fib_idx, FIB_PROTOCOL_IP6);
+ proxy = dhcp_get_proxy(dm, client_fib_idx, FIB_PROTOCOL_IP6);
- if (NULL == server)
+ if (NULL == proxy)
{
error0 = DHCPV6_PROXY_ERROR_NO_SERVER;
goto drop_packet;
@@ -599,15 +665,21 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm,
server_fib_idx = im->fib_index_by_sw_if_index
[vnet_buffer(b0)->sw_if_index[VLIB_RX]];
- if (server_fib_idx != server->server_fib_index ||
- ip0->src_address.as_u64[0] != server->dhcp_server.ip6.as_u64[0] ||
- ip0->src_address.as_u64[1] != server->dhcp_server.ip6.as_u64[1])
- {
- //drop packet if not from server with configured address or FIB
- error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS;
- goto drop_packet;
- }
+ vec_foreach(server, proxy->dhcp_servers)
+ {
+ if (server_fib_idx == server->server_fib_index &&
+ ip0->src_address.as_u64[0] == server->dhcp_server.ip6.as_u64[0] &&
+ ip0->src_address.as_u64[1] == server->dhcp_server.ip6.as_u64[1])
+ {
+ goto server_found;
+ }
+ }
+
+ //drop packet if not from server with configured address or FIB
+ error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS;
+ goto drop_packet;
+ server_found:
vnet_buffer (b0)->sw_if_index[VLIB_TX] = original_sw_if_index
= sw_if_index;
@@ -773,9 +845,8 @@ dhcp6_proxy_set_server (ip46_address_t *addr,
if (is_del)
{
- rc = dhcp_proxy_server_del (FIB_PROTOCOL_IP6, rx_fib_index);
-
- if (0 == rc)
+ if (dhcp_proxy_server_del (FIB_PROTOCOL_IP6, rx_fib_index,
+ addr, server_table_id))
{
mfib_table_entry_delete(rx_fib_index,
&all_dhcp_servers,
@@ -893,43 +964,50 @@ VLIB_CLI_COMMAND (dhcpv6_proxy_set_command, static) = {
static u8 *
format_dhcp6_proxy_server (u8 * s, va_list * args)
{
- dhcp_server_t * server = va_arg (*args, dhcp_server_t *);
+ dhcp_proxy_t * proxy = va_arg (*args, dhcp_proxy_t *);
ip6_fib_t *server_fib;
+ dhcp_server_t *server;
ip6_mfib_t *rx_fib;
- if (NULL == server)
+ if (proxy == 0)
{
- s = format (s, "%=40s%=40s%=14s%=14s", "Server Address", "Source Address",
- "Server FIB", "RX FIB");
+ s = format (s, "%=14s%=16s%s", "RX FIB", "Src Address",
+ "Servers FIB,Address");
return s;
}
- server_fib = ip6_fib_get(server->server_fib_index);
- rx_fib = ip6_mfib_get(server->rx_fib_index);
+ rx_fib = ip6_mfib_get(proxy->rx_fib_index);
+
+ s = format (s, "%=14u%=16U",
+ rx_fib->table_id,
+ format_ip46_address, &proxy->dhcp_src_address, IP46_TYPE_ANY);
+ vec_foreach(server, proxy->dhcp_servers)
+ {
+ server_fib = ip6_fib_get(server->server_fib_index);
+ s = format (s, "%u,%U ",
+ server_fib->table_id,
+ format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY);
+ }
- s = format (s, "%=40U%=40U%=14u%=14u",
- format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY,
- format_ip46_address, &server->dhcp_src_address, IP46_TYPE_ANY,
- server_fib->table_id, rx_fib->table_id);
return s;
}
static int
-dhcp6_proxy_show_walk (dhcp_server_t *server,
+dhcp6_proxy_show_walk (dhcp_proxy_t *proxy,
void *ctx)
{
vlib_main_t * vm = ctx;
- vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, server);
+ vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, proxy);
return (1);
}
static clib_error_t *
dhcpv6_proxy_show_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
{
vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, NULL /* header line */);
diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c
index ce34f6a47b3..e9c757e85b6 100644
--- a/src/vnet/dhcp/dhcp_api.c
+++ b/src/vnet/dhcp/dhcp_api.c
@@ -24,6 +24,7 @@
#include <vnet/api_errno.h>
#include <vnet/dhcp/dhcp_proxy.h>
#include <vnet/dhcp/client.h>
+#include <vnet/fib/fib_table.h>
#include <vnet/vnet_msg_enum.h>
@@ -113,46 +114,73 @@ vl_api_dhcp_proxy_dump_t_handler (vl_api_dhcp_proxy_dump_t * mp)
if (q == 0)
return;
- dhcp_proxy_dump ((mp->is_ip6 == 0 ?
+ dhcp_proxy_dump ((mp->is_ip6 == 1 ?
FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4), q, mp->context);
}
void
dhcp_send_details (fib_protocol_t proto,
- void *opaque,
- u32 context,
- const ip46_address_t * server,
- const ip46_address_t * src,
- u32 server_fib_id,
- u32 rx_fib_id, u32 vss_fib_id, u32 vss_oui)
+ void *opaque, u32 context, dhcp_proxy_t * proxy)
{
vl_api_dhcp_proxy_details_t *mp;
unix_shared_memory_queue_t *q = opaque;
-
- mp = vl_msg_api_alloc (sizeof (*mp));
+ vl_api_dhcp_server_t *v_server;
+ dhcp_server_t *server;
+ fib_table_t *s_fib;
+ dhcp_vss_t *vss;
+ u32 count;
+ size_t n;
+
+ count = vec_len (proxy->dhcp_servers);
+ n = sizeof (*mp) + (count * sizeof (vl_api_dhcp_server_t));
+ mp = vl_msg_api_alloc (n);
if (!mp)
return;
- memset (mp, 0, sizeof (*mp));
+ memset (mp, 0, n);
mp->_vl_msg_id = ntohs (VL_API_DHCP_PROXY_DETAILS);
mp->context = context;
-
- mp->rx_vrf_id = htonl (rx_fib_id);
- mp->server_vrf_id = htonl (server_fib_id);
- mp->vss_oui = htonl (vss_oui);
- mp->vss_fib_id = htonl (vss_fib_id);
+ mp->count = count;
mp->is_ipv6 = (proto == FIB_PROTOCOL_IP6);
+ mp->rx_vrf_id =
+ htonl (dhcp_proxy_rx_table_get_table_id (proto, proxy->rx_fib_index));
+
+ vss = dhcp_get_vss_info (&dhcp_proxy_main, proxy->rx_fib_index, proto);
+
+ if (NULL != vss)
+ {
+ mp->vss_oui = htonl (vss->oui);
+ mp->vss_fib_id = htonl (vss->fib_id);
+ }
+
+ vec_foreach_index (count, proxy->dhcp_servers)
+ {
+ server = &proxy->dhcp_servers[count];
+ v_server = &mp->servers[count];
+
+ s_fib = fib_table_get (server->server_fib_index, proto);
+
+ v_server->server_vrf_id = htonl (s_fib->ft_table_id);
+
+ if (mp->is_ipv6)
+ {
+ memcpy (v_server->dhcp_server, &server->dhcp_server.ip6, 16);
+ }
+ else
+ {
+ /* put the address in the first bytes */
+ memcpy (v_server->dhcp_server, &server->dhcp_server.ip4, 4);
+ }
+ }
if (mp->is_ipv6)
{
- memcpy (mp->dhcp_server, server, 16);
- memcpy (mp->dhcp_src_address, src, 16);
+ memcpy (mp->dhcp_src_address, &proxy->dhcp_src_address.ip6, 16);
}
else
{
/* put the address in the first bytes */
- memcpy (mp->dhcp_server, &server->ip4, 4);
- memcpy (mp->dhcp_src_address, &src->ip4, 4);
+ memcpy (mp->dhcp_src_address, &proxy->dhcp_src_address.ip4, 4);
}
vl_msg_api_send_shmem (q, (u8 *) & mp);
}
diff --git a/src/vnet/dhcp/dhcp_proxy.c b/src/vnet/dhcp/dhcp_proxy.c
index 8e31c3dbecc..ba7f354e9fa 100644
--- a/src/vnet/dhcp/dhcp_proxy.c
+++ b/src/vnet/dhcp/dhcp_proxy.c
@@ -44,7 +44,7 @@ dhcp_proxy_rx_table_unlock (fib_protocol_t proto,
mfib_table_unlock(fib_index, proto);
}
-static u32
+ u32
dhcp_proxy_rx_table_get_table_id (fib_protocol_t proto,
u32 fib_index)
{
@@ -72,7 +72,7 @@ dhcp_proxy_walk (fib_protocol_t proto,
void *ctx)
{
dhcp_proxy_main_t * dpm = &dhcp_proxy_main;
- dhcp_server_t * server;
+ dhcp_proxy_t * server;
u32 server_index, i;
vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index[proto])
@@ -124,31 +124,68 @@ dhcp_vss_walk (fib_protocol_t proto,
}
}
+static u32
+dhcp_proxy_server_find (dhcp_proxy_t *proxy,
+ fib_protocol_t proto,
+ ip46_address_t *addr,
+ u32 server_table_id)
+{
+ dhcp_server_t *server;
+ u32 ii, fib_index;
+
+ vec_foreach_index(ii, proxy->dhcp_servers)
+ {
+ server = &proxy->dhcp_servers[ii];
+ fib_index = fib_table_find(proto, server_table_id);
+
+ if (ip46_address_is_equal(&server->dhcp_server,
+ addr) &&
+ (server->server_fib_index == fib_index))
+ {
+ return (ii);
+ }
+ }
+ return (~0);
+}
+
int
dhcp_proxy_server_del (fib_protocol_t proto,
- u32 rx_fib_index)
+ u32 rx_fib_index,
+ ip46_address_t *addr,
+ u32 server_table_id)
{
dhcp_proxy_main_t * dpm = &dhcp_proxy_main;
- dhcp_server_t * server = 0;
- int rc = 0;
+ dhcp_proxy_t *proxy = 0;
- server = dhcp_get_server(dpm, rx_fib_index, proto);
+ proxy = dhcp_get_proxy(dpm, rx_fib_index, proto);
- if (NULL == server)
- {
- rc = VNET_API_ERROR_NO_SUCH_ENTRY;
- }
- else
+ if (NULL != proxy)
{
- /* Use the default server again. */
- dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = ~0;
+ dhcp_server_t *server;
+ u32 index;
- fib_table_unlock (server->server_fib_index, proto);
+ index = dhcp_proxy_server_find(proxy, proto, addr, server_table_id);
- pool_put (dpm->dhcp_servers[proto], server);
+ if (~0 != index)
+ {
+ server = &proxy->dhcp_servers[index];
+ fib_table_unlock (server->server_fib_index, proto);
+
+ vec_del1(proxy->dhcp_servers, index);
+
+ if (0 == vec_len(proxy->dhcp_servers))
+ {
+ /* no servers left, delete the proxy config */
+ dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = ~0;
+ vec_free(proxy->dhcp_servers);
+ pool_put (dpm->dhcp_servers[proto], proxy);
+ return (1);
+ }
+ }
}
- return (rc);
+ /* the proxy still exists */
+ return (0);
}
int
@@ -159,48 +196,42 @@ dhcp_proxy_server_add (fib_protocol_t proto,
u32 server_table_id)
{
dhcp_proxy_main_t * dpm = &dhcp_proxy_main;
- dhcp_server_t * server = 0;
+ dhcp_proxy_t * proxy = 0;
int new = 0;
- server = dhcp_get_server(dpm, rx_fib_index, proto);
+ proxy = dhcp_get_proxy(dpm, rx_fib_index, proto);
- if (NULL == server)
+ if (NULL == proxy)
{
vec_validate_init_empty(dpm->dhcp_server_index_by_rx_fib_index[proto],
rx_fib_index,
~0);
- pool_get (dpm->dhcp_servers[proto], server);
- memset (server, 0, sizeof (*server));
+ pool_get (dpm->dhcp_servers[proto], proxy);
+ memset (proxy, 0, sizeof (*proxy));
new = 1;
dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] =
- server - dpm->dhcp_servers[proto];
+ proxy - dpm->dhcp_servers[proto];
- server->rx_fib_index = rx_fib_index;
- server->server_fib_index =
- fib_table_find_or_create_and_lock(proto, server_table_id);
+ proxy->dhcp_src_address = *src_address;
+ proxy->rx_fib_index = rx_fib_index;
}
else
{
- /* modify, may need to swap server FIBs */
- u32 tmp_index;
-
- tmp_index = fib_table_find(proto, server_table_id);
-
- if (tmp_index != server->server_fib_index)
+ if (~0 != dhcp_proxy_server_find(proxy, proto, addr, server_table_id))
{
- tmp_index = server->server_fib_index;
-
- /* certainly swapping if the fib doesn't exist */
- server->server_fib_index =
- fib_table_find_or_create_and_lock(proto, server_table_id);
- fib_table_unlock (tmp_index, proto);
+ return (new);
}
}
- server->dhcp_server = *addr;
- server->dhcp_src_address = *src_address;
+ dhcp_server_t server = {
+ .dhcp_server = *addr,
+ .server_fib_index = fib_table_find_or_create_and_lock(proto,
+ server_table_id),
+ };
+
+ vec_add1(proxy->dhcp_servers, server);
return (new);
}
@@ -213,31 +244,15 @@ typedef struct dhcp4_proxy_dump_walk_ctx_t_
} dhcp_proxy_dump_walk_cxt_t;
static int
-dhcp_proxy_dump_walk (dhcp_server_t *server,
+dhcp_proxy_dump_walk (dhcp_proxy_t *proxy,
void *arg)
{
dhcp_proxy_dump_walk_cxt_t *ctx = arg;
- fib_table_t *s_fib;
- u32 rx_table_id;
- dhcp_vss_t *v;
-
- v = dhcp_get_vss_info(&dhcp_proxy_main,
- server->rx_fib_index,
- ctx->proto);
-
- s_fib = fib_table_get(server->server_fib_index, ctx->proto);
- rx_table_id = dhcp_proxy_rx_table_get_table_id(server->rx_fib_index,
- ctx->proto);
dhcp_send_details(ctx->proto,
ctx->opaque,
ctx->context,
- &server->dhcp_server,
- &server->dhcp_src_address,
- s_fib->ft_table_id,
- rx_table_id,
- (v ? v->fib_id : 0),
- (v ? v->oui : 0));
+ proxy);
return (1);
}
diff --git a/src/vnet/dhcp/dhcp_proxy.h b/src/vnet/dhcp/dhcp_proxy.h
index 708e92f3c32..ef2bc0a1926 100644
--- a/src/vnet/dhcp/dhcp_proxy.h
+++ b/src/vnet/dhcp/dhcp_proxy.h
@@ -58,9 +58,10 @@ typedef struct dhcp_vss_t_ {
} dhcp_vss_t;
/**
- * @brief A DHCP proxy server represenation
+ * @brief A representation of a single DHCP Server within a given VRF config
*/
-typedef struct dhcp_server_t_ {
+typedef struct dhcp_server_t_
+{
/**
* @brief The address of the DHCP server to which to relay the client's
* messages
@@ -68,22 +69,47 @@ typedef struct dhcp_server_t_ {
ip46_address_t dhcp_server;
/**
- * @brief The source address to use in relayed messaes
- */
- ip46_address_t dhcp_src_address;
-
- /**
* @brief The FIB index (not the external Table-ID) in which the server
* is reachable.
*/
u32 server_fib_index;
+} dhcp_server_t;
+
+/**
+ * @brief A DHCP proxy represenation fpr per-client VRF config
+ */
+typedef struct dhcp_proxy_t_ {
+ /**
+ * @brief The set of DHCP servers to which messages are relayed.
+ * If multiple servers are configured then discover/solict messages
+ * are relayed to each. A cookie is maintained for the relay, and only
+ * one message is replayed to the client, based on the presence of the
+ * cookie.
+ * The expectation is there are only 1 or 2 servers, hence no fancy DB.
+ */
+ dhcp_server_t *dhcp_servers;
+
+ /**
+ * @brief Hash table of pending requets key'd on the clients MAC address
+ */
+ uword *dhcp_pending;
+
+ /**
+ * @brief A lock for the pending request DB.
+ */
+ int lock;
+
+ /**
+ * @brief The source address to use in relayed messaes
+ */
+ ip46_address_t dhcp_src_address;
/**
* @brief The FIB index (not the external Table-ID) in which the client
* is resides.
*/
u32 rx_fib_index;
-} dhcp_server_t;
+} dhcp_proxy_t;
#define DHCP_N_PROTOS (FIB_PROTOCOL_IP6 + 1)
@@ -92,7 +118,7 @@ typedef struct dhcp_server_t_ {
*/
typedef struct {
/* Pool of DHCP servers */
- dhcp_server_t *dhcp_servers[DHCP_N_PROTOS];
+ dhcp_proxy_t *dhcp_servers[DHCP_N_PROTOS];
/* Pool of selected DHCP server. Zero is the default server */
u32 * dhcp_server_index_by_rx_fib_index[DHCP_N_PROTOS];
@@ -114,12 +140,7 @@ extern dhcp_proxy_main_t dhcp_proxy_main;
void dhcp_send_details (fib_protocol_t proto,
void *opaque,
u32 context,
- const ip46_address_t *server,
- const ip46_address_t *src,
- u32 server_fib_id,
- u32 rx_fib_id,
- u32 vss_fib_id,
- u32 vss_oui);
+ dhcp_proxy_t *proxy);
/**
* @brief Show (on CLI) a VSS config during a show walk
@@ -157,16 +178,22 @@ int dhcp_proxy_server_add(fib_protocol_t proto,
/**
* @brief Delete a DHCP proxy config
- * @return 0 is deleted, otherwise an error code
+ * @return 1 if the proxy is deleted, 0 otherwise
*/
int dhcp_proxy_server_del(fib_protocol_t proto,
- u32 rx_fib_index);
+ u32 rx_fib_index,
+ ip46_address_t *addr,
+ u32 server_table_id);
+
+u32
+dhcp_proxy_rx_table_get_table_id (fib_protocol_t proto,
+ u32 fib_index);
/**
* @brief Callback function invoked for each DHCP proxy entry
* return 0 to break the walk, non-zero otherwise.
*/
-typedef int (*dhcp_proxy_walk_fn_t)(dhcp_server_t *server,
+typedef int (*dhcp_proxy_walk_fn_t)(dhcp_proxy_t *server,
void *ctx);
/**
@@ -192,6 +219,18 @@ void dhcp_vss_walk(fib_protocol_t proto,
void *ctx);
/**
+ * @brief Lock a proxy object to prevent simultaneous access of its
+ * pending store
+ */
+void dhcp_proxy_lock (dhcp_proxy_t *server);
+
+/**
+ * @brief Lock a proxy object to prevent simultaneous access of its
+ * pending store
+ */
+void dhcp_proxy_unlock (dhcp_proxy_t *server);
+
+/**
* @brief Get the VSS data for the FIB index
*/
static inline dhcp_vss_t *
@@ -215,12 +254,12 @@ dhcp_get_vss_info (dhcp_proxy_main_t *dm,
/**
* @brief Get the DHCP proxy server data for the FIB index
*/
-static inline dhcp_server_t *
-dhcp_get_server (dhcp_proxy_main_t *dm,
- u32 rx_fib_index,
- fib_protocol_t proto)
+static inline dhcp_proxy_t *
+dhcp_get_proxy (dhcp_proxy_main_t *dm,
+ u32 rx_fib_index,
+ fib_protocol_t proto)
{
- dhcp_server_t *s = NULL;
+ dhcp_proxy_t *s = NULL;
if (vec_len(dm->dhcp_server_index_by_rx_fib_index[proto]) > rx_fib_index &&
dm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] != ~0)
diff --git a/src/vnet/ip/ip6_packet.h b/src/vnet/ip/ip6_packet.h
index 6eabeef1f3d..9bf19edb5db 100644
--- a/src/vnet/ip/ip6_packet.h
+++ b/src/vnet/ip/ip6_packet.h
@@ -79,6 +79,8 @@ typedef CLIB_PACKED (union {
#define ip46_address_reset(ip46) ((ip46)->as_u64[0] = (ip46)->as_u64[1] = 0)
#define ip46_address_cmp(ip46_1, ip46_2) (memcmp(ip46_1, ip46_2, sizeof(*ip46_1)))
#define ip46_address_is_zero(ip46) (((ip46)->as_u64[0] == 0) && ((ip46)->as_u64[1] == 0))
+#define ip46_address_is_equal(a1, a2) (((a1)->as_u64[0] == (a2)->as_u64[0]) \
+ && ((a1)->as_u64[1] == (a2)->as_u64[1]))
always_inline void
ip46_from_addr_buf (u32 is_ipv6, u8 * buf, ip46_address_t * ip)
diff --git a/src/vnet/pg/input.c b/src/vnet/pg/input.c
index 4a65b024f6c..2649798b109 100644
--- a/src/vnet/pg/input.c
+++ b/src/vnet/pg/input.c
@@ -1373,6 +1373,7 @@ typedef struct
u32 stream_index;
u32 packet_length;
+ u32 sw_if_index;
/* Use pre data for packet data. */
vlib_buffer_t buffer;
@@ -1399,6 +1400,7 @@ format_pg_input_trace (u8 * s, va_list * va)
s = format (s, "stream %d", t->stream_index);
s = format (s, ", %d bytes", t->packet_length);
+ s = format (s, ", %d sw_if_index", t->sw_if_index);
s = format (s, "\n%U%U",
format_white_space, indent, format_vlib_buffer, &t->buffer);
@@ -1458,6 +1460,9 @@ pg_input_trace (pg_main_t * pg,
t0->packet_length = vlib_buffer_length_in_chain (vm, b0);
t1->packet_length = vlib_buffer_length_in_chain (vm, b1);
+ t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ t1->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+
clib_memcpy (&t0->buffer, b0, sizeof (b0[0]) - sizeof (b0->pre_data));
clib_memcpy (&t1->buffer, b1, sizeof (b1[0]) - sizeof (b1->pre_data));
@@ -1484,6 +1489,7 @@ pg_input_trace (pg_main_t * pg,
t0->stream_index = stream_index;
t0->packet_length = vlib_buffer_length_in_chain (vm, b0);
+ t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
clib_memcpy (&t0->buffer, b0, sizeof (b0[0]) - sizeof (b0->pre_data));
clib_memcpy (t0->buffer.pre_data, b0->data,
sizeof (t0->buffer.pre_data));
diff --git a/test/test_dhcp.py b/test/test_dhcp.py
index a09c9bdb0b4..89667d3d1fc 100644
--- a/test/test_dhcp.py
+++ b/test/test_dhcp.py
@@ -2,8 +2,10 @@
import unittest
import socket
+import struct
from framework import VppTestCase, VppTestRunner
+from vpp_neighbor import VppNeighbor
from scapy.layers.l2 import Ether, getmacbyip
from scapy.layers.inet import IP, UDP, ICMP
@@ -11,7 +13,7 @@ from scapy.layers.inet6 import IPv6, in6_getnsmac, in6_mactoifaceid
from scapy.layers.dhcp import DHCP, BOOTP, DHCPTypes
from scapy.layers.dhcp6 import DHCP6, DHCP6_Solicit, DHCP6_RelayForward, \
DHCP6_RelayReply, DHCP6_Advertise, DHCP6OptRelayMsg, DHCP6OptIfaceId, \
- DHCP6OptStatusCode, DHCP6OptVSS, DHCP6OptClientLinkLayerAddr
+ DHCP6OptStatusCode, DHCP6OptVSS, DHCP6OptClientLinkLayerAddr, DHCP6_Request
from socket import AF_INET, AF_INET6
from scapy.utils import inet_pton, inet_ntop
from scapy.utils6 import in6_ptop
@@ -140,7 +142,7 @@ class TestDHCP(VppTestCase):
return data
- def verify_dhcp_offer(self, pkt, intf):
+ def verify_dhcp_offer(self, pkt, intf, fib_id=0, oui=0):
ether = pkt[Ether]
self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
self.assertEqual(ether.src, intf.local_mac)
@@ -162,15 +164,22 @@ class TestDHCP(VppTestCase):
is_offer = True
self.assertTrue(is_offer)
- data = self.validate_relay_options(pkt, intf, intf.local_ip4, 0, 0)
+ data = self.validate_relay_options(pkt, intf, intf.local_ip4,
+ fib_id, oui)
+
+ def verify_dhcp_discover(self, pkt, intf, src_intf=None, fib_id=0, oui=0,
+ dst_mac=None, dst_ip=None):
+ if not dst_mac:
+ dst_mac = intf.remote_mac
+ if not dst_ip:
+ dst_ip = intf.remote_ip4
- def verify_dhcp_discover(self, pkt, intf, src_intf=None, fib_id=0, oui=0):
ether = pkt[Ether]
- self.assertEqual(ether.dst, intf.remote_mac)
+ self.assertEqual(ether.dst, dst_mac)
self.assertEqual(ether.src, intf.local_mac)
ip = pkt[IP]
- self.assertEqual(ip.dst, intf.remote_ip4)
+ self.assertEqual(ip.dst, dst_ip)
self.assertEqual(ip.src, intf.local_ip4)
udp = pkt[UDP]
@@ -195,13 +204,20 @@ class TestDHCP(VppTestCase):
def verify_dhcp6_solicit(self, pkt, intf,
peer_ip, peer_mac,
fib_id=0,
- oui=0):
+ oui=0,
+ dst_mac=None,
+ dst_ip=None):
+ if not dst_mac:
+ dst_mac = intf.remote_mac
+ if not dst_ip:
+ dst_ip = in6_ptop(intf.remote_ip6)
+
ether = pkt[Ether]
- self.assertEqual(ether.dst, intf.remote_mac)
+ self.assertEqual(ether.dst, dst_mac)
self.assertEqual(ether.src, intf.local_mac)
ip = pkt[IPv6]
- self.assertEqual(in6_ptop(ip.dst), in6_ptop(intf.remote_ip6))
+ self.assertEqual(in6_ptop(ip.dst), dst_ip)
self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6))
udp = pkt[UDP]
@@ -453,6 +469,128 @@ class TestDHCP(VppTestCase):
fib_id=1, oui=4)
#
+ # Add a second DHCP server in VRF 1
+ # expect clients messages to be relay to both configured servers
+ #
+ self.pg1.generate_remote_hosts(2)
+ server_addr2 = socket.inet_pton(AF_INET, self.pg1.remote_hosts[1].ip4)
+
+ self.vapi.dhcp_proxy_config(server_addr2,
+ src_addr,
+ rx_table_id=1,
+ server_table_id=1,
+ is_add=1)
+
+ #
+ # We'll need an ARP entry for the server to send it packets
+ #
+ arp_entry = VppNeighbor(self,
+ self.pg1.sw_if_index,
+ self.pg1.remote_hosts[1].mac,
+ self.pg1.remote_hosts[1].ip4)
+ arp_entry.add_vpp_config()
+
+ #
+ # Send a discover from the client. expect two relayed messages
+ # The frist packet is sent to the second server
+ # We're not enforcing that here, it's just the way it is.
+ #
+ self.pg3.add_stream(pkts_disc_vrf1)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg1.get_capture(2)
+
+ option_82 = self.verify_dhcp_discover(
+ rx[0], self.pg1,
+ src_intf=self.pg3,
+ dst_mac=self.pg1.remote_hosts[1].mac,
+ dst_ip=self.pg1.remote_hosts[1].ip4,
+ fib_id=1, oui=4)
+ self.verify_dhcp_discover(rx[1], self.pg1, src_intf=self.pg3,
+ fib_id=1, oui=4)
+
+ #
+ # Send both packets back. Client gets both.
+ #
+ p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
+ IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) /
+ UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
+ BOOTP(op=1) /
+ DHCP(options=[('message-type', 'offer'),
+ ('relay_agent_Information', option_82),
+ ('end')]))
+ p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
+ IP(src=self.pg1.remote_hosts[1].ip4, dst=self.pg1.local_ip4) /
+ UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
+ BOOTP(op=1) /
+ DHCP(options=[('message-type', 'offer'),
+ ('relay_agent_Information', option_82),
+ ('end')]))
+ pkts = [p1, p2]
+
+ self.pg1.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg3.get_capture(2)
+
+ self.verify_dhcp_offer(rx[0], self.pg3, fib_id=1, oui=4)
+ self.verify_dhcp_offer(rx[1], self.pg3, fib_id=1, oui=4)
+
+ #
+ # Ensure offers from non-servers are dropeed
+ #
+ p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
+ IP(src="8.8.8.8", dst=self.pg1.local_ip4) /
+ UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
+ BOOTP(op=1) /
+ DHCP(options=[('message-type', 'offer'),
+ ('relay_agent_Information', option_82),
+ ('end')]))
+ self.send_and_assert_no_replies(self.pg1, p2,
+ "DHCP offer from non-server")
+
+ #
+ # Ensure only the discover is sent to multiple servers
+ #
+ p_req_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
+ src=self.pg3.remote_mac) /
+ IP(src="0.0.0.0", dst="255.255.255.255") /
+ UDP(sport=DHCP4_CLIENT_PORT,
+ dport=DHCP4_SERVER_PORT) /
+ BOOTP(op=1) /
+ DHCP(options=[('message-type', 'request'),
+ ('end')]))
+
+ self.pg3.add_stream(p_req_vrf1)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg1.get_capture(1)
+
+ #
+ # Remove the second DHCP server
+ #
+ self.vapi.dhcp_proxy_config(server_addr2,
+ src_addr,
+ rx_table_id=1,
+ server_table_id=1,
+ is_add=0)
+
+ #
+ # Test we can still relay with the first
+ #
+ self.pg3.add_stream(pkts_disc_vrf1)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg1.get_capture(1)
+ rx = rx[0]
+ self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3,
+ fib_id=1, oui=4)
+
+ #
# Remove the VSS config
# relayed DHCP has default vlaues in the option.
#
@@ -472,7 +610,7 @@ class TestDHCP(VppTestCase):
self.vapi.dhcp_proxy_config(server_addr,
src_addr,
rx_table_id=1,
- server_table_id=11,
+ server_table_id=1,
is_add=0)
self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0,
@@ -500,18 +638,16 @@ class TestDHCP(VppTestCase):
UDP(sport=DHCP6_SERVER_PORT,
dport=DHCP6_CLIENT_PORT) /
DHCP6_Solicit())
- pkts_solicit_vrf0 = [p_solicit_vrf0]
p_solicit_vrf1 = (Ether(dst=dmac, src=self.pg3.remote_mac) /
IPv6(src=dhcp_solicit_src_vrf1,
dst=dhcp_solicit_dst) /
UDP(sport=DHCP6_SERVER_PORT,
dport=DHCP6_CLIENT_PORT) /
DHCP6_Solicit())
- pkts_solicit_vrf1 = [p_solicit_vrf1]
- self.send_and_assert_no_replies(self.pg2, pkts_solicit_vrf0,
+ self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0,
"DHCP with no configuration")
- self.send_and_assert_no_replies(self.pg3, pkts_solicit_vrf1,
+ self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1,
"DHCP with no configuration")
#
@@ -525,9 +661,9 @@ class TestDHCP(VppTestCase):
server_table_id=0,
is_ipv6=1)
- self.send_and_assert_no_replies(self.pg2, pkts_solicit_vrf0,
+ self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0,
"DHCP with no configuration")
- self.send_and_assert_no_replies(self.pg3, pkts_solicit_vrf1,
+ self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1,
"DHCP with no configuration")
#
@@ -538,13 +674,13 @@ class TestDHCP(VppTestCase):
#
# Now the DHCP requests are relayed to the server
#
- self.pg2.add_stream(pkts_solicit_vrf0)
+ self.pg2.add_stream(p_solicit_vrf0)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
rx = self.pg0.get_capture(1)
- rx = rx[0]
- self.verify_dhcp6_solicit(rx, self.pg0,
+
+ self.verify_dhcp6_solicit(rx[0], self.pg0,
dhcp_solicit_src_vrf0,
self.pg2.remote_mac)
@@ -557,8 +693,7 @@ class TestDHCP(VppTestCase):
IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
DHCP6_Advertise())
- pkts_adv_vrf0 = [p_adv_vrf0]
- self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0,
+ self.send_and_assert_no_replies(self.pg2, p_adv_vrf0,
"DHCP6 not a relay reply")
# 2 - no relay message option
@@ -567,8 +702,7 @@ class TestDHCP(VppTestCase):
UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
DHCP6_RelayReply() /
DHCP6_Advertise())
- pkts_adv_vrf0 = [p_adv_vrf0]
- self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0,
+ self.send_and_assert_no_replies(self.pg2, p_adv_vrf0,
"DHCP not a relay message")
# 3 - no circuit ID
@@ -578,8 +712,7 @@ class TestDHCP(VppTestCase):
DHCP6_RelayReply() /
DHCP6OptRelayMsg(optlen=0) /
DHCP6_Advertise())
- pkts_adv_vrf0 = [p_adv_vrf0]
- self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0,
+ self.send_and_assert_no_replies(self.pg2, p_adv_vrf0,
"DHCP6 no circuit ID")
# 4 - wrong circuit ID
p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
@@ -589,8 +722,7 @@ class TestDHCP(VppTestCase):
DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') /
DHCP6OptRelayMsg(optlen=0) /
DHCP6_Advertise())
- pkts_adv_vrf0 = [p_adv_vrf0]
- self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0,
+ self.send_and_assert_no_replies(self.pg2, p_adv_vrf0,
"DHCP6 wrong circuit ID")
#
@@ -611,8 +743,8 @@ class TestDHCP(VppTestCase):
self.pg_start()
rx = self.pg2.get_capture(1)
- rx = rx[0]
- self.verify_dhcp6_advert(rx, self.pg2, "::")
+
+ self.verify_dhcp6_advert(rx[0], self.pg2, "::")
#
# Send the relay response (the advertisement)
@@ -632,8 +764,8 @@ class TestDHCP(VppTestCase):
self.pg_start()
rx = self.pg2.get_capture(1)
- rx = rx[0]
- self.verify_dhcp6_advert(rx, self.pg2, dhcp_solicit_src_vrf0)
+
+ self.verify_dhcp6_advert(rx[0], self.pg2, dhcp_solicit_src_vrf0)
#
# Add all the config for VRF 1
@@ -648,13 +780,13 @@ class TestDHCP(VppTestCase):
#
# VRF 1 solicit
#
- self.pg3.add_stream(pkts_solicit_vrf1)
+ self.pg3.add_stream(p_solicit_vrf1)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
rx = self.pg1.get_capture(1)
- rx = rx[0]
- self.verify_dhcp6_solicit(rx, self.pg1,
+
+ self.verify_dhcp6_solicit(rx[0], self.pg1,
dhcp_solicit_src_vrf1,
self.pg3.remote_mac)
@@ -676,21 +808,21 @@ class TestDHCP(VppTestCase):
self.pg_start()
rx = self.pg3.get_capture(1)
- rx = rx[0]
- self.verify_dhcp6_advert(rx, self.pg3, dhcp_solicit_src_vrf1)
+
+ self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1)
#
# Add VSS config
# table=1, fib=id=1, oui=4
self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1)
- self.pg3.add_stream(pkts_solicit_vrf1)
+ self.pg3.add_stream(p_solicit_vrf1)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
rx = self.pg1.get_capture(1)
- rx = rx[0]
- self.verify_dhcp6_solicit(rx, self.pg1,
+
+ self.verify_dhcp6_solicit(rx[0], self.pg1,
dhcp_solicit_src_vrf1,
self.pg3.remote_mac,
fib_id=1,
@@ -702,27 +834,163 @@ class TestDHCP(VppTestCase):
#
self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1, is_add=0)
- self.pg3.add_stream(pkts_solicit_vrf1)
+ self.pg3.add_stream(p_solicit_vrf1)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
rx = self.pg1.get_capture(1)
- rx = rx[0]
- self.verify_dhcp6_solicit(rx, self.pg1,
+
+ self.verify_dhcp6_solicit(rx[0], self.pg1,
dhcp_solicit_src_vrf1,
self.pg3.remote_mac)
#
- # Cleanup
+ # Add a second DHCP server in VRF 1
+ # expect clients messages to be relay to both configured servers
#
- self.vapi.dhcp_proxy_config(server_addr_vrf1,
+ self.pg1.generate_remote_hosts(2)
+ server_addr2 = socket.inet_pton(AF_INET6, self.pg1.remote_hosts[1].ip6)
+
+ self.vapi.dhcp_proxy_config(server_addr2,
+ src_addr_vrf1,
+ rx_table_id=1,
+ server_table_id=1,
+ is_ipv6=1)
+
+ #
+ # We'll need an ND entry for the server to send it packets
+ #
+ nd_entry = VppNeighbor(self,
+ self.pg1.sw_if_index,
+ self.pg1.remote_hosts[1].mac,
+ self.pg1.remote_hosts[1].ip6,
+ af=AF_INET6)
+ nd_entry.add_vpp_config()
+
+ #
+ # Send a discover from the client. expect two relayed messages
+ # The frist packet is sent to the second server
+ # We're not enforcing that here, it's just the way it is.
+ #
+ self.pg3.add_stream(p_solicit_vrf1)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg1.get_capture(2)
+
+ self.verify_dhcp6_solicit(rx[0], self.pg1,
+ dhcp_solicit_src_vrf1,
+ self.pg3.remote_mac)
+ self.verify_dhcp6_solicit(rx[1], self.pg1,
+ dhcp_solicit_src_vrf1,
+ self.pg3.remote_mac,
+ dst_mac=self.pg1.remote_hosts[1].mac,
+ dst_ip=self.pg1.remote_hosts[1].ip6)
+
+ #
+ # Send both packets back. Client gets both.
+ #
+ p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
+ IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) /
+ UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
+ DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) /
+ DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') /
+ DHCP6OptRelayMsg(optlen=0) /
+ DHCP6_Advertise(trid=1) /
+ DHCP6OptStatusCode(statuscode=0))
+ p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac) /
+ IPv6(dst=self.pg1.local_ip6, src=self.pg1._remote_hosts[1].ip6) /
+ UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
+ DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) /
+ DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') /
+ DHCP6OptRelayMsg(optlen=0) /
+ DHCP6_Advertise(trid=1) /
+ DHCP6OptStatusCode(statuscode=0))
+
+ pkts = [p1, p2]
+
+ self.pg1.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg3.get_capture(2)
+
+ self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1)
+ self.verify_dhcp6_advert(rx[1], self.pg3, dhcp_solicit_src_vrf1)
+
+ #
+ # Ensure only solicit messages are duplicated
+ #
+ p_request_vrf1 = (Ether(dst=dmac, src=self.pg3.remote_mac) /
+ IPv6(src=dhcp_solicit_src_vrf1,
+ dst=dhcp_solicit_dst) /
+ UDP(sport=DHCP6_SERVER_PORT,
+ dport=DHCP6_CLIENT_PORT) /
+ DHCP6_Request())
+
+ self.pg3.add_stream(p_request_vrf1)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg1.get_capture(1)
+
+ #
+ # Test we drop DHCP packets from addresses that are not configured as
+ # DHCP servers
+ #
+ p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac) /
+ IPv6(dst=self.pg1.local_ip6, src="3001::1") /
+ UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
+ DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) /
+ DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') /
+ DHCP6OptRelayMsg(optlen=0) /
+ DHCP6_Advertise(trid=1) /
+ DHCP6OptStatusCode(statuscode=0))
+ self.send_and_assert_no_replies(self.pg1, p2,
+ "DHCP6 not from server")
+
+ #
+ # Remove the second DHCP server
+ #
+ self.vapi.dhcp_proxy_config(server_addr2,
src_addr_vrf1,
rx_table_id=1,
server_table_id=1,
is_ipv6=1,
is_add=0)
+
+ #
+ # Test we can still relay with the first
+ #
+ self.pg3.add_stream(p_solicit_vrf1)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg1.get_capture(1)
+
+ self.verify_dhcp6_solicit(rx[0], self.pg1,
+ dhcp_solicit_src_vrf1,
+ self.pg3.remote_mac)
+
+ #
+ # Cleanup
+ #
self.vapi.dhcp_proxy_config(server_addr_vrf1,
src_addr_vrf1,
+ rx_table_id=1,
+ server_table_id=1,
+ is_ipv6=1,
+ is_add=0)
+ self.vapi.dhcp_proxy_config(server_addr_vrf0,
+ src_addr_vrf0,
+ rx_table_id=0,
+ server_table_id=0,
+ is_ipv6=1,
+ is_add=0)
+
+ # duplicate delete
+ self.vapi.dhcp_proxy_config(server_addr_vrf0,
+ src_addr_vrf0,
rx_table_id=0,
server_table_id=0,
is_ipv6=1,