aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/dhcp/dhcp6_proxy_node.c
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 /src/vnet/dhcp/dhcp6_proxy_node.c
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>
Diffstat (limited to 'src/vnet/dhcp/dhcp6_proxy_node.c')
-rw-r--r--src/vnet/dhcp/dhcp6_proxy_node.c158
1 files changed, 118 insertions, 40 deletions
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 */);