diff options
author | Neale Ranns <nranns@cisco.com> | 2019-10-07 00:39:28 -0700 |
---|---|---|
committer | Dave Barach <openvpp@barachs.net> | 2019-10-07 19:33:39 +0000 |
commit | 02bfd641b69aab83397e217b9ca4e35a6aab05c8 (patch) | |
tree | 665e232425f90d0662bc3d29729e11bb5e8727fc /src | |
parent | 2c41a61d5fc87737b9b46b88cb9271d0f987721e (diff) |
dhcp: Move to plugin
Type: feature
Change-Id: I3fe27a8ef577741d9a5c4f090ec91cf68fb44fe3
Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/dhcp/CMakeLists.txt | 51 | ||||
-rw-r--r-- | src/plugins/dhcp/client.c (renamed from src/vnet/dhcp/client.c) | 4 | ||||
-rw-r--r-- | src/plugins/dhcp/client.h (renamed from src/vnet/dhcp/client.h) | 2 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp.api (renamed from src/vnet/dhcp/dhcp.api) | 48 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp4_packet.h (renamed from src/vnet/dhcp/dhcp4_packet.h) | 0 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp4_proxy_error.def (renamed from src/vnet/dhcp/dhcp4_proxy_error.def) | 0 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp4_proxy_node.c (renamed from src/vnet/dhcp/dhcp4_proxy_node.c) | 6 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_client_common_dp.c (renamed from src/vnet/dhcp/dhcp6_client_common_dp.c) | 96 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_client_common_dp.h (renamed from src/vnet/dhcp/dhcp6_client_common_dp.h) | 28 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_ia_na_client_cp.api (renamed from src/vnet/dhcp/dhcp6_ia_na_client_cp.api) | 0 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_ia_na_client_cp.c (renamed from src/vnet/dhcp/dhcp6_ia_na_client_cp.c) | 76 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_ia_na_client_cp_api.c | 80 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_ia_na_client_dp.c (renamed from src/vnet/dhcp/dhcp6_ia_na_client_dp.c) | 230 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_ia_na_client_dp.h (renamed from src/vnet/dhcp/dhcp6_ia_na_client_dp.h) | 23 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_packet.h (renamed from src/vnet/dhcp/dhcp6_packet.h) | 0 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_pd_client_cp.api (renamed from src/vnet/dhcp/dhcp6_pd_client_cp.api) | 0 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_pd_client_cp.c (renamed from src/vnet/dhcp/dhcp6_pd_client_cp.c) | 118 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_pd_client_cp_api.c | 102 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_pd_client_dp.c (renamed from src/vnet/dhcp/dhcp6_pd_client_dp.c) | 236 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_pd_client_dp.h (renamed from src/vnet/dhcp/dhcp6_pd_client_dp.h) | 23 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_pd_doc.md (renamed from src/vnet/dhcp/dhcp6_pd_doc.md) | 0 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_proxy_error.def (renamed from src/vnet/dhcp/dhcp6_proxy_error.def) | 0 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp6_proxy_node.c (renamed from src/vnet/dhcp/dhcp6_proxy_node.c) | 6 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp_api.c | 871 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp_client_detect.c (renamed from src/vnet/dhcp/dhcp_client_detect.c) | 2 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp_proxy.c (renamed from src/vnet/dhcp/dhcp_proxy.c) | 2 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp_proxy.h (renamed from src/vnet/dhcp/dhcp_proxy.h) | 6 | ||||
-rw-r--r-- | src/plugins/dhcp/dhcp_test.c | 492 | ||||
-rw-r--r-- | src/plugins/dhcp/test/test_dhcp.py | 1653 | ||||
-rw-r--r-- | src/plugins/dhcp/test/test_dhcp6.py | 806 | ||||
-rw-r--r-- | src/plugins/dhcp/test/vpp_dhcp.py | 129 | ||||
-rw-r--r-- | src/vat/api_format.c | 396 | ||||
-rw-r--r-- | src/vnet/CMakeLists.txt | 48 | ||||
-rw-r--r-- | src/vnet/dhcp/dhcp_api.c | 420 | ||||
-rw-r--r-- | src/vnet/vnet_all_api_h.h | 3 | ||||
-rw-r--r-- | src/vpp/api/custom_dump.c | 73 |
36 files changed, 4327 insertions, 1703 deletions
diff --git a/src/plugins/dhcp/CMakeLists.txt b/src/plugins/dhcp/CMakeLists.txt new file mode 100644 index 00000000000..b2dd630d461 --- /dev/null +++ b/src/plugins/dhcp/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (c) 2018 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_vpp_plugin(dhcp + SOURCES + client.c + dhcp_api.c + dhcp_client_detect.c + dhcp_proxy.c + dhcp4_proxy_node.c + dhcp6_client_common_dp.c + dhcp6_ia_na_client_dp.c + dhcp6_ia_na_client_cp.c + dhcp6_ia_na_client_cp_api.c + dhcp6_pd_client_cp.c + dhcp6_pd_client_cp_api.c + dhcp6_pd_client_dp.c + dhcp6_proxy_node.c + + MULTIARCH_SOURCES + dhcp_client_detect.c + + API_FILES + dhcp.api + dhcp6_pd_client_cp.api + dhcp6_ia_na_client_cp.api + + INSTALL_HEADERS + client.h + dhcp4_packet.h + dhcp6_packet.h + dhcp_proxy.h + dhcp6_proxy_error.def + dhcp4_proxy_error.def + dhcp6_client_common_dp.h + dhcp6_pd_client_dp.h + dhcp6_ia_na_client_dp.h + + API_TEST_SOURCES + dhcp_test.c +) diff --git a/src/vnet/dhcp/client.c b/src/plugins/dhcp/client.c index aaeda96327d..800da3e504a 100644 --- a/src/vnet/dhcp/client.c +++ b/src/plugins/dhcp/client.c @@ -14,8 +14,8 @@ */ #include <vlib/vlib.h> #include <vlibmemory/api.h> -#include <vnet/dhcp/client.h> -#include <vnet/dhcp/dhcp_proxy.h> +#include <dhcp/client.h> +#include <dhcp/dhcp_proxy.h> #include <vnet/fib/fib_table.h> #include <vnet/qos/qos_types.h> diff --git a/src/vnet/dhcp/client.h b/src/plugins/dhcp/client.h index 5191fcf0fa8..68176abadf6 100644 --- a/src/vnet/dhcp/client.h +++ b/src/plugins/dhcp/client.h @@ -20,7 +20,7 @@ #define included_dhcp_client_h #include <vnet/ip/ip.h> -#include <vnet/dhcp/dhcp4_packet.h> +#include <dhcp/dhcp4_packet.h> #define foreach_dhcp_client_state \ _(DHCP_DISCOVER) \ diff --git a/src/vnet/dhcp/dhcp.api b/src/plugins/dhcp/dhcp.api index f3fef5135f1..a91874be82c 100644 --- a/src/vnet/dhcp/dhcp.api +++ b/src/plugins/dhcp/dhcp.api @@ -49,6 +49,54 @@ enum dhcpv6_msg_type DHCPV6_MSG_API_RELAY_REPL = 13, }; +/** \brief Get the plugin version + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ + +define dhcp_plugin_get_version +{ + u32 client_index; + u32 context; +}; + +/** \brief Reply to get the plugin version + @param context - returned sender context, to match reply w/ request + @param major - Incremented every time a known breaking behavior change is introduced + @param minor - Incremented with small changes, may be used to avoid buggy versions +*/ + +define dhcp_plugin_get_version_reply +{ + u32 context; + u32 major; + u32 minor; +}; + +/** \brief Control ping from client to api server request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define dhcp_plugin_control_ping +{ + u32 client_index; + u32 context; +}; + +/** \brief Control ping from the client to the server response + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param retval - return code for the request + @param vpe_pid - the pid of the vpe, returned by the server +*/ +define dhcp_plugin_control_ping_reply +{ + u32 context; + i32 retval; + u32 client_index; + u32 vpe_pid; +}; + /** \brief DHCP Proxy config add / del request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/dhcp/dhcp4_packet.h b/src/plugins/dhcp/dhcp4_packet.h index 3076dd9529d..3076dd9529d 100644 --- a/src/vnet/dhcp/dhcp4_packet.h +++ b/src/plugins/dhcp/dhcp4_packet.h diff --git a/src/vnet/dhcp/dhcp4_proxy_error.def b/src/plugins/dhcp/dhcp4_proxy_error.def index adf04808fa3..adf04808fa3 100644 --- a/src/vnet/dhcp/dhcp4_proxy_error.def +++ b/src/plugins/dhcp/dhcp4_proxy_error.def diff --git a/src/vnet/dhcp/dhcp4_proxy_node.c b/src/plugins/dhcp/dhcp4_proxy_node.c index 3576f0cbf35..10963c7ff47 100644 --- a/src/vnet/dhcp/dhcp4_proxy_node.c +++ b/src/plugins/dhcp/dhcp4_proxy_node.c @@ -17,13 +17,13 @@ #include <vlib/vlib.h> #include <vnet/pg/pg.h> -#include <vnet/dhcp/dhcp_proxy.h> -#include <vnet/dhcp/client.h> +#include <dhcp/dhcp_proxy.h> +#include <dhcp/client.h> #include <vnet/fib/ip4_fib.h> static char *dhcp_proxy_error_strings[] = { #define dhcp_proxy_error(n,s) s, -#include <vnet/dhcp/dhcp4_proxy_error.def> +#include <dhcp/dhcp4_proxy_error.def> #undef dhcp_proxy_error }; diff --git a/src/vnet/dhcp/dhcp6_client_common_dp.c b/src/plugins/dhcp/dhcp6_client_common_dp.c index 7ca3b61defb..e42ec3f472c 100644 --- a/src/vnet/dhcp/dhcp6_client_common_dp.c +++ b/src/plugins/dhcp/dhcp6_client_common_dp.c @@ -14,10 +14,11 @@ */ #include <vnet/ethernet/ethernet.h> -#include <vnet/dhcp/dhcp6_client_common_dp.h> -#include <vnet/dhcp/dhcp6_ia_na_client_dp.h> -#include <vnet/dhcp/dhcp6_pd_client_dp.h> -#include <vnet/dhcp/dhcp6_packet.h> +#include <dhcp/dhcp6_packet.h> +#include <dhcp/dhcp6_client_common_dp.h> +#include <dhcp/dhcp6_ia_na_client_dp.h> +#include <dhcp/dhcp6_pd_client_dp.h> +#include <dhcp/dhcp6_packet.h> #include <vnet/udp/udp.h> dhcp6_client_common_main_t dhcp6_client_common_main; @@ -48,30 +49,11 @@ server_index_get_or_create (u8 * data, u16 len) return vec_len (ccm->server_ids) - 1; } -void -vl_api_dhcp6_duid_ll_set_t_handler (vl_api_dhcp6_duid_ll_set_t * mp) -{ - vl_api_dhcp6_duid_ll_set_reply_t *rmp; - dhcpv6_duid_ll_string_t *duid; - int rv = 0; - - duid = (dhcpv6_duid_ll_string_t *) mp->duid_ll; - if (duid->duid_type != htonl (DHCPV6_DUID_LL)) - { - rv = VNET_API_ERROR_INVALID_VALUE; - goto reply; - } - clib_memcpy (&client_duid, &duid, sizeof (client_duid)); - -reply: - REPLY_MACRO (VL_API_DHCP6_DUID_LL_SET_REPLY); -} - static void generate_client_duid (void) { - client_duid.duid_type = htons (DHCPV6_DUID_LL); - client_duid.hardware_type = htons (1); + client_duid.duid_type = clib_host_to_net_u16 (DHCPV6_DUID_LL); + client_duid.hardware_type = clib_host_to_net_u16 (1); vnet_main_t *vnm = vnet_get_main (); vnet_interface_main_t *im = &vnm->interface_main; @@ -190,8 +172,8 @@ dhcpv6_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, u32 dhcpv6_ip6_payload_offset = (u8 *) dhcpv60 - ((u8 *) ip0 + sizeof (*ip0)); options_length = - ntohs (ip0->payload_length) - dhcpv6_ip6_payload_offset - - sizeof (*dhcpv60); + clib_net_to_host_u16 (ip0->payload_length) - + dhcpv6_ip6_payload_offset - sizeof (*dhcpv60); clib_memset (&report, 0, sizeof (report)); @@ -232,22 +214,24 @@ dhcpv6_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, while (options_length > 0) { if (options_length < - ntohs (option->length) + sizeof (*option)) + clib_net_to_host_u16 (option->length) + + sizeof (*option)) { clib_warning ("remaining payload length < option length (%d < %d)", options_length, - ntohs (option->length) + sizeof (*option)); + clib_net_to_host_u16 (option->length) + + sizeof (*option)); break; } - u16 oo = ntohs (option->option); + u16 oo = clib_net_to_host_u16 (option->option); if (oo == DHCPV6_OPTION_IA_NA || oo == DHCPV6_OPTION_IA_PD) { u8 discard_option = 0; dhcpv6_ia_header_t *ia_header = (void *) option; - iaid = ntohl (ia_header->iaid); - u32 T1 = ntohl (ia_header->t1); - u32 T2 = ntohl (ia_header->t2); + iaid = clib_net_to_host_u32 (ia_header->iaid); + u32 T1 = clib_net_to_host_u32 (ia_header->t1); + u32 T2 = clib_net_to_host_u32 (ia_header->t2); if (iaid != DHCPV6_CLIENT_IAID) discard_option = 1; if (T1 != 0 && T2 != 0 && T1 > T2) @@ -260,11 +244,12 @@ dhcpv6_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, dhcpv6_option_t *inner_option = (void *) ia_header->data; u16 inner_options_length = - ntohs (option->length) - (sizeof (*ia_header) - - sizeof (dhcpv6_option_t)); + clib_net_to_host_u16 (option->length) - + (sizeof (*ia_header) - sizeof (dhcpv6_option_t)); while (inner_options_length > 0) { - u16 inner_oo = ntohs (inner_option->option); + u16 inner_oo = + clib_net_to_host_u16 (inner_option->option); if (discard_option) ; else if (inner_oo == DHCPV6_OPTION_IAADDR) @@ -276,9 +261,9 @@ dhcpv6_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, dhcp6_address_info_t *address_info = &addresses[n_addresses]; address_info->preferred_time = - ntohl (iaaddr->preferred); + clib_net_to_host_u32 (iaaddr->preferred); address_info->valid_time = - ntohl (iaaddr->valid); + clib_net_to_host_u32 (iaaddr->valid); address_info->address = iaaddr->addr; } else if (inner_oo == DHCPV6_OPTION_IAPREFIX) @@ -290,9 +275,9 @@ dhcpv6_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, dhcp6_prefix_info_t *prefix_info = &prefixes[n_prefixes]; prefix_info->preferred_time = - ntohl (iaprefix->preferred); + clib_net_to_host_u32 (iaprefix->preferred); prefix_info->valid_time = - ntohl (iaprefix->valid); + clib_net_to_host_u32 (iaprefix->valid); prefix_info->prefix_length = iaprefix->prefix; prefix_info->prefix = iaprefix->addr; } @@ -301,15 +286,16 @@ dhcpv6_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, dhcpv6_status_code_t *sc = (void *) inner_option; report.inner_status_code = - ntohs (sc->status_code); + clib_net_to_host_u16 (sc->status_code); } inner_options_length -= sizeof (*inner_option) + - ntohs (inner_option->length); + clib_net_to_host_u16 (inner_option->length); inner_option = (void *) ((u8 *) inner_option + sizeof (*inner_option) + - ntohs (inner_option->length)); + clib_net_to_host_u16 + (inner_option->length)); } } else if (oo == DHCPV6_OPTION_CLIENTID) @@ -322,7 +308,7 @@ dhcpv6_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, } else { - u16 len = ntohs (option->length); + u16 len = clib_net_to_host_u16 (option->length); client_id_present = 1; if (len != CLIENT_DUID_LENGTH || 0 != memcmp (option->data, @@ -345,7 +331,7 @@ dhcpv6_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, } else { - u16 ol = ntohs (option->length); + u16 ol = clib_net_to_host_u16 (option->length); if (ol - 2 /* 2 byte DUID type code */ > 128) { clib_warning @@ -366,12 +352,14 @@ dhcpv6_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, else if (oo == DHCPV6_OPTION_STATUS_CODE) { dhcpv6_status_code_t *sc = (void *) option; - report.status_code = ntohs (sc->status_code); + report.status_code = + clib_net_to_host_u16 (sc->status_code); } - options_length -= sizeof (*option) + ntohs (option->length); + options_length -= + sizeof (*option) + clib_net_to_host_u16 (option->length); option = (void *) ((u8 *) option + sizeof (*option) + - ntohs (option->length)); + clib_net_to_host_u16 (option->length)); } if (!client_id_present) @@ -472,18 +460,6 @@ dhcp6_clients_enable_disable (u8 enable) 0 /* is_ip6 */ ); } -void - vl_api_dhcp6_clients_enable_disable_t_handler - (vl_api_dhcp6_clients_enable_disable_t * mp) -{ - vl_api_dhcp6_clients_enable_disable_reply_t *rmp; - int rv = 0; - - dhcp6_clients_enable_disable (mp->enable); - - REPLY_MACRO (VL_API_DHCP6_CLIENTS_ENABLE_DISABLE_REPLY); -} - /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/dhcp/dhcp6_client_common_dp.h b/src/plugins/dhcp/dhcp6_client_common_dp.h index 0acef8408c6..4010aa07564 100644 --- a/src/vnet/dhcp/dhcp6_client_common_dp.h +++ b/src/plugins/dhcp/dhcp6_client_common_dp.h @@ -17,27 +17,7 @@ #define included_vnet_dhcp6_client_common_dp_h #include <vlib/vlib.h> -#include <vnet/dhcp/dhcp6_client_common_dp.h> -#include <vnet/dhcp/dhcp6_packet.h> -#include <vnet/vnet_msg_enum.h> -#include <vlibapi/api_common.h> -#include <vlibmemory/api.h> - -#define vl_typedefs /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_typedefs - -#define vl_endianfun /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) -#define vl_printfun -#include <vnet/vnet_all_api_h.h> -#undef vl_printfun - -#include <vlibapi/api_helper_macros.h> +#include <dhcp/dhcp6_packet.h> typedef struct { @@ -82,11 +62,7 @@ extern dhcpv6_duid_ll_string_t client_duid; void dhcp6_clients_enable_disable (u8 enable); u32 server_index_get_or_create (u8 * data, u16 len); -#define vl_typedefs /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_typedefs - -void vl_api_dhcp6_duid_ll_set_t_handler (vl_api_dhcp6_duid_ll_set_t * mp); +extern dhcpv6_duid_ll_string_t client_duid; static_always_inline f64 random_f64_from_to (f64 from, f64 to) diff --git a/src/vnet/dhcp/dhcp6_ia_na_client_cp.api b/src/plugins/dhcp/dhcp6_ia_na_client_cp.api index caa4fd4afc8..caa4fd4afc8 100644 --- a/src/vnet/dhcp/dhcp6_ia_na_client_cp.api +++ b/src/plugins/dhcp/dhcp6_ia_na_client_cp.api diff --git a/src/vnet/dhcp/dhcp6_ia_na_client_cp.c b/src/plugins/dhcp/dhcp6_ia_na_client_cp.c index e440805d707..2d4135d7ebd 100644 --- a/src/vnet/dhcp/dhcp6_ia_na_client_cp.c +++ b/src/plugins/dhcp/dhcp6_ia_na_client_cp.c @@ -16,28 +16,13 @@ #include <vnet/vnet.h> #include <vlibmemory/api.h> #include <vnet/vnet_msg_enum.h> -#include <vnet/dhcp/dhcp6_packet.h> -#include <vnet/dhcp/dhcp6_ia_na_client_dp.h> +#include <dhcp/dhcp6_packet.h> +#include <dhcp/dhcp6_ia_na_client_dp.h> #include <vnet/ip/ip.h> #include <vnet/ip/ip6.h> #include <float.h> #include <math.h> -#define vl_typedefs /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_typedefs - -#define vl_endianfun /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_endianfun - -#include <vlibapi/api_helper_macros.h> - -#define foreach_dhcp6_client_cp_msg \ -_(DHCP6_CLIENT_ENABLE_DISABLE, dhcp6_client_enable_disable) - -#define vl_api_dhcp6_client_enable_disable_t_print vl_noop_handler - typedef struct { u32 sw_if_index; @@ -622,7 +607,7 @@ VLIB_CLI_COMMAND (dhcp6_clients_show_command, static) = { }; /* *INDENT-ON* */ -static int +int dhcp6_client_enable_disable (u32 sw_if_index, u8 enable) { dhcp6_client_cp_main_t *rm = &dhcp6_client_cp_main; @@ -766,67 +751,20 @@ VLIB_CLI_COMMAND (dhcp6_client_enable_disable_command, static) = { }; /* *INDENT-ON* */ -static void - vl_api_dhcp6_client_enable_disable_t_handler - (vl_api_dhcp6_client_enable_disable_t * mp) -{ - vl_api_dhcp6_client_enable_disable_reply_t *rmp; - u32 sw_if_index; - int rv = 0; - - VALIDATE_SW_IF_INDEX (mp); - - sw_if_index = ntohl (mp->sw_if_index); - - rv = dhcp6_client_enable_disable (sw_if_index, mp->enable); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_SW_INTERFACE_SET_TABLE_REPLY); -} - -#define vl_msg_name_crc_list -#include <vnet/dhcp/dhcp6_ia_na_client_cp.api.h> -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (api_main_t * am) -{ -#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id); - foreach_vl_msg_name_crc_dhcp6_ia_na_client_cp; -#undef _ -} - static clib_error_t * -dhcp_client_cp_init (vlib_main_t * vm) +dhcp_ia_na_client_cp_init (vlib_main_t * vm) { dhcp6_client_cp_main_t *rm = &dhcp6_client_cp_main; - api_main_t *am = &api_main; rm->vlib_main = vm; rm->vnet_main = vnet_get_main (); - rm->api_main = am; + rm->api_main = &api_main; rm->node_index = dhcp6_client_cp_process_node.index; -#define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N, #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_api_##n##_t_endian, \ - vl_api_##n##_t_print, \ - sizeof(vl_api_##n##_t), 0/* do NOT trace! */); - foreach_dhcp6_client_cp_msg; -#undef _ - - /* - * Set up the (msg_name, crc, message-id) table - */ - setup_message_id_table (am); - - return 0; + return NULL; } -VLIB_INIT_FUNCTION (dhcp_client_cp_init); +VLIB_INIT_FUNCTION (dhcp_ia_na_client_cp_init); /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/dhcp/dhcp6_ia_na_client_cp_api.c b/src/plugins/dhcp/dhcp6_ia_na_client_cp_api.c new file mode 100644 index 00000000000..8e5898adb36 --- /dev/null +++ b/src/plugins/dhcp/dhcp6_ia_na_client_cp_api.c @@ -0,0 +1,80 @@ +/* + *------------------------------------------------------------------ + * dhcp_api.c - dhcp api + * + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include <vnet/vnet.h> +#include <vlibmemory/api.h> + +#include <dhcp/dhcp6_ia_na_client_dp.h> + +/* define message IDs */ +#include <vnet/format_fns.h> +#include <dhcp/dhcp6_ia_na_client_cp.api_enum.h> +#include <dhcp/dhcp6_ia_na_client_cp.api_types.h> + +/** + * Base message ID fot the plugin + */ +static u32 dhcp_base_msg_id; +#define REPLY_MSG_ID_BASE dhcp_base_msg_id + +#include <vlibapi/api_helper_macros.h> + +static void + vl_api_dhcp6_client_enable_disable_t_handler + (vl_api_dhcp6_client_enable_disable_t * mp) +{ + vl_api_dhcp6_client_enable_disable_reply_t *rmp; + u32 sw_if_index; + int rv = 0; + + VALIDATE_SW_IF_INDEX (mp); + + sw_if_index = ntohl (mp->sw_if_index); + + rv = dhcp6_client_enable_disable (sw_if_index, mp->enable); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_DHCP6_CLIENT_ENABLE_DISABLE_REPLY); +} + +#define vl_msg_name_crc_list +#include <dhcp/dhcp6_ia_na_client_cp.api.c> +#undef vl_msg_name_crc_list + +static clib_error_t * +dhcp_ia_na_client_cp_api_init (vlib_main_t * vm) +{ + /* + * Set up the (msg_name, crc, message-id) table + */ + dhcp_base_msg_id = setup_message_id_table (); + + return 0; +} + +VLIB_INIT_FUNCTION (dhcp_ia_na_client_cp_api_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/dhcp/dhcp6_ia_na_client_dp.c b/src/plugins/dhcp/dhcp6_ia_na_client_dp.c index f49017b0236..6ea822fff48 100644 --- a/src/vnet/dhcp/dhcp6_ia_na_client_dp.c +++ b/src/plugins/dhcp/dhcp6_ia_na_client_dp.c @@ -14,37 +14,17 @@ */ #include <vlib/vlib.h> -#include <vnet/dhcp/dhcp6_packet.h> -#include <vnet/dhcp/dhcp_proxy.h> +#include <dhcp/dhcp6_packet.h> +#include <dhcp/dhcp_proxy.h> #include <vnet/mfib/mfib_table.h> #include <vnet/mfib/ip6_mfib.h> #include <vnet/fib/fib.h> #include <vnet/adj/adj_mcast.h> #include <vnet/ip/ip6_neighbor.h> -#include <vlibapi/api_common.h> -#include <vlibmemory/api.h> -#include <vnet/dhcp/dhcp6_ia_na_client_dp.h> -#include <vnet/dhcp/dhcp6_client_common_dp.h> +#include <dhcp/dhcp6_ia_na_client_dp.h> +#include <dhcp/dhcp6_client_common_dp.h> #include <vnet/ip/ip_types_api.h> -#include <vnet/vnet_msg_enum.h> - -#define vl_typedefs /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_typedefs - -#define vl_endianfun /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) -#define vl_printfun -#include <vnet/vnet_all_api_h.h> -#undef vl_printfun - -#include <vlibapi/api_helper_macros.h> - dhcp6_ia_na_client_main_t dhcp6_ia_na_client_main; dhcp6_ia_na_client_public_main_t dhcp6_ia_na_client_public_main; @@ -430,208 +410,6 @@ dhcp6_send_client_message (vlib_main_t * vm, u32 sw_if_index, u8 stop, } } -void - vl_api_dhcp6_send_client_message_t_handler - (vl_api_dhcp6_send_client_message_t * mp) -{ - vl_api_dhcp6_send_client_message_reply_t *rmp; - dhcp6_send_client_message_params_t params; - vlib_main_t *vm = vlib_get_main (); - u32 n_addresses; - u32 i; - int rv = 0; - - VALIDATE_SW_IF_INDEX (mp); - - BAD_SW_IF_INDEX_LABEL; - REPLY_MACRO (VL_API_DHCP6_SEND_CLIENT_MESSAGE_REPLY); - - if (rv != 0) - return; - - params.sw_if_index = ntohl (mp->sw_if_index); - params.server_index = ntohl (mp->server_index); - params.irt = ntohl (mp->irt); - params.mrt = ntohl (mp->mrt); - params.mrc = ntohl (mp->mrc); - params.mrd = ntohl (mp->mrd); - params.msg_type = ntohl (mp->msg_type); - params.T1 = ntohl (mp->T1); - params.T2 = ntohl (mp->T2); - n_addresses = ntohl (mp->n_addresses); - params.addresses = 0; - if (n_addresses > 0) - vec_validate (params.addresses, n_addresses - 1); - for (i = 0; i < n_addresses; i++) - { - vl_api_dhcp6_address_info_t *ai = &mp->addresses[i]; - dhcp6_send_client_message_params_address_t *addr = ¶ms.addresses[i]; - addr->preferred_lt = ntohl (ai->preferred_time); - addr->valid_lt = ntohl (ai->valid_time); - ip6_address_decode (ai->address, &addr->address); - } - - dhcp6_send_client_message (vm, ntohl (mp->sw_if_index), mp->stop, ¶ms); -} - -clib_error_t * -call_dhcp6_reply_event_callbacks (void *data, - _vnet_dhcp6_reply_event_function_list_elt_t - * elt) -{ - clib_error_t *error = 0; - - while (elt) - { - error = elt->fp (data); - if (error) - return error; - elt = elt->next_dhcp6_reply_event_function; - } - - return error; -} - -static uword -dhcp6_reply_process (vlib_main_t * vm, vlib_node_runtime_t * rt, - vlib_frame_t * f) -{ - /* These cross the longjmp boundary (vlib_process_wait_for_event) - * and need to be volatile - to prevent them from being optimized into - * a register - which could change during suspension */ - - while (1) - { - vlib_process_wait_for_event (vm); - uword event_type = DHCP6_DP_REPLY_REPORT; - void *event_data = vlib_process_get_event_data (vm, &event_type); - - int i; - if (event_type == DHCP6_DP_REPLY_REPORT) - { - address_report_t *events = event_data; - for (i = 0; i < vec_len (events); i++) - { - u32 event_size = - sizeof (vl_api_dhcp6_reply_event_t) + - vec_len (events[i].addresses) * - sizeof (vl_api_dhcp6_address_info_t); - vl_api_dhcp6_reply_event_t *event = clib_mem_alloc (event_size); - clib_memset (event, 0, event_size); - - event->sw_if_index = htonl (events[i].body.sw_if_index); - event->server_index = htonl (events[i].body.server_index); - event->msg_type = events[i].body.msg_type; - event->T1 = htonl (events[i].body.T1); - event->T2 = htonl (events[i].body.T2); - event->inner_status_code = - htons (events[i].body.inner_status_code); - event->status_code = htons (events[i].body.status_code); - event->preference = events[i].body.preference; - - event->n_addresses = htonl (vec_len (events[i].addresses)); - vl_api_dhcp6_address_info_t *address = - (typeof (address)) event->addresses; - u32 j; - for (j = 0; j < vec_len (events[i].addresses); j++) - { - dhcp6_address_info_t *info = &events[i].addresses[j]; - ip6_address_encode (&info->address, address->address); - address->valid_time = htonl (info->valid_time); - address->preferred_time = htonl (info->preferred_time); - address++; - } - vec_free (events[i].addresses); - - dhcp6_ia_na_client_public_main_t *dcpm = - &dhcp6_ia_na_client_public_main; - call_dhcp6_reply_event_callbacks (event, dcpm->functions); - - vpe_client_registration_t *reg; - /* *INDENT-OFF* */ - pool_foreach(reg, vpe_api_main.dhcp6_reply_events_registrations, - ({ - vl_api_registration_t *vl_reg; - vl_reg = - vl_api_client_index_to_registration (reg->client_index); - if (vl_reg && vl_api_can_send_msg (vl_reg)) - { - vl_api_dhcp6_reply_event_t *msg = - vl_msg_api_alloc (event_size); - clib_memcpy (msg, event, event_size); - msg->_vl_msg_id = htons (VL_API_DHCP6_REPLY_EVENT); - msg->client_index = reg->client_index; - msg->pid = reg->client_pid; - vl_api_send_msg (vl_reg, (u8 *) msg); - } - })); - /* *INDENT-ON* */ - - clib_mem_free (event); - } - } - vlib_process_put_event_data (vm, event_data); - } - - return 0; -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (dhcp6_reply_process_node) = { - .function = dhcp6_reply_process, - .type = VLIB_NODE_TYPE_PROCESS, - .name = "dhcp6-reply-publisher-process", -}; -/* *INDENT-ON* */ - -void - vl_api_want_dhcp6_reply_events_t_handler - (vl_api_want_dhcp6_reply_events_t * mp) -{ - vpe_api_main_t *am = &vpe_api_main; - vl_api_want_dhcp6_reply_events_reply_t *rmp; - int rv = 0; - - uword *p = - hash_get (am->dhcp6_reply_events_registration_hash, mp->client_index); - vpe_client_registration_t *rp; - if (p) - { - if (mp->enable_disable) - { - clib_warning ("pid %d: already enabled...", ntohl (mp->pid)); - rv = VNET_API_ERROR_INVALID_REGISTRATION; - goto reply; - } - else - { - rp = pool_elt_at_index (am->dhcp6_reply_events_registrations, p[0]); - pool_put (am->dhcp6_reply_events_registrations, rp); - hash_unset (am->dhcp6_reply_events_registration_hash, - mp->client_index); - if (pool_elts (am->dhcp6_reply_events_registrations) == 0) - dhcp6_set_publisher_node (~0, DHCP6_DP_REPORT_MAX); - goto reply; - } - } - if (mp->enable_disable == 0) - { - clib_warning ("pid %d: already disabled...", ntohl (mp->pid)); - rv = VNET_API_ERROR_INVALID_REGISTRATION; - goto reply; - } - pool_get (am->dhcp6_reply_events_registrations, rp); - rp->client_index = mp->client_index; - rp->client_pid = ntohl (mp->pid); - hash_set (am->dhcp6_reply_events_registration_hash, rp->client_index, - rp - am->dhcp6_reply_events_registrations); - dhcp6_set_publisher_node (dhcp6_reply_process_node.index, - DHCP6_DP_REPLY_REPORT); - -reply: - REPLY_MACRO (VL_API_WANT_DHCP6_REPLY_EVENTS_REPLY); -} - static clib_error_t * dhcp6_client_init (vlib_main_t * vm) { diff --git a/src/vnet/dhcp/dhcp6_ia_na_client_dp.h b/src/plugins/dhcp/dhcp6_ia_na_client_dp.h index a866479fbaf..88a6b75ecdd 100644 --- a/src/vnet/dhcp/dhcp6_ia_na_client_dp.h +++ b/src/plugins/dhcp/dhcp6_ia_na_client_dp.h @@ -16,8 +16,9 @@ #ifndef included_vnet_dhcp6_client_dp_h #define included_vnet_dhcp6_client_dp_h -#include <vlib/vlib.h> -#include <vnet/dhcp/dhcp6_client_common_dp.h> +#include <stdbool.h> + +#include <dhcp/dhcp6_client_common_dp.h> typedef struct { @@ -87,31 +88,19 @@ typedef struct dhcp6_address_info_t *addresses; } address_report_t; -#define vl_typedefs /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_typedefs - void dhcp6_send_client_message (vlib_main_t * vm, u32 sw_if_index, u8 stop, dhcp6_send_client_message_params_t * params); void dhcp6_set_publisher_node (uword node_index, uword event_type); int dhcp6_publish_report (address_report_t * r); - - -void - vl_api_want_dhcp6_reply_events_t_handler - (vl_api_want_dhcp6_reply_events_t * mp); -void - vl_api_dhcp6_send_client_message_t_handler - (vl_api_dhcp6_send_client_message_t * mp); -void - vl_api_dhcp6_clients_enable_disable_t_handler - (vl_api_dhcp6_clients_enable_disable_t * mp); +int dhcp6_client_enable_disable (u32 sw_if_index, u8 enable); extern vlib_node_registration_t dhcp6_reply_process_node; enum { DHCP6_DP_REPLY_REPORT, DHCP6_DP_REPORT_MAX }; +#include <dhcp/dhcp.api_types.h> + typedef struct _vnet_dhcp6_reply_function_list_elt { struct _vnet_dhcp6_reply_function_list_elt *next_dhcp6_reply_event_function; diff --git a/src/vnet/dhcp/dhcp6_packet.h b/src/plugins/dhcp/dhcp6_packet.h index d5467952a64..d5467952a64 100644 --- a/src/vnet/dhcp/dhcp6_packet.h +++ b/src/plugins/dhcp/dhcp6_packet.h diff --git a/src/vnet/dhcp/dhcp6_pd_client_cp.api b/src/plugins/dhcp/dhcp6_pd_client_cp.api index 43ed868e81e..43ed868e81e 100644 --- a/src/vnet/dhcp/dhcp6_pd_client_cp.api +++ b/src/plugins/dhcp/dhcp6_pd_client_cp.api diff --git a/src/vnet/dhcp/dhcp6_pd_client_cp.c b/src/plugins/dhcp/dhcp6_pd_client_cp.c index cc538a78ab1..6f151430e58 100644 --- a/src/vnet/dhcp/dhcp6_pd_client_cp.c +++ b/src/plugins/dhcp/dhcp6_pd_client_cp.c @@ -15,32 +15,14 @@ #include <vnet/vnet.h> #include <vlibmemory/api.h> -#include <vnet/vnet_msg_enum.h> -#include <vnet/dhcp/dhcp6_packet.h> -#include <vnet/dhcp/dhcp6_pd_client_dp.h> +#include <dhcp/dhcp6_packet.h> +#include <dhcp/dhcp6_pd_client_dp.h> #include <vnet/ip/ip.h> #include <vnet/ip/ip6.h> #include <float.h> #include <math.h> #include <string.h> -#define vl_typedefs /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_typedefs - -#define vl_endianfun /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_endianfun - -#include <vlibapi/api_helper_macros.h> - -#define foreach_dhcp6_pd_client_cp_msg \ -_(DHCP6_PD_CLIENT_ENABLE_DISABLE, dhcp6_pd_client_enable_disable) \ -_(IP6_ADD_DEL_ADDRESS_USING_PREFIX, ip6_add_del_address_using_prefix) - -#define vl_api_dhcp6_pd_client_enable_disable_t_print vl_noop_handler -#define vl_api_ip6_add_del_address_using_prefix_t_print vl_noop_handler - typedef struct { u32 prefix_group_index; @@ -868,9 +850,10 @@ prefix_group_find_or_create (const u8 * name, u8 create) } } -static int -cp_ip6_address_add_del (u32 sw_if_index, const u8 * prefix_group, - ip6_address_t address, u8 prefix_length, u8 is_add) +int +dhcp6_cp_ip6_address_add_del (u32 sw_if_index, const u8 * prefix_group, + ip6_address_t address, u8 prefix_length, + u8 is_add) { ip6_address_with_prefix_main_t *apm = &ip6_address_with_prefix_main; @@ -927,32 +910,6 @@ cp_ip6_address_add_del (u32 sw_if_index, const u8 * prefix_group, return 0; } -static void - vl_api_ip6_add_del_address_using_prefix_t_handler - (vl_api_ip6_add_del_address_using_prefix_t * mp) -{ - vl_api_ip6_add_del_address_using_prefix_reply_t *rmp; - u32 sw_if_index; - ip6_address_t address; - u8 prefix_length; - int rv = 0; - - VALIDATE_SW_IF_INDEX (mp); - - sw_if_index = ntohl (mp->sw_if_index); - - memcpy (address.as_u8, mp->address, 16); - prefix_length = mp->prefix_length; - - rv = - cp_ip6_address_add_del (sw_if_index, mp->prefix_group, address, - prefix_length, mp->is_add); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_IP6_ADD_DEL_ADDRESS_USING_PREFIX_REPLY); -} - static clib_error_t * cp_ip6_address_add_del_command_function (vlib_main_t * vm, unformat_input_t * input, @@ -999,7 +956,7 @@ cp_ip6_address_add_del_command_function (vlib_main_t * vm, error = clib_error_return (0, "Missing address"); else { - if (cp_ip6_address_add_del + if (dhcp6_cp_ip6_address_add_del (sw_if_index, prefix_group, address, prefix_length, add) != 0) error = clib_error_return (0, "Error adding or removing address"); } @@ -1169,9 +1126,11 @@ VLIB_CLI_COMMAND (ip6_pd_clients_show_command, static) = { }; /* *INDENT-ON* */ -static int -dhcp6_pd_client_enable_disable (u32 sw_if_index, const u8 * prefix_group, - u8 enable) + + +int +dhcp6_pd_client_enable_disable (u32 sw_if_index, + const u8 * prefix_group, u8 enable) { dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main; ip6_prefix_main_t *pm = &ip6_prefix_main; @@ -1341,66 +1300,17 @@ VLIB_CLI_COMMAND (dhcp6_pd_client_enable_disable_command, static) = { }; /* *INDENT-ON* */ -static void - vl_api_dhcp6_pd_client_enable_disable_t_handler - (vl_api_dhcp6_pd_client_enable_disable_t * mp) -{ - vl_api_dhcp6_pd_client_enable_disable_reply_t *rmp; - u32 sw_if_index; - int rv = 0; - - VALIDATE_SW_IF_INDEX (mp); - - sw_if_index = ntohl (mp->sw_if_index); - - rv = - dhcp6_pd_client_enable_disable (sw_if_index, mp->prefix_group, - mp->enable); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_DHCP6_PD_CLIENT_ENABLE_DISABLE_REPLY); -} - -#define vl_msg_name_crc_list -#include <vnet/dhcp/dhcp6_pd_client_cp.api.h> -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (api_main_t * am) -{ -#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id); - foreach_vl_msg_name_crc_dhcp6_pd_client_cp; -#undef _ -} - static clib_error_t * dhcp_pd_client_cp_init (vlib_main_t * vm) { dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main; - api_main_t *am = &api_main; rm->vlib_main = vm; rm->vnet_main = vnet_get_main (); - rm->api_main = am; + rm->api_main = &api_main; rm->node_index = dhcp6_pd_client_cp_process_node.index; -#define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N, #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_api_##n##_t_endian, \ - vl_api_##n##_t_print, \ - sizeof(vl_api_##n##_t), 0/* do NOT trace! */); - foreach_dhcp6_pd_client_cp_msg; -#undef _ - - /* - * Set up the (msg_name, crc, message-id) table - */ - setup_message_id_table (am); - - return 0; + return (NULL); } VLIB_INIT_FUNCTION (dhcp_pd_client_cp_init); diff --git a/src/plugins/dhcp/dhcp6_pd_client_cp_api.c b/src/plugins/dhcp/dhcp6_pd_client_cp_api.c new file mode 100644 index 00000000000..4999fd7f623 --- /dev/null +++ b/src/plugins/dhcp/dhcp6_pd_client_cp_api.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <vnet/vnet.h> +#include <vlibmemory/api.h> + +#include <dhcp/dhcp6_pd_client_dp.h> + +/* define message IDs */ +#include <vnet/format_fns.h> +#include <dhcp/dhcp6_pd_client_cp.api_enum.h> +#include <dhcp/dhcp6_pd_client_cp.api_types.h> + +/** + * Base message ID fot the plugin + */ +static u32 dhcp_base_msg_id; +#define REPLY_MSG_ID_BASE dhcp_base_msg_id + +#include <vlibapi/api_helper_macros.h> + +static void + vl_api_dhcp6_pd_client_enable_disable_t_handler + (vl_api_dhcp6_pd_client_enable_disable_t * mp) +{ + vl_api_dhcp6_pd_client_enable_disable_reply_t *rmp; + u32 sw_if_index; + int rv = 0; + + VALIDATE_SW_IF_INDEX (mp); + + sw_if_index = ntohl (mp->sw_if_index); + + rv = dhcp6_pd_client_enable_disable (sw_if_index, + mp->prefix_group, mp->enable); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_DHCP6_PD_CLIENT_ENABLE_DISABLE_REPLY); +} + +static void + vl_api_ip6_add_del_address_using_prefix_t_handler + (vl_api_ip6_add_del_address_using_prefix_t * mp) +{ + vl_api_ip6_add_del_address_using_prefix_reply_t *rmp; + u32 sw_if_index; + ip6_address_t address; + u8 prefix_length; + int rv = 0; + + VALIDATE_SW_IF_INDEX (mp); + + sw_if_index = ntohl (mp->sw_if_index); + + memcpy (address.as_u8, mp->address, 16); + prefix_length = mp->prefix_length; + + rv = dhcp6_cp_ip6_address_add_del (sw_if_index, mp->prefix_group, address, + prefix_length, mp->is_add); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_IP6_ADD_DEL_ADDRESS_USING_PREFIX_REPLY); +} + +#define vl_msg_name_crc_list +#include <dhcp/dhcp6_pd_client_cp.api.c> +#undef vl_msg_name_crc_list + +static clib_error_t * +dhcp_pd_client_cp_api_init (vlib_main_t * vm) +{ + /* + * Set up the (msg_name, crc, message-id) table + */ + dhcp_base_msg_id = setup_message_id_table (); + + return 0; +} + +VLIB_INIT_FUNCTION (dhcp_pd_client_cp_api_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/dhcp/dhcp6_pd_client_dp.c b/src/plugins/dhcp/dhcp6_pd_client_dp.c index c665b17281a..74a1f16000c 100644 --- a/src/vnet/dhcp/dhcp6_pd_client_dp.c +++ b/src/plugins/dhcp/dhcp6_pd_client_dp.c @@ -14,37 +14,17 @@ */ #include <vlib/vlib.h> -#include <vnet/dhcp/dhcp6_packet.h> -#include <vnet/dhcp/dhcp_proxy.h> +#include <dhcp/dhcp6_packet.h> +#include <dhcp/dhcp_proxy.h> #include <vnet/mfib/mfib_table.h> #include <vnet/mfib/ip6_mfib.h> #include <vnet/fib/fib.h> #include <vnet/adj/adj_mcast.h> #include <vnet/ip/ip6_neighbor.h> -#include <vlibapi/api_common.h> -#include <vlibmemory/api.h> -#include <vnet/dhcp/dhcp6_pd_client_dp.h> -#include <vnet/dhcp/dhcp6_client_common_dp.h> +#include <dhcp/dhcp6_pd_client_dp.h> +#include <dhcp/dhcp6_client_common_dp.h> #include <vnet/ip/ip_types_api.h> -#include <vnet/vnet_msg_enum.h> - -#define vl_typedefs /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_typedefs - -#define vl_endianfun /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) -#define vl_printfun -#include <vnet/vnet_all_api_h.h> -#undef vl_printfun - -#include <vlibapi/api_helper_macros.h> - dhcp6_pd_client_main_t dhcp6_pd_client_main; dhcp6_pd_client_public_main_t dhcp6_pd_client_public_main; @@ -433,214 +413,6 @@ dhcp6_pd_send_client_message (vlib_main_t * vm, u32 sw_if_index, u8 stop, } } -void - vl_api_dhcp6_pd_send_client_message_t_handler - (vl_api_dhcp6_pd_send_client_message_t * mp) -{ - vl_api_dhcp6_pd_send_client_message_reply_t *rmp; - dhcp6_pd_send_client_message_params_t params; - vlib_main_t *vm = vlib_get_main (); - u32 n_prefixes; - u32 i; - int rv = 0; - - VALIDATE_SW_IF_INDEX (mp); - - BAD_SW_IF_INDEX_LABEL; - REPLY_MACRO (VL_API_DHCP6_PD_SEND_CLIENT_MESSAGE_REPLY); - - if (rv != 0) - return; - - params.sw_if_index = ntohl (mp->sw_if_index); - params.server_index = ntohl (mp->server_index); - params.irt = ntohl (mp->irt); - params.mrt = ntohl (mp->mrt); - params.mrc = ntohl (mp->mrc); - params.mrd = ntohl (mp->mrd); - params.msg_type = ntohl (mp->msg_type); - params.T1 = ntohl (mp->T1); - params.T2 = ntohl (mp->T2); - n_prefixes = ntohl (mp->n_prefixes); - params.prefixes = 0; - if (n_prefixes > 0) - vec_validate (params.prefixes, n_prefixes - 1); - for (i = 0; i < n_prefixes; i++) - { - vl_api_dhcp6_pd_prefix_info_t *pi = &mp->prefixes[i]; - dhcp6_pd_send_client_message_params_prefix_t *pref = - ¶ms.prefixes[i]; - pref->preferred_lt = ntohl (pi->preferred_time); - pref->valid_lt = ntohl (pi->valid_time); - ip6_address_decode (pi->prefix.address, &pref->prefix); - pref->prefix_length = pi->prefix.len; - } - - dhcp6_pd_send_client_message (vm, ntohl (mp->sw_if_index), mp->stop, - ¶ms); -} - -static clib_error_t * -call_dhcp6_pd_reply_event_callbacks (void *data, - _vnet_dhcp6_pd_reply_event_function_list_elt_t - * elt) -{ - clib_error_t *error = 0; - - while (elt) - { - error = elt->fp (data); - if (error) - return error; - elt = elt->next_dhcp6_pd_reply_event_function; - } - - return error; -} - -static uword -dhcp6_pd_reply_process (vlib_main_t * vm, vlib_node_runtime_t * rt, - vlib_frame_t * f) -{ - /* These cross the longjmp boundary (vlib_process_wait_for_event) - * and need to be volatile - to prevent them from being optimized into - * a register - which could change during suspension */ - - while (1) - { - vlib_process_wait_for_event (vm); - uword event_type = DHCP6_PD_DP_REPLY_REPORT; - void *event_data = vlib_process_get_event_data (vm, &event_type); - - int i; - if (event_type == DHCP6_PD_DP_REPLY_REPORT) - { - prefix_report_t *events = event_data; - for (i = 0; i < vec_len (events); i++) - { - u32 event_size = - sizeof (vl_api_dhcp6_pd_reply_event_t) + - vec_len (events[i].prefixes) * - sizeof (vl_api_dhcp6_pd_prefix_info_t); - vl_api_dhcp6_pd_reply_event_t *event = - clib_mem_alloc (event_size); - clib_memset (event, 0, event_size); - - event->sw_if_index = htonl (events[i].body.sw_if_index); - event->server_index = htonl (events[i].body.server_index); - event->msg_type = events[i].body.msg_type; - event->T1 = htonl (events[i].body.T1); - event->T2 = htonl (events[i].body.T2); - event->inner_status_code = - htons (events[i].body.inner_status_code); - event->status_code = htons (events[i].body.status_code); - event->preference = events[i].body.preference; - - event->n_prefixes = htonl (vec_len (events[i].prefixes)); - vl_api_dhcp6_pd_prefix_info_t *prefix = - (typeof (prefix)) event->prefixes; - u32 j; - for (j = 0; j < vec_len (events[i].prefixes); j++) - { - dhcp6_prefix_info_t *info = &events[i].prefixes[j]; - ip6_address_encode (&info->prefix, prefix->prefix.address); - prefix->prefix.len = info->prefix_length; - prefix->valid_time = htonl (info->valid_time); - prefix->preferred_time = htonl (info->preferred_time); - prefix++; - } - vec_free (events[i].prefixes); - - dhcp6_pd_client_public_main_t *dpcpm = - &dhcp6_pd_client_public_main; - call_dhcp6_pd_reply_event_callbacks (event, dpcpm->functions); - - vpe_client_registration_t *reg; - /* *INDENT-OFF* */ - pool_foreach(reg, vpe_api_main.dhcp6_pd_reply_events_registrations, - ({ - vl_api_registration_t *vl_reg; - vl_reg = - vl_api_client_index_to_registration (reg->client_index); - if (vl_reg && vl_api_can_send_msg (vl_reg)) - { - vl_api_dhcp6_pd_reply_event_t *msg = - vl_msg_api_alloc (event_size); - clib_memcpy (msg, event, event_size); - msg->_vl_msg_id = htons (VL_API_DHCP6_PD_REPLY_EVENT); - msg->client_index = reg->client_index; - msg->pid = reg->client_pid; - vl_api_send_msg (vl_reg, (u8 *) msg); - } - })); - /* *INDENT-ON* */ - - clib_mem_free (event); - } - } - vlib_process_put_event_data (vm, event_data); - } - - return 0; -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (dhcp6_pd_reply_process_node) = { - .function = dhcp6_pd_reply_process, - .type = VLIB_NODE_TYPE_PROCESS, - .name = "dhcp6-pd-reply-publisher-process", -}; -/* *INDENT-ON* */ - -void - vl_api_want_dhcp6_pd_reply_events_t_handler - (vl_api_want_dhcp6_pd_reply_events_t * mp) -{ - vpe_api_main_t *am = &vpe_api_main; - vl_api_want_dhcp6_pd_reply_events_reply_t *rmp; - int rv = 0; - - uword *p = - hash_get (am->dhcp6_pd_reply_events_registration_hash, mp->client_index); - vpe_client_registration_t *rp; - if (p) - { - if (mp->enable_disable) - { - clib_warning ("pid %d: already enabled...", ntohl (mp->pid)); - rv = VNET_API_ERROR_INVALID_REGISTRATION; - goto reply; - } - else - { - rp = - pool_elt_at_index (am->dhcp6_pd_reply_events_registrations, p[0]); - pool_put (am->dhcp6_pd_reply_events_registrations, rp); - hash_unset (am->dhcp6_pd_reply_events_registration_hash, - mp->client_index); - if (pool_elts (am->dhcp6_pd_reply_events_registrations) == 0) - dhcp6_pd_set_publisher_node (~0, DHCP6_PD_DP_REPORT_MAX); - goto reply; - } - } - if (mp->enable_disable == 0) - { - clib_warning ("pid %d: already disabled...", ntohl (mp->pid)); - rv = VNET_API_ERROR_INVALID_REGISTRATION; - goto reply; - } - pool_get (am->dhcp6_pd_reply_events_registrations, rp); - rp->client_index = mp->client_index; - rp->client_pid = ntohl (mp->pid); - hash_set (am->dhcp6_pd_reply_events_registration_hash, rp->client_index, - rp - am->dhcp6_pd_reply_events_registrations); - dhcp6_pd_set_publisher_node (dhcp6_pd_reply_process_node.index, - DHCP6_PD_DP_REPLY_REPORT); - -reply: - REPLY_MACRO (VL_API_WANT_DHCP6_PD_REPLY_EVENTS_REPLY); -} - static clib_error_t * dhcp6_pd_client_init (vlib_main_t * vm) { diff --git a/src/vnet/dhcp/dhcp6_pd_client_dp.h b/src/plugins/dhcp/dhcp6_pd_client_dp.h index 88c731c2e67..561ca8a5a5b 100644 --- a/src/vnet/dhcp/dhcp6_pd_client_dp.h +++ b/src/plugins/dhcp/dhcp6_pd_client_dp.h @@ -17,7 +17,7 @@ #define included_vnet_dhcp6_pd_client_dp_h #include <vlib/vlib.h> -#include <vnet/dhcp/dhcp6_client_common_dp.h> +#include <dhcp/dhcp6_client_common_dp.h> typedef struct { @@ -89,31 +89,24 @@ typedef struct dhcp6_prefix_info_t *prefixes; } prefix_report_t; -#define vl_typedefs /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_typedefs - void dhcp6_pd_send_client_message (vlib_main_t * vm, u32 sw_if_index, u8 stop, dhcp6_pd_send_client_message_params_t * params); void dhcp6_pd_set_publisher_node (uword node_index, uword event_type); int dhcp6_pd_publish_report (prefix_report_t * r); - -void - vl_api_want_dhcp6_pd_reply_events_t_handler - (vl_api_want_dhcp6_pd_reply_events_t * mp); -void - vl_api_dhcp6_pd_send_client_message_t_handler - (vl_api_dhcp6_pd_send_client_message_t * mp); -void - vl_api_dhcp6_clients_enable_disable_t_handler - (vl_api_dhcp6_clients_enable_disable_t * mp); +int dhcp6_pd_client_enable_disable (u32 sw_if_index, + const u8 * prefix_group, u8 enable); +int dhcp6_cp_ip6_address_add_del (u32 sw_if_index, const u8 * prefix_group, + ip6_address_t address, u8 prefix_length, + u8 is_add); extern vlib_node_registration_t dhcp6_pd_reply_process_node; enum { DHCP6_PD_DP_REPLY_REPORT, DHCP6_PD_DP_REPORT_MAX }; +#include <dhcp/dhcp.api_types.h> + typedef struct _vnet_dhcp6_pd_reply_function_list_elt { struct _vnet_dhcp6_pd_reply_function_list_elt diff --git a/src/vnet/dhcp/dhcp6_pd_doc.md b/src/plugins/dhcp/dhcp6_pd_doc.md index 0d0e0865f1b..0d0e0865f1b 100644 --- a/src/vnet/dhcp/dhcp6_pd_doc.md +++ b/src/plugins/dhcp/dhcp6_pd_doc.md diff --git a/src/vnet/dhcp/dhcp6_proxy_error.def b/src/plugins/dhcp/dhcp6_proxy_error.def index 55fa731766c..55fa731766c 100644 --- a/src/vnet/dhcp/dhcp6_proxy_error.def +++ b/src/plugins/dhcp/dhcp6_proxy_error.def diff --git a/src/vnet/dhcp/dhcp6_proxy_node.c b/src/plugins/dhcp/dhcp6_proxy_node.c index 174548f24eb..929b49e2b41 100644 --- a/src/vnet/dhcp/dhcp6_proxy_node.c +++ b/src/plugins/dhcp/dhcp6_proxy_node.c @@ -17,15 +17,15 @@ #include <vlib/vlib.h> #include <vnet/pg/pg.h> -#include <vnet/dhcp/dhcp_proxy.h> -#include <vnet/dhcp/dhcp6_packet.h> +#include <dhcp/dhcp_proxy.h> +#include <dhcp/dhcp6_packet.h> #include <vnet/mfib/mfib_table.h> #include <vnet/mfib/ip6_mfib.h> #include <vnet/fib/fib.h> static char *dhcpv6_proxy_error_strings[] = { #define dhcpv6_proxy_error(n,s) s, -#include <vnet/dhcp/dhcp6_proxy_error.def> +#include <dhcp/dhcp6_proxy_error.def> #undef dhcpv6_proxy_error }; diff --git a/src/plugins/dhcp/dhcp_api.c b/src/plugins/dhcp/dhcp_api.c new file mode 100644 index 00000000000..61efaba09b0 --- /dev/null +++ b/src/plugins/dhcp/dhcp_api.c @@ -0,0 +1,871 @@ +/* + *------------------------------------------------------------------ + * dhcp_api.c - dhcp api + * + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include <vnet/vnet.h> +#include <vlibmemory/api.h> + +#include <vnet/interface.h> +#include <vnet/api_errno.h> +#include <dhcp/dhcp_proxy.h> +#include <dhcp/client.h> +#include <dhcp/dhcp6_pd_client_dp.h> +#include <dhcp/dhcp6_ia_na_client_dp.h> +#include <dhcp/dhcp6_client_common_dp.h> +#include <vnet/fib/fib_table.h> +#include <vnet/ip/ip_types_api.h> + +/* define message IDs */ +#include <vnet/format_fns.h> +#include <dhcp/dhcp.api_enum.h> +#include <dhcp/dhcp.api_types.h> + +/** + * Base message ID fot the plugin + */ +static u32 dhcp_base_msg_id; +#define REPLY_MSG_ID_BASE dhcp_base_msg_id + +#include <vlibapi/api_helper_macros.h> + +#define DHCP_PLUGIN_VERSION_MAJOR 1 +#define DHCP_PLUGIN_VERSION_MINOR 0 + +static void +vl_api_dhcp_plugin_get_version_t_handler (vl_api_dhcp_plugin_get_version_t * + mp) +{ + vl_api_dhcp_plugin_get_version_reply_t *rmp; + int msg_size = sizeof (*rmp); + vl_api_registration_t *reg; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + rmp = vl_msg_api_alloc (msg_size); + clib_memset (rmp, 0, msg_size); + rmp->_vl_msg_id = + ntohs (VL_API_DHCP_PLUGIN_GET_VERSION_REPLY + REPLY_MSG_ID_BASE); + rmp->context = mp->context; + rmp->major = htonl (DHCP_PLUGIN_VERSION_MAJOR); + rmp->minor = htonl (DHCP_PLUGIN_VERSION_MINOR); + + vl_api_send_msg (reg, (u8 *) rmp); +} + +static void +vl_api_dhcp_plugin_control_ping_t_handler (vl_api_dhcp_plugin_control_ping_t * + mp) +{ + vl_api_dhcp_plugin_control_ping_reply_t *rmp; + int rv = 0; + + /* *INDENT-OFF* */ + REPLY_MACRO2 (VL_API_DHCP_PLUGIN_CONTROL_PING_REPLY, + ({ + rmp->vpe_pid = ntohl (getpid ()); + })); + /* *INDENT-ON* */ +} + +static void +vl_api_dhcp6_duid_ll_set_t_handler (vl_api_dhcp6_duid_ll_set_t * mp) +{ + vl_api_dhcp6_duid_ll_set_reply_t *rmp; + dhcpv6_duid_ll_string_t *duid; + int rv = 0; + + duid = (dhcpv6_duid_ll_string_t *) mp->duid_ll; + if (duid->duid_type != htonl (DHCPV6_DUID_LL)) + { + rv = VNET_API_ERROR_INVALID_VALUE; + goto reply; + } + clib_memcpy (&client_duid, &duid, sizeof (client_duid)); + +reply: + REPLY_MACRO (VL_API_DHCP6_DUID_LL_SET_REPLY); +} + +static void +vl_api_dhcp_proxy_set_vss_t_handler (vl_api_dhcp_proxy_set_vss_t * mp) +{ + vl_api_dhcp_proxy_set_vss_reply_t *rmp; + u8 *vpn_ascii_id; + int rv; + + mp->vpn_ascii_id[sizeof (mp->vpn_ascii_id) - 1] = 0; + vpn_ascii_id = format (0, "%s", mp->vpn_ascii_id); + rv = + dhcp_proxy_set_vss ((mp->is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4), + ntohl (mp->tbl_id), ntohl (mp->vss_type), + vpn_ascii_id, ntohl (mp->oui), ntohl (mp->vpn_index), + mp->is_add == 0); + + REPLY_MACRO (VL_API_DHCP_PROXY_SET_VSS_REPLY); +} + + +static void vl_api_dhcp_proxy_config_t_handler + (vl_api_dhcp_proxy_config_t * mp) +{ + vl_api_dhcp_proxy_set_vss_reply_t *rmp; + ip46_address_t src, server; + int rv = -1; + + if (mp->dhcp_src_address.af != mp->dhcp_server.af) + { + rv = VNET_API_ERROR_INVALID_ARGUMENT; + goto reply; + } + + ip_address_decode (&mp->dhcp_src_address, &src); + ip_address_decode (&mp->dhcp_server, &server); + + if (mp->dhcp_src_address.af == ADDRESS_IP4) + { + rv = dhcp4_proxy_set_server (&server, + &src, + (u32) ntohl (mp->rx_vrf_id), + (u32) ntohl (mp->server_vrf_id), + (int) (mp->is_add == 0)); + } + else + { + rv = dhcp6_proxy_set_server (&server, + &src, + (u32) ntohl (mp->rx_vrf_id), + (u32) ntohl (mp->server_vrf_id), + (int) (mp->is_add == 0)); + } + +reply: + REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); +} + +static void +vl_api_dhcp_proxy_dump_t_handler (vl_api_dhcp_proxy_dump_t * mp) +{ + vl_api_registration_t *reg; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return;; + + dhcp_proxy_dump ((mp->is_ip6 == 1 ? + FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4), reg, mp->context); +} + +void +dhcp_send_details (fib_protocol_t proto, + void *opaque, u32 context, dhcp_proxy_t * proxy) +{ + vl_api_dhcp_proxy_details_t *mp; + vl_api_registration_t *reg = opaque; + 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; + clib_memset (mp, 0, n); + mp->_vl_msg_id = ntohs (VL_API_DHCP_PROXY_DETAILS + REPLY_MSG_ID_BASE); + mp->context = context; + 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 (vss) + { + mp->vss_type = ntohl (vss->vss_type); + if (vss->vss_type == VSS_TYPE_ASCII) + { + u32 id_len = vec_len (vss->vpn_ascii_id); + clib_memcpy (mp->vss_vpn_ascii_id, vss->vpn_ascii_id, id_len); + } + else if (vss->vss_type == VSS_TYPE_VPN_ID) + { + u32 oui = ((u32) vss->vpn_id[0] << 16) + ((u32) vss->vpn_id[1] << 8) + + ((u32) vss->vpn_id[2]); + u32 fib_id = ((u32) vss->vpn_id[3] << 24) + + ((u32) vss->vpn_id[4] << 16) + ((u32) vss->vpn_id[5] << 8) + + ((u32) vss->vpn_id[6]); + mp->vss_oui = htonl (oui); + mp->vss_fib_id = htonl (fib_id); + } + } + else + mp->vss_type = VSS_TYPE_INVALID; + + 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.un, &server->dhcp_server.ip6, 16); + } + else + { + /* put the address in the first bytes */ + memcpy (&v_server->dhcp_server.un, &server->dhcp_server.ip4, 4); + } + } + + if (mp->is_ipv6) + { + memcpy (&mp->dhcp_src_address.un, &proxy->dhcp_src_address.ip6, 16); + } + else + { + /* put the address in the first bytes */ + memcpy (&mp->dhcp_src_address.un, &proxy->dhcp_src_address.ip4, 4); + } + vl_api_send_msg (reg, (u8 *) mp); +} + +static void +dhcp_client_lease_encode (vl_api_dhcp_lease_t * lease, + const dhcp_client_t * client) +{ + size_t len; + u8 i; + + lease->is_ipv6 = 0; // only support IPv6 clients + lease->sw_if_index = ntohl (client->sw_if_index); + lease->state = ntohl (client->state); + len = clib_min (sizeof (lease->hostname) - 1, vec_len (client->hostname)); + clib_memcpy (&lease->hostname, client->hostname, len); + lease->hostname[len] = 0; + + lease->mask_width = client->subnet_mask_width; + clib_memcpy (&lease->host_address.un, (u8 *) & client->leased_address, + sizeof (ip4_address_t)); + clib_memcpy (&lease->router_address.un, (u8 *) & client->router_address, + sizeof (ip4_address_t)); + + lease->count = vec_len (client->domain_server_address); + for (i = 0; i < lease->count; i++) + clib_memcpy (&lease->domain_server[i].address, + (u8 *) & client->domain_server_address[i], + sizeof (ip4_address_t)); + + clib_memcpy (&lease->host_mac[0], client->client_hardware_address, 6); +} + +static void +dhcp_client_data_encode (vl_api_dhcp_client_t * vclient, + const dhcp_client_t * client) +{ + size_t len; + + vclient->sw_if_index = ntohl (client->sw_if_index); + len = clib_min (sizeof (vclient->hostname) - 1, vec_len (client->hostname)); + clib_memcpy (&vclient->hostname, client->hostname, len); + vclient->hostname[len] = 0; + + len = clib_min (sizeof (vclient->id) - 1, + vec_len (client->client_identifier)); + clib_memcpy (&vclient->id, client->client_identifier, len); + vclient->id[len] = 0; + + if (NULL != client->event_callback) + vclient->want_dhcp_event = 1; + else + vclient->want_dhcp_event = 0; + vclient->set_broadcast_flag = client->set_broadcast_flag; + vclient->dscp = ip_dscp_encode (client->dscp); + vclient->pid = client->pid; +} + +static void +dhcp_compl_event_callback (u32 client_index, const dhcp_client_t * client) +{ + vl_api_registration_t *reg; + vl_api_dhcp_compl_event_t *mp; + + reg = vl_api_client_index_to_registration (client_index); + if (!reg) + return; + + mp = vl_msg_api_alloc (sizeof (*mp)); + mp->client_index = client_index; + mp->pid = client->pid; + dhcp_client_lease_encode (&mp->lease, client); + + mp->_vl_msg_id = ntohs (VL_API_DHCP_COMPL_EVENT + REPLY_MSG_ID_BASE); + + vl_api_send_msg (reg, (u8 *) mp); +} + +static void vl_api_dhcp_client_config_t_handler + (vl_api_dhcp_client_config_t * mp) +{ + vlib_main_t *vm = vlib_get_main (); + vl_api_dhcp_client_config_reply_t *rmp; + u32 sw_if_index; + ip_dscp_t dscp; + int rv = 0; + + VALIDATE_SW_IF_INDEX (&(mp->client)); + + sw_if_index = ntohl (mp->client.sw_if_index); + dscp = ip_dscp_decode (mp->client.dscp); + + rv = dhcp_client_config (mp->is_add, + mp->client_index, + vm, + sw_if_index, + mp->client.hostname, + mp->client.id, + (mp->client.want_dhcp_event ? + dhcp_compl_event_callback : + NULL), + mp->client.set_broadcast_flag, + dscp, mp->client.pid); + + BAD_SW_IF_INDEX_LABEL; + REPLY_MACRO (VL_API_DHCP_CLIENT_CONFIG_REPLY); +} + +typedef struct dhcp_client_send_walk_ctx_t_ +{ + vl_api_registration_t *reg; + u32 context; +} dhcp_client_send_walk_ctx_t; + +static int +send_dhcp_client_entry (const dhcp_client_t * client, void *arg) +{ + dhcp_client_send_walk_ctx_t *ctx; + vl_api_dhcp_client_details_t *mp; + + ctx = arg; + + mp = vl_msg_api_alloc (sizeof (*mp)); + clib_memset (mp, 0, sizeof (*mp)); + + mp->_vl_msg_id = ntohs (VL_API_DHCP_CLIENT_DETAILS + REPLY_MSG_ID_BASE); + mp->context = ctx->context; + + dhcp_client_data_encode (&mp->client, client); + dhcp_client_lease_encode (&mp->lease, client); + + vl_api_send_msg (ctx->reg, (u8 *) mp); + + return (1); +} + +static void +vl_api_dhcp_client_dump_t_handler (vl_api_dhcp_client_dump_t * mp) +{ + vl_api_registration_t *reg; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + dhcp_client_send_walk_ctx_t ctx = { + .reg = reg, + .context = mp->context, + }; + dhcp_client_walk (send_dhcp_client_entry, &ctx); +} + +static void + vl_api_dhcp6_clients_enable_disable_t_handler + (vl_api_dhcp6_clients_enable_disable_t * mp) +{ + vl_api_dhcp6_clients_enable_disable_reply_t *rmp; + int rv = 0; + + dhcp6_clients_enable_disable (mp->enable); + + REPLY_MACRO (VL_API_DHCP6_CLIENTS_ENABLE_DISABLE_REPLY); +} + +void + vl_api_want_dhcp6_reply_events_t_handler + (vl_api_want_dhcp6_reply_events_t * mp) +{ + vpe_api_main_t *am = &vpe_api_main; + vl_api_want_dhcp6_reply_events_reply_t *rmp; + int rv = 0; + + uword *p = + hash_get (am->dhcp6_reply_events_registration_hash, mp->client_index); + vpe_client_registration_t *rp; + if (p) + { + if (mp->enable_disable) + { + clib_warning ("pid %d: already enabled...", ntohl (mp->pid)); + rv = VNET_API_ERROR_INVALID_REGISTRATION; + goto reply; + } + else + { + rp = pool_elt_at_index (am->dhcp6_reply_events_registrations, p[0]); + pool_put (am->dhcp6_reply_events_registrations, rp); + hash_unset (am->dhcp6_reply_events_registration_hash, + mp->client_index); + if (pool_elts (am->dhcp6_reply_events_registrations) == 0) + dhcp6_set_publisher_node (~0, DHCP6_DP_REPORT_MAX); + goto reply; + } + } + if (mp->enable_disable == 0) + { + clib_warning ("pid %d: already disabled...", ntohl (mp->pid)); + rv = VNET_API_ERROR_INVALID_REGISTRATION; + goto reply; + } + pool_get (am->dhcp6_reply_events_registrations, rp); + rp->client_index = mp->client_index; + rp->client_pid = ntohl (mp->pid); + hash_set (am->dhcp6_reply_events_registration_hash, rp->client_index, + rp - am->dhcp6_reply_events_registrations); + dhcp6_set_publisher_node (dhcp6_reply_process_node.index, + DHCP6_DP_REPLY_REPORT); + +reply: + REPLY_MACRO (VL_API_WANT_DHCP6_REPLY_EVENTS_REPLY); +} + +void + vl_api_want_dhcp6_pd_reply_events_t_handler + (vl_api_want_dhcp6_pd_reply_events_t * mp) +{ + vpe_api_main_t *am = &vpe_api_main; + vl_api_want_dhcp6_pd_reply_events_reply_t *rmp; + int rv = 0; + + uword *p = + hash_get (am->dhcp6_pd_reply_events_registration_hash, mp->client_index); + vpe_client_registration_t *rp; + if (p) + { + if (mp->enable_disable) + { + clib_warning ("pid %d: already enabled...", ntohl (mp->pid)); + rv = VNET_API_ERROR_INVALID_REGISTRATION; + goto reply; + } + else + { + rp = + pool_elt_at_index (am->dhcp6_pd_reply_events_registrations, p[0]); + pool_put (am->dhcp6_pd_reply_events_registrations, rp); + hash_unset (am->dhcp6_pd_reply_events_registration_hash, + mp->client_index); + if (pool_elts (am->dhcp6_pd_reply_events_registrations) == 0) + dhcp6_pd_set_publisher_node (~0, DHCP6_PD_DP_REPORT_MAX); + goto reply; + } + } + if (mp->enable_disable == 0) + { + clib_warning ("pid %d: already disabled...", ntohl (mp->pid)); + rv = VNET_API_ERROR_INVALID_REGISTRATION; + goto reply; + } + pool_get (am->dhcp6_pd_reply_events_registrations, rp); + rp->client_index = mp->client_index; + rp->client_pid = ntohl (mp->pid); + hash_set (am->dhcp6_pd_reply_events_registration_hash, rp->client_index, + rp - am->dhcp6_pd_reply_events_registrations); + dhcp6_pd_set_publisher_node (dhcp6_pd_reply_process_node.index, + DHCP6_PD_DP_REPLY_REPORT); + +reply: + REPLY_MACRO (VL_API_WANT_DHCP6_PD_REPLY_EVENTS_REPLY); +} + +void + vl_api_dhcp6_send_client_message_t_handler + (vl_api_dhcp6_send_client_message_t * mp) +{ + vl_api_dhcp6_send_client_message_reply_t *rmp; + dhcp6_send_client_message_params_t params; + vlib_main_t *vm = vlib_get_main (); + u32 n_addresses; + u32 i; + int rv = 0; + + VALIDATE_SW_IF_INDEX (mp); + + BAD_SW_IF_INDEX_LABEL; + REPLY_MACRO (VL_API_DHCP6_SEND_CLIENT_MESSAGE_REPLY); + + if (rv != 0) + return; + + params.sw_if_index = ntohl (mp->sw_if_index); + params.server_index = ntohl (mp->server_index); + params.irt = ntohl (mp->irt); + params.mrt = ntohl (mp->mrt); + params.mrc = ntohl (mp->mrc); + params.mrd = ntohl (mp->mrd); + params.msg_type = ntohl (mp->msg_type); + params.T1 = ntohl (mp->T1); + params.T2 = ntohl (mp->T2); + n_addresses = ntohl (mp->n_addresses); + params.addresses = 0; + if (n_addresses > 0) + vec_validate (params.addresses, n_addresses - 1); + for (i = 0; i < n_addresses; i++) + { + vl_api_dhcp6_address_info_t *ai = &mp->addresses[i]; + dhcp6_send_client_message_params_address_t *addr = ¶ms.addresses[i]; + addr->preferred_lt = ntohl (ai->preferred_time); + addr->valid_lt = ntohl (ai->valid_time); + ip6_address_decode (ai->address, &addr->address); + } + + dhcp6_send_client_message (vm, ntohl (mp->sw_if_index), mp->stop, ¶ms); +} + +void + vl_api_dhcp6_pd_send_client_message_t_handler + (vl_api_dhcp6_pd_send_client_message_t * mp) +{ + vl_api_dhcp6_pd_send_client_message_reply_t *rmp; + dhcp6_pd_send_client_message_params_t params; + vlib_main_t *vm = vlib_get_main (); + u32 n_prefixes; + u32 i; + int rv = 0; + + VALIDATE_SW_IF_INDEX (mp); + + BAD_SW_IF_INDEX_LABEL; + REPLY_MACRO (VL_API_DHCP6_PD_SEND_CLIENT_MESSAGE_REPLY); + + if (rv != 0) + return; + + params.sw_if_index = ntohl (mp->sw_if_index); + params.server_index = ntohl (mp->server_index); + params.irt = ntohl (mp->irt); + params.mrt = ntohl (mp->mrt); + params.mrc = ntohl (mp->mrc); + params.mrd = ntohl (mp->mrd); + params.msg_type = ntohl (mp->msg_type); + params.T1 = ntohl (mp->T1); + params.T2 = ntohl (mp->T2); + n_prefixes = ntohl (mp->n_prefixes); + params.prefixes = 0; + if (n_prefixes > 0) + vec_validate (params.prefixes, n_prefixes - 1); + for (i = 0; i < n_prefixes; i++) + { + vl_api_dhcp6_pd_prefix_info_t *pi = &mp->prefixes[i]; + dhcp6_pd_send_client_message_params_prefix_t *pref = + ¶ms.prefixes[i]; + pref->preferred_lt = ntohl (pi->preferred_time); + pref->valid_lt = ntohl (pi->valid_time); + ip6_address_decode (pi->prefix.address, &pref->prefix); + pref->prefix_length = pi->prefix.len; + } + + dhcp6_pd_send_client_message (vm, ntohl (mp->sw_if_index), mp->stop, + ¶ms); +} + +static clib_error_t * +call_dhcp6_reply_event_callbacks (void *data, + _vnet_dhcp6_reply_event_function_list_elt_t + * elt) +{ + clib_error_t *error = 0; + + while (elt) + { + error = elt->fp (data); + if (error) + return error; + elt = elt->next_dhcp6_reply_event_function; + } + + return error; +} + +static uword +dhcp6_reply_process (vlib_main_t * vm, vlib_node_runtime_t * rt, + vlib_frame_t * f) +{ + /* These cross the longjmp boundary (vlib_process_wait_for_event) + * and need to be volatile - to prevent them from being optimized into + * a register - which could change during suspension */ + + while (1) + { + vlib_process_wait_for_event (vm); + uword event_type = DHCP6_DP_REPLY_REPORT; + void *event_data = vlib_process_get_event_data (vm, &event_type); + + int i; + if (event_type == DHCP6_DP_REPLY_REPORT) + { + address_report_t *events = event_data; + for (i = 0; i < vec_len (events); i++) + { + u32 event_size = + sizeof (vl_api_dhcp6_reply_event_t) + + vec_len (events[i].addresses) * + sizeof (vl_api_dhcp6_address_info_t); + vl_api_dhcp6_reply_event_t *event = clib_mem_alloc (event_size); + clib_memset (event, 0, event_size); + + event->sw_if_index = htonl (events[i].body.sw_if_index); + event->server_index = htonl (events[i].body.server_index); + event->msg_type = events[i].body.msg_type; + event->T1 = htonl (events[i].body.T1); + event->T2 = htonl (events[i].body.T2); + event->inner_status_code = + htons (events[i].body.inner_status_code); + event->status_code = htons (events[i].body.status_code); + event->preference = events[i].body.preference; + + event->n_addresses = htonl (vec_len (events[i].addresses)); + vl_api_dhcp6_address_info_t *address = + (typeof (address)) event->addresses; + u32 j; + for (j = 0; j < vec_len (events[i].addresses); j++) + { + dhcp6_address_info_t *info = &events[i].addresses[j]; + ip6_address_encode (&info->address, address->address); + address->valid_time = htonl (info->valid_time); + address->preferred_time = htonl (info->preferred_time); + address++; + } + vec_free (events[i].addresses); + + dhcp6_ia_na_client_public_main_t *dcpm = + &dhcp6_ia_na_client_public_main; + call_dhcp6_reply_event_callbacks (event, dcpm->functions); + + vpe_client_registration_t *reg; + /* *INDENT-OFF* */ + pool_foreach(reg, vpe_api_main.dhcp6_reply_events_registrations, + ({ + vl_api_registration_t *vl_reg; + vl_reg = + vl_api_client_index_to_registration (reg->client_index); + if (vl_reg && vl_api_can_send_msg (vl_reg)) + { + vl_api_dhcp6_reply_event_t *msg = + vl_msg_api_alloc (event_size); + clib_memcpy (msg, event, event_size); + msg->_vl_msg_id = htons (VL_API_DHCP6_REPLY_EVENT + REPLY_MSG_ID_BASE); + msg->client_index = reg->client_index; + msg->pid = reg->client_pid; + vl_api_send_msg (vl_reg, (u8 *) msg); + } + })); + /* *INDENT-ON* */ + + clib_mem_free (event); + } + } + vlib_process_put_event_data (vm, event_data); + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (dhcp6_reply_process_node) = { + .function = dhcp6_reply_process, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "dhcp6-reply-publisher-process", +}; +/* *INDENT-ON* */ + +static clib_error_t * +call_dhcp6_pd_reply_event_callbacks (void *data, + _vnet_dhcp6_pd_reply_event_function_list_elt_t + * elt) +{ + clib_error_t *error = 0; + + while (elt) + { + error = elt->fp (data); + if (error) + return error; + elt = elt->next_dhcp6_pd_reply_event_function; + } + + return error; +} + +static uword +dhcp6_pd_reply_process (vlib_main_t * vm, vlib_node_runtime_t * rt, + vlib_frame_t * f) +{ + /* These cross the longjmp boundary (vlib_process_wait_for_event) + * and need to be volatile - to prevent them from being optimized into + * a register - which could change during suspension */ + + while (1) + { + vlib_process_wait_for_event (vm); + uword event_type = DHCP6_PD_DP_REPLY_REPORT; + void *event_data = vlib_process_get_event_data (vm, &event_type); + + int i; + if (event_type == DHCP6_PD_DP_REPLY_REPORT) + { + prefix_report_t *events = event_data; + for (i = 0; i < vec_len (events); i++) + { + u32 event_size = + sizeof (vl_api_dhcp6_pd_reply_event_t) + + vec_len (events[i].prefixes) * + sizeof (vl_api_dhcp6_pd_prefix_info_t); + vl_api_dhcp6_pd_reply_event_t *event = + clib_mem_alloc (event_size); + clib_memset (event, 0, event_size); + + event->sw_if_index = htonl (events[i].body.sw_if_index); + event->server_index = htonl (events[i].body.server_index); + event->msg_type = events[i].body.msg_type; + event->T1 = htonl (events[i].body.T1); + event->T2 = htonl (events[i].body.T2); + event->inner_status_code = + htons (events[i].body.inner_status_code); + event->status_code = htons (events[i].body.status_code); + event->preference = events[i].body.preference; + + event->n_prefixes = htonl (vec_len (events[i].prefixes)); + vl_api_dhcp6_pd_prefix_info_t *prefix = + (typeof (prefix)) event->prefixes; + u32 j; + for (j = 0; j < vec_len (events[i].prefixes); j++) + { + dhcp6_prefix_info_t *info = &events[i].prefixes[j]; + ip6_address_encode (&info->prefix, prefix->prefix.address); + prefix->prefix.len = info->prefix_length; + prefix->valid_time = htonl (info->valid_time); + prefix->preferred_time = htonl (info->preferred_time); + prefix++; + } + vec_free (events[i].prefixes); + + dhcp6_pd_client_public_main_t *dpcpm = + &dhcp6_pd_client_public_main; + call_dhcp6_pd_reply_event_callbacks (event, dpcpm->functions); + + vpe_client_registration_t *reg; + /* *INDENT-OFF* */ + pool_foreach(reg, vpe_api_main.dhcp6_pd_reply_events_registrations, + ({ + vl_api_registration_t *vl_reg; + vl_reg = + vl_api_client_index_to_registration (reg->client_index); + if (vl_reg && vl_api_can_send_msg (vl_reg)) + { + vl_api_dhcp6_pd_reply_event_t *msg = + vl_msg_api_alloc (event_size); + clib_memcpy (msg, event, event_size); + msg->_vl_msg_id = htons (VL_API_DHCP6_PD_REPLY_EVENT + REPLY_MSG_ID_BASE); + msg->client_index = reg->client_index; + msg->pid = reg->client_pid; + vl_api_send_msg (vl_reg, (u8 *) msg); + } + })); + /* *INDENT-ON* */ + + clib_mem_free (event); + } + } + vlib_process_put_event_data (vm, event_data); + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (dhcp6_pd_reply_process_node) = { + .function = dhcp6_pd_reply_process, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "dhcp6-pd-reply-publisher-process", +}; +/* *INDENT-ON* */ + +/* + * dhcp_api_hookup + * Add vpe's API message handlers to the table. + * vlib has already mapped shared memory and + * added the client registration handlers. + * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process() + */ +#include <dhcp/dhcp.api.c> + +static clib_error_t * +dhcp_api_hookup (vlib_main_t * vm) +{ + /* + * Set up the (msg_name, crc, message-id) table + */ + dhcp_base_msg_id = setup_message_id_table (); + + dhcp6_pd_set_publisher_node (dhcp6_pd_reply_process_node.index, + DHCP6_PD_DP_REPLY_REPORT); + dhcp6_set_publisher_node (dhcp6_reply_process_node.index, + DHCP6_DP_REPLY_REPORT); + + return 0; +} + +VLIB_API_INIT_FUNCTION (dhcp_api_hookup); + +#include <vlib/unix/plugin.h> +#include <vpp/app/version.h> + +/* *INDENT-OFF* */ +VLIB_PLUGIN_REGISTER () = { + .version = VPP_BUILD_VER, + .description = "Dynamic Host Configuration Protocol (DHCP)", +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/dhcp/dhcp_client_detect.c b/src/plugins/dhcp/dhcp_client_detect.c index c79970d1456..31b89850802 100644 --- a/src/vnet/dhcp/dhcp_client_detect.c +++ b/src/plugins/dhcp/dhcp_client_detect.c @@ -15,7 +15,7 @@ * limitations under the License. */ -#include <vnet/dhcp/client.h> +#include <dhcp/client.h> #include <vnet/udp/udp.h> #define foreach_dhcp_client_detect \ diff --git a/src/vnet/dhcp/dhcp_proxy.c b/src/plugins/dhcp/dhcp_proxy.c index 9a69041bc1d..1890c874b61 100644 --- a/src/vnet/dhcp/dhcp_proxy.c +++ b/src/plugins/dhcp/dhcp_proxy.c @@ -15,7 +15,7 @@ * limitations under the License. */ -#include <vnet/dhcp/dhcp_proxy.h> +#include <dhcp/dhcp_proxy.h> #include <vnet/fib/fib_table.h> #include <vnet/mfib/mfib_table.h> diff --git a/src/vnet/dhcp/dhcp_proxy.h b/src/plugins/dhcp/dhcp_proxy.h index 60c4eb838c8..2b120b5c5f4 100644 --- a/src/vnet/dhcp/dhcp_proxy.h +++ b/src/plugins/dhcp/dhcp_proxy.h @@ -19,7 +19,7 @@ #define included_dhcp_proxy_h #include <vnet/vnet.h> -#include <vnet/dhcp/dhcp4_packet.h> +#include <dhcp/dhcp4_packet.h> #include <vnet/ethernet/ethernet.h> #include <vnet/ip/ip.h> #include <vnet/ip/ip4.h> @@ -31,7 +31,7 @@ typedef enum { #define dhcp_proxy_error(n,s) DHCP_PROXY_ERROR_##n, -#include <vnet/dhcp/dhcp4_proxy_error.def> +#include <dhcp/dhcp4_proxy_error.def> #undef dhcp_proxy_error DHCP_PROXY_N_ERROR, } dhcp_proxy_error_t; @@ -39,7 +39,7 @@ typedef enum typedef enum { #define dhcpv6_proxy_error(n,s) DHCPV6_PROXY_ERROR_##n, -#include <vnet/dhcp/dhcp6_proxy_error.def> +#include <dhcp/dhcp6_proxy_error.def> #undef dhcpv6_proxy_error DHCPV6_PROXY_N_ERROR, } dhcpv6_proxy_error_t; diff --git a/src/plugins/dhcp/dhcp_test.c b/src/plugins/dhcp/dhcp_test.c new file mode 100644 index 00000000000..a042dc02843 --- /dev/null +++ b/src/plugins/dhcp/dhcp_test.c @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <vat/vat.h> +#include <vlibapi/api.h> +#include <vlibmemory/api.h> +#include <vppinfra/error.h> + +#include <dhcp/client.h> +#include <dhcp/dhcp_proxy.h> +#include <vnet/ip/ip_format_fns.h> +#include <vnet/ethernet/ethernet_format_fns.h> + +/* define message IDs */ +#include <dhcp/dhcp.api_enum.h> +#include <dhcp/dhcp.api_types.h> + +typedef struct { + /* API message ID base */ + u16 msg_id_base; + vat_main_t *vat_main; +} dhcp_test_main_t; + +dhcp_test_main_t dhcp_test_main; + +#define __plugin_msg_base dhcp_test_main.msg_id_base +#include <vlibapi/vat_helper_macros.h> + +/* Macro to finish up custom dump fns */ +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) +#define FINISH \ + vec_add1 (s, 0); \ + vl_print (handle, (char *)s); \ + vec_free (s); \ + return handle; + +static int +api_dhcp_proxy_config (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_dhcp_proxy_config_t *mp; + u32 rx_vrf_id = 0; + u32 server_vrf_id = 0; + u8 is_add = 1; + u8 v4_address_set = 0; + u8 v6_address_set = 0; + ip4_address_t v4address; + ip6_address_t v6address; + u8 v4_src_address_set = 0; + u8 v6_src_address_set = 0; + ip4_address_t v4srcaddress; + ip6_address_t v6srcaddress; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "rx_vrf_id %d", &rx_vrf_id)) + ; + else if (unformat (i, "server_vrf_id %d", &server_vrf_id)) + ; + else if (unformat (i, "svr %U", unformat_ip4_address, &v4address)) + v4_address_set = 1; + else if (unformat (i, "svr %U", unformat_ip6_address, &v6address)) + v6_address_set = 1; + else if (unformat (i, "src %U", unformat_ip4_address, &v4srcaddress)) + v4_src_address_set = 1; + else if (unformat (i, "src %U", unformat_ip6_address, &v6srcaddress)) + v6_src_address_set = 1; + else + break; + } + + if (v4_address_set && v6_address_set) + { + errmsg ("both v4 and v6 server addresses set"); + return -99; + } + if (!v4_address_set && !v6_address_set) + { + errmsg ("no server addresses set"); + return -99; + } + + if (v4_src_address_set && v6_src_address_set) + { + errmsg ("both v4 and v6 src addresses set"); + return -99; + } + if (!v4_src_address_set && !v6_src_address_set) + { + errmsg ("no src addresses set"); + return -99; + } + + if (!(v4_src_address_set && v4_address_set) && + !(v6_src_address_set && v6_address_set)) + { + errmsg ("no matching server and src addresses set"); + return -99; + } + + /* Construct the API message */ + M (DHCP_PROXY_CONFIG, mp); + + mp->is_add = is_add; + mp->rx_vrf_id = ntohl (rx_vrf_id); + mp->server_vrf_id = ntohl (server_vrf_id); + if (v6_address_set) + { + clib_memcpy (&mp->dhcp_server.un, &v6address, sizeof (v6address)); + clib_memcpy (&mp->dhcp_src_address.un, &v6srcaddress, + sizeof (v6address)); + } + else + { + clib_memcpy (&mp->dhcp_server.un, &v4address, sizeof (v4address)); + clib_memcpy (&mp->dhcp_src_address.un, &v4srcaddress, + sizeof (v4address)); + } + + /* send it... */ + S (mp); + + /* Wait for a reply, return good/bad news */ + W (ret); + return ret; +} + +#define vl_api_dhcp_proxy_details_t_endian vl_noop_handler +#define vl_api_dhcp_proxy_details_t_print vl_noop_handler + +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, Source Address %U, VSS Type %d, " + "VSS ASCII VPN-ID '%s', VSS RFC2685 VPN-ID (oui:id) %d:%d", + ntohl (mp->rx_vrf_id), + format_ip6_address, mp->dhcp_src_address, + mp->vss_type, mp->vss_vpn_ascii_id, + ntohl (mp->vss_oui), ntohl (mp->vss_fib_id)); + else + print (vam->ofp, + "RX Table-ID %d, Source Address %U, VSS Type %d, " + "VSS ASCII VPN-ID '%s', VSS RFC2685 VPN-ID (oui:id) %d:%d", + ntohl (mp->rx_vrf_id), + format_ip4_address, mp->dhcp_src_address, + mp->vss_type, mp->vss_vpn_ascii_id, + 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 int +api_dhcp_proxy_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_dhcp_plugin_control_ping_t *mp_ping; + vl_api_dhcp_proxy_dump_t *mp; + u8 is_ipv6 = 0; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "ipv6")) + is_ipv6 = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + M (DHCP_PROXY_DUMP, mp); + + mp->is_ip6 = is_ipv6; + S (mp); + + /* Use a control ping for synchronization */ + MPING (DHCP_PLUGIN_CONTROL_PING, mp_ping); + S (mp_ping); + + W (ret); + return ret; +} + +static int +api_dhcp_proxy_set_vss (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_dhcp_proxy_set_vss_t *mp; + u8 is_ipv6 = 0; + u8 is_add = 1; + u32 tbl_id = ~0; + u8 vss_type = VSS_TYPE_DEFAULT; + u8 *vpn_ascii_id = 0; + u32 oui = 0; + u32 fib_id = 0; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "tbl_id %d", &tbl_id)) + ; + else if (unformat (i, "vpn_ascii_id %s", &vpn_ascii_id)) + vss_type = VSS_TYPE_ASCII; + else if (unformat (i, "fib_id %d", &fib_id)) + vss_type = VSS_TYPE_VPN_ID; + else if (unformat (i, "oui %d", &oui)) + vss_type = VSS_TYPE_VPN_ID; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else if (unformat (i, "del")) + is_add = 0; + else + break; + } + + if (tbl_id == ~0) + { + errmsg ("missing tbl_id "); + vec_free (vpn_ascii_id); + return -99; + } + + if ((vpn_ascii_id) && (vec_len (vpn_ascii_id) > 128)) + { + errmsg ("vpn_ascii_id cannot be longer than 128 "); + vec_free (vpn_ascii_id); + return -99; + } + + M (DHCP_PROXY_SET_VSS, mp); + mp->tbl_id = ntohl (tbl_id); + mp->vss_type = vss_type; + if (vpn_ascii_id) + { + clib_memcpy (mp->vpn_ascii_id, vpn_ascii_id, vec_len (vpn_ascii_id)); + mp->vpn_ascii_id[vec_len (vpn_ascii_id)] = 0; + } + mp->vpn_index = ntohl (fib_id); + mp->oui = ntohl (oui); + mp->is_ipv6 = is_ipv6; + mp->is_add = is_add; + + S (mp); + W (ret); + + vec_free (vpn_ascii_id); + return ret; +} + +static int +api_dhcp_client_config (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_dhcp_client_config_t *mp; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 is_add = 1; + u8 *hostname = 0; + u8 disable_event = 0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else + if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "hostname %s", &hostname)) + ; + else if (unformat (i, "disable_event")) + disable_event = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (vec_len (hostname) > 63) + { + errmsg ("hostname too long"); + } + vec_add1 (hostname, 0); + + /* Construct the API message */ + M (DHCP_CLIENT_CONFIG, mp); + + mp->is_add = is_add; + mp->client.sw_if_index = htonl (sw_if_index); + clib_memcpy (mp->client.hostname, hostname, vec_len (hostname)); + vec_free (hostname); + mp->client.want_dhcp_event = disable_event ? 0 : 1; + mp->client.pid = htonl (getpid ()); + + /* send it... */ + S (mp); + + /* Wait for a reply, return good/bad news */ + W (ret); + return ret; +} + +/* static void *vl_api_dhcp_proxy_config_t_print */ +/* (vl_api_dhcp_proxy_config_t * mp, void *handle) */ +/* { */ +/* u8 *s; */ + +/* s = format (0, "SCRIPT: dhcp_proxy_config_2 "); */ + +/* s = format (s, "rx_vrf_id %d ", (mp->rx_vrf_id)); */ +/* s = format (s, "server_vrf_id %d ", (mp->server_vrf_id)); */ + +/* s = format (s, "svr %U ", format_ip46_address, */ +/* (ip46_address_t *) & mp->dhcp_server.un); */ +/* s = format (s, "src %U ", format_ip46_address, */ +/* (ip46_address_t *) & mp->dhcp_src_address.un); */ + +/* if (mp->is_add == 0) */ +/* s = format (s, "del "); */ + +/* FINISH; */ +/* } */ + +/* static void *vl_api_dhcp_proxy_set_vss_t_print */ +/* (vl_api_dhcp_proxy_set_vss_t * mp, void *handle) */ +/* { */ +/* u8 *s; */ + +/* s = format (0, "SCRIPT: dhcp_proxy_set_vss "); */ + +/* s = format (s, "tbl_id %d ", (mp->tbl_id)); */ + +/* if (mp->vss_type == VSS_TYPE_VPN_ID) */ +/* { */ +/* s = format (s, "fib_id %d ", (mp->vpn_index)); */ +/* s = format (s, "oui %d ", (mp->oui)); */ +/* } */ +/* else if (mp->vss_type == VSS_TYPE_ASCII) */ +/* s = format (s, "vpn_ascii_id %s", mp->vpn_ascii_id); */ + +/* if (mp->is_ipv6 != 0) */ +/* s = format (s, "ipv6 "); */ + +/* if (mp->is_add == 0) */ +/* s = format (s, "del "); */ + +/* FINISH; */ +/* } */ + +/* static void *vl_api_dhcp_client_config_t_print */ +/* (vl_api_dhcp_client_config_t * mp, void *handle) */ +/* { */ +/* u8 *s; */ + +/* s = format (0, "SCRIPT: dhcp_client_config "); */ + +/* s = format (s, "sw_if_index %d ", (mp->client.sw_if_index)); */ + +/* s = format (s, "hostname %s ", mp->client.hostname); */ + +/* s = format (s, "want_dhcp_event %d ", mp->client.want_dhcp_event); */ + +/* s = format (s, "pid %d ", (mp->client.pid)); */ + +/* if (mp->is_add == 0) */ +/* s = format (s, "del "); */ + +/* FINISH; */ +/* } */ + +static int +api_want_dhcp6_reply_events (vat_main_t * vam) +{ + return -1; +} +static int +api_want_dhcp6_pd_reply_events (vat_main_t * vam) +{ + return -1; +} +static int +api_dhcp6_send_client_message (vat_main_t * vam) +{ + return -1; +} +static int +api_dhcp6_pd_send_client_message (vat_main_t * vam) +{ + return -1; +} +static int +api_dhcp_client_dump (vat_main_t * vam) +{ + return -1; +} +static int +api_dhcp6_duid_ll_set (vat_main_t * vam) +{ + return -1; +} +static int +api_dhcp6_clients_enable_disable (vat_main_t * vam) +{ + return -1; +} +static int +api_dhcp_plugin_control_ping (vat_main_t * vam) +{ + return -1; +} +static int +api_dhcp_plugin_get_version (vat_main_t * vam) +{ + return -1; +} + +#define vl_api_dhcp_client_details_t_handler vl_noop_handler + +static void +vl_api_dhcp_plugin_get_version_reply_t_handler (vl_api_dhcp_plugin_get_version_reply_t * mp) +{ +} + +static void +vl_api_dhcp_plugin_control_ping_reply_t_handler (vl_api_dhcp_plugin_get_version_reply_t * mp) +{ +} + +/* static void */ +/* vl_api_dhcp_compl_event_t_handler (vl_api_dhcp_compl_event_t * mp) */ +/* { */ +/* u8 *s, i; */ + +/* s = format (0, "DHCP compl event: pid %d hostname %s host_addr %U " */ +/* "host_mac %U router_addr %U", */ +/* ntohl (mp->pid), mp->lease.hostname, */ +/* format_ip4_address, mp->lease.host_address, */ +/* format_ethernet_address, mp->lease.host_mac, */ +/* format_ip4_address, mp->lease.router_address); */ + +/* for (i = 0; i < mp->lease.count; i++) */ +/* s = */ +/* format (s, " domain_server_addr %U", format_ip4_address, */ +/* mp->lease.domain_server[i].address); */ + +/* errmsg ((char *) s); */ +/* vec_free (s); */ +/* } */ + +#include <dhcp/dhcp.api_test.c> diff --git a/src/plugins/dhcp/test/test_dhcp.py b/src/plugins/dhcp/test/test_dhcp.py new file mode 100644 index 00000000000..2200e489d00 --- /dev/null +++ b/src/plugins/dhcp/test/test_dhcp.py @@ -0,0 +1,1653 @@ +#!/usr/bin/env python + +import unittest +import socket +import struct + +from framework import VppTestCase, VppTestRunner, running_extended_tests +from vpp_neighbor import VppNeighbor +from vpp_ip_route import find_route, VppIpTable +from util import mk_ll_addr +import scapy.compat +from scapy.layers.l2 import Ether, getmacbyip, ARP, Dot1Q +from scapy.layers.inet import IP, UDP, ICMP +from scapy.layers.inet6 import IPv6, in6_getnsmac +from scapy.utils6 import 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, DHCP6_Request +from socket import AF_INET, AF_INET6 +from scapy.utils import inet_pton, inet_ntop +from scapy.utils6 import in6_ptop +from vpp_papi import mac_pton, VppEnum +from vpp_sub_interface import VppDot1QSubint +from vpp_qos import VppQosEgressMap, VppQosMark +from vpp_dhcp import VppDHCPClient, VppDHCPProxy + + +DHCP4_CLIENT_PORT = 68 +DHCP4_SERVER_PORT = 67 +DHCP6_CLIENT_PORT = 547 +DHCP6_SERVER_PORT = 546 + + +class TestDHCP(VppTestCase): + """ DHCP Test Case """ + + @classmethod + def setUpClass(cls): + super(TestDHCP, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestDHCP, cls).tearDownClass() + + def setUp(self): + super(TestDHCP, self).setUp() + + # create 6 pg interfaces for pg0 to pg5 + self.create_pg_interfaces(range(6)) + self.tables = [] + + # pg0 to 2 are IP configured in VRF 0, 1 and 2. + # pg3 to 5 are non IP-configured in VRF 0, 1 and 2. + table_id = 0 + for table_id in range(1, 4): + tbl4 = VppIpTable(self, table_id) + tbl4.add_vpp_config() + self.tables.append(tbl4) + tbl6 = VppIpTable(self, table_id, is_ip6=1) + tbl6.add_vpp_config() + self.tables.append(tbl6) + + table_id = 0 + for i in self.pg_interfaces[:3]: + i.admin_up() + i.set_table_ip4(table_id) + i.set_table_ip6(table_id) + i.config_ip4() + i.resolve_arp() + i.config_ip6() + i.resolve_ndp() + table_id += 1 + + table_id = 0 + for i in self.pg_interfaces[3:]: + i.admin_up() + i.set_table_ip4(table_id) + i.set_table_ip6(table_id) + table_id += 1 + + def tearDown(self): + for i in self.pg_interfaces[:3]: + i.unconfig_ip4() + i.unconfig_ip6() + + for i in self.pg_interfaces: + i.set_table_ip4(0) + i.set_table_ip6(0) + i.admin_down() + super(TestDHCP, self).tearDown() + + def verify_dhcp_has_option(self, pkt, option, value): + dhcp = pkt[DHCP] + found = False + + for i in dhcp.options: + if isinstance(i, tuple): + if i[0] == option: + self.assertEqual(i[1], value) + found = True + + self.assertTrue(found) + + def validate_relay_options(self, pkt, intf, ip_addr, vpn_id, fib_id, oui): + dhcp = pkt[DHCP] + found = 0 + data = [] + id_len = len(vpn_id) + + for i in dhcp.options: + if isinstance(i, tuple): + if i[0] == "relay_agent_Information": + # + # There are two sb-options present - each of length 6. + # + data = i[1] + if oui != 0: + self.assertEqual(len(data), 24) + elif len(vpn_id) > 0: + self.assertEqual(len(data), len(vpn_id) + 17) + else: + self.assertEqual(len(data), 12) + + # + # First sub-option is ID 1, len 4, then encoded + # sw_if_index. This test uses low valued indicies + # so [2:4] are 0. + # The ID space is VPP internal - so no matching value + # scapy + # + self.assertEqual(ord(data[0]), 1) + self.assertEqual(ord(data[1]), 4) + self.assertEqual(ord(data[2]), 0) + self.assertEqual(ord(data[3]), 0) + self.assertEqual(ord(data[4]), 0) + self.assertEqual(ord(data[5]), intf._sw_if_index) + + # + # next sub-option is the IP address of the client side + # interface. + # sub-option ID=5, length (of a v4 address)=4 + # + claddr = socket.inet_pton(AF_INET, ip_addr) + + self.assertEqual(ord(data[6]), 5) + self.assertEqual(ord(data[7]), 4) + self.assertEqual(data[8], claddr[0]) + self.assertEqual(data[9], claddr[1]) + self.assertEqual(data[10], claddr[2]) + self.assertEqual(data[11], claddr[3]) + + if oui != 0: + # sub-option 151 encodes vss_type 1, + # the 3 byte oui and the 4 byte fib_id + self.assertEqual(id_len, 0) + self.assertEqual(ord(data[12]), 151) + self.assertEqual(ord(data[13]), 8) + self.assertEqual(ord(data[14]), 1) + self.assertEqual(ord(data[15]), 0) + self.assertEqual(ord(data[16]), 0) + self.assertEqual(ord(data[17]), oui) + self.assertEqual(ord(data[18]), 0) + self.assertEqual(ord(data[19]), 0) + self.assertEqual(ord(data[20]), 0) + self.assertEqual(ord(data[21]), fib_id) + + # VSS control sub-option + self.assertEqual(ord(data[22]), 152) + self.assertEqual(ord(data[23]), 0) + + if id_len > 0: + # sub-option 151 encode vss_type of 0 + # followerd by vpn_id in ascii + self.assertEqual(oui, 0) + self.assertEqual(ord(data[12]), 151) + self.assertEqual(ord(data[13]), id_len + 1) + self.assertEqual(ord(data[14]), 0) + self.assertEqual(data[15:15 + id_len], vpn_id) + + # VSS control sub-option + self.assertEqual(ord(data[15 + len(vpn_id)]), 152) + self.assertEqual(ord(data[16 + len(vpn_id)]), 0) + + found = 1 + self.assertTrue(found) + + return data + + def verify_dhcp_msg_type(self, pkt, name): + dhcp = pkt[DHCP] + found = False + for o in dhcp.options: + if isinstance(o, tuple): + if o[0] == "message-type" \ + and DHCPTypes[o[1]] == name: + found = True + self.assertTrue(found) + + def verify_dhcp_offer(self, pkt, intf, vpn_id="", 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) + + ip = pkt[IP] + self.assertEqual(ip.dst, "255.255.255.255") + self.assertEqual(ip.src, intf.local_ip4) + + udp = pkt[UDP] + self.assertEqual(udp.dport, DHCP4_CLIENT_PORT) + self.assertEqual(udp.sport, DHCP4_SERVER_PORT) + + self.verify_dhcp_msg_type(pkt, "offer") + data = self.validate_relay_options(pkt, intf, intf.local_ip4, + vpn_id, fib_id, oui) + + def verify_orig_dhcp_pkt(self, pkt, intf, dscp, l2_bc=True): + ether = pkt[Ether] + if l2_bc: + self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") + else: + self.assertEqual(ether.dst, intf.remote_mac) + self.assertEqual(ether.src, intf.local_mac) + + ip = pkt[IP] + + if (l2_bc): + self.assertEqual(ip.dst, "255.255.255.255") + self.assertEqual(ip.src, "0.0.0.0") + else: + self.assertEqual(ip.dst, intf.remote_ip4) + self.assertEqual(ip.src, intf.local_ip4) + self.assertEqual(ip.tos, dscp) + + udp = pkt[UDP] + self.assertEqual(udp.dport, DHCP4_SERVER_PORT) + self.assertEqual(udp.sport, DHCP4_CLIENT_PORT) + + def verify_orig_dhcp_discover(self, pkt, intf, hostname, client_id=None, + broadcast=True, dscp=0): + self.verify_orig_dhcp_pkt(pkt, intf, dscp) + + self.verify_dhcp_msg_type(pkt, "discover") + self.verify_dhcp_has_option(pkt, "hostname", hostname) + if client_id: + self.verify_dhcp_has_option(pkt, "client_id", client_id) + bootp = pkt[BOOTP] + self.assertEqual(bootp.ciaddr, "0.0.0.0") + self.assertEqual(bootp.giaddr, "0.0.0.0") + if broadcast: + self.assertEqual(bootp.flags, 0x8000) + else: + self.assertEqual(bootp.flags, 0x0000) + + def verify_orig_dhcp_request(self, pkt, intf, hostname, ip, + broadcast=True, + l2_bc=True, + dscp=0): + self.verify_orig_dhcp_pkt(pkt, intf, dscp, l2_bc=l2_bc) + + self.verify_dhcp_msg_type(pkt, "request") + self.verify_dhcp_has_option(pkt, "hostname", hostname) + self.verify_dhcp_has_option(pkt, "requested_addr", ip) + bootp = pkt[BOOTP] + + if l2_bc: + self.assertEqual(bootp.ciaddr, "0.0.0.0") + else: + self.assertEqual(bootp.ciaddr, intf.local_ip4) + self.assertEqual(bootp.giaddr, "0.0.0.0") + + if broadcast: + self.assertEqual(bootp.flags, 0x8000) + else: + self.assertEqual(bootp.flags, 0x0000) + + def verify_relayed_dhcp_discover(self, pkt, intf, src_intf=None, + fib_id=0, oui=0, + vpn_id="", + dst_mac=None, dst_ip=None): + if not dst_mac: + dst_mac = intf.remote_mac + if not dst_ip: + dst_ip = intf.remote_ip4 + + ether = pkt[Ether] + self.assertEqual(ether.dst, dst_mac) + self.assertEqual(ether.src, intf.local_mac) + + ip = pkt[IP] + self.assertEqual(ip.dst, dst_ip) + self.assertEqual(ip.src, intf.local_ip4) + + udp = pkt[UDP] + self.assertEqual(udp.dport, DHCP4_SERVER_PORT) + self.assertEqual(udp.sport, DHCP4_CLIENT_PORT) + + dhcp = pkt[DHCP] + + is_discover = False + for o in dhcp.options: + if isinstance(o, tuple): + if o[0] == "message-type" \ + and DHCPTypes[o[1]] == "discover": + is_discover = True + self.assertTrue(is_discover) + + data = self.validate_relay_options(pkt, src_intf, + src_intf.local_ip4, + vpn_id, + fib_id, oui) + return data + + def verify_dhcp6_solicit(self, pkt, intf, + peer_ip, peer_mac, + vpn_id="", + 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 = in6_ptop(intf.remote_ip6) + + ether = pkt[Ether] + self.assertEqual(ether.dst, dst_mac) + self.assertEqual(ether.src, intf.local_mac) + + ip = pkt[IPv6] + self.assertEqual(in6_ptop(ip.dst), dst_ip) + self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6)) + + udp = pkt[UDP] + self.assertEqual(udp.dport, DHCP6_CLIENT_PORT) + self.assertEqual(udp.sport, DHCP6_SERVER_PORT) + + relay = pkt[DHCP6_RelayForward] + self.assertEqual(in6_ptop(relay.peeraddr), in6_ptop(peer_ip)) + oid = pkt[DHCP6OptIfaceId] + cll = pkt[DHCP6OptClientLinkLayerAddr] + self.assertEqual(cll.optlen, 8) + self.assertEqual(cll.lltype, 1) + self.assertEqual(cll.clladdr, peer_mac) + + id_len = len(vpn_id) + + if fib_id != 0: + self.assertEqual(id_len, 0) + vss = pkt[DHCP6OptVSS] + self.assertEqual(vss.optlen, 8) + self.assertEqual(vss.type, 1) + # the OUI and FIB-id are really 3 and 4 bytes resp. + # but the tested range is small + self.assertEqual(ord(vss.data[0]), 0) + self.assertEqual(ord(vss.data[1]), 0) + self.assertEqual(ord(vss.data[2]), oui) + self.assertEqual(ord(vss.data[3]), 0) + self.assertEqual(ord(vss.data[4]), 0) + self.assertEqual(ord(vss.data[5]), 0) + self.assertEqual(ord(vss.data[6]), fib_id) + + if id_len > 0: + self.assertEqual(oui, 0) + vss = pkt[DHCP6OptVSS] + self.assertEqual(vss.optlen, id_len + 1) + self.assertEqual(vss.type, 0) + self.assertEqual(vss.data[0:id_len], vpn_id) + + # the relay message should be an encoded Solicit + msg = pkt[DHCP6OptRelayMsg] + sol = DHCP6_Solicit() + self.assertEqual(msg.optlen, len(str(sol))) + self.assertEqual(str(sol), (str(msg[1]))[:msg.optlen]) + + def verify_dhcp6_advert(self, pkt, intf, peer): + ether = pkt[Ether] + self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") + self.assertEqual(ether.src, intf.local_mac) + + ip = pkt[IPv6] + self.assertEqual(in6_ptop(ip.dst), in6_ptop(peer)) + self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6)) + + udp = pkt[UDP] + self.assertEqual(udp.dport, DHCP6_SERVER_PORT) + self.assertEqual(udp.sport, DHCP6_CLIENT_PORT) + + # not sure why this is not decoding + # adv = pkt[DHCP6_Advertise] + + def wait_for_no_route(self, address, length, + n_tries=50, s_time=1): + while (n_tries): + if not find_route(self, address, length): + return True + n_tries = n_tries - 1 + self.sleep(s_time) + + return False + + def test_dhcp_proxy(self): + """ DHCPv4 Proxy """ + + # + # Verify no response to DHCP request without DHCP config + # + p_disc_vrf0 = (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', 'discover'), ('end')])) + pkts_disc_vrf0 = [p_disc_vrf0] + p_disc_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff", + src=self.pg4.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', 'discover'), ('end')])) + pkts_disc_vrf1 = [p_disc_vrf1] + p_disc_vrf2 = (Ether(dst="ff:ff:ff:ff:ff:ff", + src=self.pg5.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', 'discover'), ('end')])) + pkts_disc_vrf2 = [p_disc_vrf2] + + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0, + "DHCP with no configuration") + self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1, + "DHCP with no configuration") + self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2, + "DHCP with no configuration") + + # + # Enable DHCP proxy in VRF 0 + # + server_addr = self.pg0.remote_ip4 + src_addr = self.pg0.local_ip4 + + Proxy = VppDHCPProxy(self, server_addr, src_addr, rx_vrf_id=0) + Proxy.add_vpp_config() + + # + # Discover packets from the client are dropped because there is no + # IP address configured on the client facing interface + # + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0, + "Discover DHCP no relay address") + + # + # Inject a response from the server + # dropped, because there is no IP addrees on the + # client interfce to fill in the option. + # + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), ('end')])) + pkts = [p] + + self.send_and_assert_no_replies(self.pg3, pkts, + "Offer DHCP no relay address") + + # + # configure an IP address on the client facing interface + # + self.pg3.config_ip4() + + # + # Try again with a discover packet + # Rx'd packet should be to the server address and from the configured + # source address + # UDP source ports are unchanged + # we've no option 82 config so that should be absent + # + self.pg3.add_stream(pkts_disc_vrf0) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg0.get_capture(1) + rx = rx[0] + + option_82 = self.verify_relayed_dhcp_discover(rx, self.pg0, + src_intf=self.pg3) + + # + # Create an DHCP offer reply from the server with a correctly formatted + # option 82. i.e. send back what we just captured + # The offer, sent mcast to the client, still has option 82. + # + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg0.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 = [p] + + self.pg0.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg3.get_capture(1) + rx = rx[0] + + self.verify_dhcp_offer(rx, self.pg3) + + # + # Bogus Option 82: + # + # 1. not our IP address = not checked by VPP? so offer is replayed + # to client + bad_ip = option_82[0:8] + scapy.compat.chb(33) + option_82[9:] + + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), + ('relay_agent_Information', bad_ip), + ('end')])) + pkts = [p] + self.send_and_assert_no_replies(self.pg0, pkts, + "DHCP offer option 82 bad address") + + # 2. Not a sw_if_index VPP knows + bad_if_index = option_82[0:2] + scapy.compat.chb(33) + option_82[3:] + + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), + ('relay_agent_Information', bad_if_index), + ('end')])) + pkts = [p] + self.send_and_assert_no_replies(self.pg0, pkts, + "DHCP offer option 82 bad if index") + + # + # Send a DHCP request in VRF 1. should be dropped. + # + self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1, + "DHCP with no configuration VRF 1") + + # + # Delete the DHCP config in VRF 0 + # Should now drop requests. + # + Proxy.remove_vpp_config() + + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0, + "DHCP config removed VRF 0") + self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1, + "DHCP config removed VRF 1") + + # + # Add DHCP config for VRF 1 & 2 + # + server_addr1 = self.pg1.remote_ip4 + src_addr1 = self.pg1.local_ip4 + Proxy1 = VppDHCPProxy( + self, + server_addr1, + src_addr1, + rx_vrf_id=1, + server_vrf_id=1) + Proxy1.add_vpp_config() + + server_addr2 = self.pg2.remote_ip4 + src_addr2 = self.pg2.local_ip4 + Proxy2 = VppDHCPProxy( + self, + server_addr2, + src_addr2, + rx_vrf_id=2, + server_vrf_id=2) + Proxy2.add_vpp_config() + + # + # Confim DHCP requests ok in VRF 1 & 2. + # - dropped on IP config on client interface + # + self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1, + "DHCP config removed VRF 1") + self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2, + "DHCP config removed VRF 2") + + # + # configure an IP address on the client facing interface + # + self.pg4.config_ip4() + self.pg4.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_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg4) + + self.pg5.config_ip4() + self.pg5.add_stream(pkts_disc_vrf2) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + rx = self.pg2.get_capture(1) + rx = rx[0] + self.verify_relayed_dhcp_discover(rx, self.pg2, src_intf=self.pg5) + + # + # Add VSS config + # table=1, vss_type=1, vpn_index=1, oui=4 + # table=2, vss_type=0, vpn_id = "ip4-table-2" + self.vapi.dhcp_proxy_set_vss(tbl_id=1, vss_type=1, + vpn_index=1, oui=4, is_add=1) + self.vapi.dhcp_proxy_set_vss(tbl_id=2, vss_type=0, + vpn_ascii_id="ip4-table-2", is_add=1) + + self.pg4.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_relayed_dhcp_discover(rx, self.pg1, + src_intf=self.pg4, + fib_id=1, oui=4) + + self.pg5.add_stream(pkts_disc_vrf2) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + rx = rx[0] + self.verify_relayed_dhcp_discover(rx, self.pg2, + src_intf=self.pg5, + vpn_id="ip4-table-2") + + # + # 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_addr12 = self.pg1.remote_hosts[1].ip4 + + Proxy12 = VppDHCPProxy( + self, + server_addr12, + src_addr, + rx_vrf_id=1, + server_vrf_id=1) + Proxy12.add_vpp_config() + + # + # 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.pg4.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_relayed_dhcp_discover( + rx[0], self.pg1, + src_intf=self.pg4, + dst_mac=self.pg1.remote_hosts[1].mac, + dst_ip=self.pg1.remote_hosts[1].ip4, + fib_id=1, oui=4) + self.verify_relayed_dhcp_discover(rx[1], self.pg1, + src_intf=self.pg4, + 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.pg4.get_capture(2) + + self.verify_dhcp_offer(rx[0], self.pg4, fib_id=1, oui=4) + self.verify_dhcp_offer(rx[1], self.pg4, 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.pg4.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.pg4.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 + # + Proxy12.remove_vpp_config() + + # + # Test we can still relay with the first + # + self.pg4.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_relayed_dhcp_discover(rx, self.pg1, + src_intf=self.pg4, + fib_id=1, oui=4) + + # + # Remove the VSS config + # relayed DHCP has default vlaues in the option. + # + self.vapi.dhcp_proxy_set_vss(tbl_id=1, is_add=0) + self.vapi.dhcp_proxy_set_vss(tbl_id=2, is_add=0) + + self.pg4.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_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg4) + + # + # remove DHCP config to cleanup + # + Proxy1.remove_vpp_config() + Proxy2.remove_vpp_config() + + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0, + "DHCP cleanup VRF 0") + self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1, + "DHCP cleanup VRF 1") + self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2, + "DHCP cleanup VRF 2") + + self.pg3.unconfig_ip4() + self.pg4.unconfig_ip4() + self.pg5.unconfig_ip4() + + def test_dhcp6_proxy(self): + """ DHCPv6 Proxy""" + # + # Verify no response to DHCP request without DHCP config + # + dhcp_solicit_dst = "ff02::1:2" + dhcp_solicit_src_vrf0 = mk_ll_addr(self.pg3.remote_mac) + dhcp_solicit_src_vrf1 = mk_ll_addr(self.pg4.remote_mac) + dhcp_solicit_src_vrf2 = mk_ll_addr(self.pg5.remote_mac) + server_addr_vrf0 = self.pg0.remote_ip6 + src_addr_vrf0 = self.pg0.local_ip6 + server_addr_vrf1 = self.pg1.remote_ip6 + src_addr_vrf1 = self.pg1.local_ip6 + server_addr_vrf2 = self.pg2.remote_ip6 + src_addr_vrf2 = self.pg2.local_ip6 + + dmac = in6_getnsmac(inet_pton(socket.AF_INET6, dhcp_solicit_dst)) + p_solicit_vrf0 = (Ether(dst=dmac, src=self.pg3.remote_mac) / + IPv6(src=dhcp_solicit_src_vrf0, + dst=dhcp_solicit_dst) / + UDP(sport=DHCP6_SERVER_PORT, + dport=DHCP6_CLIENT_PORT) / + DHCP6_Solicit()) + p_solicit_vrf1 = (Ether(dst=dmac, src=self.pg4.remote_mac) / + IPv6(src=dhcp_solicit_src_vrf1, + dst=dhcp_solicit_dst) / + UDP(sport=DHCP6_SERVER_PORT, + dport=DHCP6_CLIENT_PORT) / + DHCP6_Solicit()) + p_solicit_vrf2 = (Ether(dst=dmac, src=self.pg5.remote_mac) / + IPv6(src=dhcp_solicit_src_vrf2, + dst=dhcp_solicit_dst) / + UDP(sport=DHCP6_SERVER_PORT, + dport=DHCP6_CLIENT_PORT) / + DHCP6_Solicit()) + + self.send_and_assert_no_replies(self.pg3, p_solicit_vrf0, + "DHCP with no configuration") + self.send_and_assert_no_replies(self.pg4, p_solicit_vrf1, + "DHCP with no configuration") + self.send_and_assert_no_replies(self.pg5, p_solicit_vrf2, + "DHCP with no configuration") + + # + # DHCPv6 config in VRF 0. + # Packets still dropped because the client facing interface has no + # IPv6 config + # + Proxy = VppDHCPProxy( + self, + server_addr_vrf0, + src_addr_vrf0, + rx_vrf_id=0, + server_vrf_id=0) + Proxy.add_vpp_config() + + self.send_and_assert_no_replies(self.pg3, p_solicit_vrf0, + "DHCP with no configuration") + self.send_and_assert_no_replies(self.pg4, p_solicit_vrf1, + "DHCP with no configuration") + + # + # configure an IP address on the client facing interface + # + self.pg3.config_ip6() + + # + # Now the DHCP requests are relayed to the server + # + self.pg3.add_stream(p_solicit_vrf0) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg0.get_capture(1) + + self.verify_dhcp6_solicit(rx[0], self.pg0, + dhcp_solicit_src_vrf0, + self.pg3.remote_mac) + + # + # Exception cases for rejected relay responses + # + + # 1 - not a relay reply + p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_Advertise()) + self.send_and_assert_no_replies(self.pg3, p_adv_vrf0, + "DHCP6 not a relay reply") + + # 2 - no relay message option + p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply() / + DHCP6_Advertise()) + self.send_and_assert_no_replies(self.pg3, p_adv_vrf0, + "DHCP not a relay message") + + # 3 - no circuit ID + p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply() / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise()) + self.send_and_assert_no_replies(self.pg3, 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) / + IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply() / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise()) + self.send_and_assert_no_replies(self.pg3, p_adv_vrf0, + "DHCP6 wrong circuit ID") + + # + # Send the relay response (the advertisement) + # - no peer address + p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply() / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise(trid=1) / + DHCP6OptStatusCode(statuscode=0)) + pkts_adv_vrf0 = [p_adv_vrf0] + + self.pg0.add_stream(pkts_adv_vrf0) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg3.get_capture(1) + + self.verify_dhcp6_advert(rx[0], self.pg3, "::") + + # + # Send the relay response (the advertisement) + # - with peer address + p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf0) / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise(trid=1) / + DHCP6OptStatusCode(statuscode=0)) + pkts_adv_vrf0 = [p_adv_vrf0] + + self.pg0.add_stream(pkts_adv_vrf0) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg3.get_capture(1) + + self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf0) + + # + # Add all the config for VRF 1 & 2 + # + Proxy1 = VppDHCPProxy( + self, + server_addr_vrf1, + src_addr_vrf1, + rx_vrf_id=1, + server_vrf_id=1) + Proxy1.add_vpp_config() + self.pg4.config_ip6() + + Proxy2 = VppDHCPProxy( + self, + server_addr_vrf2, + src_addr_vrf2, + rx_vrf_id=2, + server_vrf_id=2) + Proxy2.add_vpp_config() + self.pg5.config_ip6() + + # + # VRF 1 solicit + # + self.pg4.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.pg4.remote_mac) + + # + # VRF 2 solicit + # + self.pg5.add_stream(p_solicit_vrf2) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + + self.verify_dhcp6_solicit(rx[0], self.pg2, + dhcp_solicit_src_vrf2, + self.pg5.remote_mac) + + # + # VRF 1 Advert + # + p_adv_vrf1 = (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\x05') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise(trid=1) / + DHCP6OptStatusCode(statuscode=0)) + pkts_adv_vrf1 = [p_adv_vrf1] + + self.pg1.add_stream(pkts_adv_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg4.get_capture(1) + + self.verify_dhcp6_advert(rx[0], self.pg4, dhcp_solicit_src_vrf1) + + # + # Add VSS config + # + self.vapi.dhcp_proxy_set_vss( + tbl_id=1, vss_type=1, oui=4, vpn_index=1, is_ipv6=1, is_add=1) + self.vapi.dhcp_proxy_set_vss( + tbl_id=2, + vss_type=0, + vpn_ascii_id="IPv6-table-2", + is_ipv6=1, + is_add=1) + + self.pg4.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.pg4.remote_mac, + fib_id=1, + oui=4) + + self.pg5.add_stream(p_solicit_vrf2) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + + self.verify_dhcp6_solicit(rx[0], self.pg2, + dhcp_solicit_src_vrf2, + self.pg5.remote_mac, + vpn_id="IPv6-table-2") + + # + # Remove the VSS config + # relayed DHCP has default vlaues in the option. + # + self.vapi.dhcp_proxy_set_vss(tbl_id=1, is_ipv6=1, is_add=0) + + self.pg4.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.pg4.remote_mac) + + # + # 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_addr12 = self.pg1.remote_hosts[1].ip6 + + Proxy12 = VppDHCPProxy( + self, + server_addr12, + src_addr_vrf1, + rx_vrf_id=1, + server_vrf_id=1) + Proxy12.add_vpp_config() + + # + # 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) + 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.pg4.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.pg4.remote_mac) + self.verify_dhcp6_solicit(rx[1], self.pg1, + dhcp_solicit_src_vrf1, + self.pg4.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\x05') / + 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\x05') / + 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.pg4.get_capture(2) + + self.verify_dhcp6_advert(rx[0], self.pg4, dhcp_solicit_src_vrf1) + self.verify_dhcp6_advert(rx[1], self.pg4, dhcp_solicit_src_vrf1) + + # + # Ensure only solicit messages are duplicated + # + p_request_vrf1 = (Ether(dst=dmac, src=self.pg4.remote_mac) / + IPv6(src=dhcp_solicit_src_vrf1, + dst=dhcp_solicit_dst) / + UDP(sport=DHCP6_SERVER_PORT, + dport=DHCP6_CLIENT_PORT) / + DHCP6_Request()) + + self.pg4.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\x05') / + 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 + # + Proxy12.remove_vpp_config() + + # + # Test we can still relay with the first + # + self.pg4.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.pg4.remote_mac) + + # + # Cleanup + # + Proxy.remove_vpp_config() + Proxy1.remove_vpp_config() + Proxy2.remove_vpp_config() + + self.pg3.unconfig_ip6() + self.pg4.unconfig_ip6() + self.pg5.unconfig_ip6() + + def test_dhcp_client(self): + """ DHCP Client""" + + vdscp = VppEnum.vl_api_ip_dscp_t + hostname = 'universal-dp' + + self.pg_enable_capture(self.pg_interfaces) + + # + # Configure DHCP client on PG3 and capture the discover sent + # + Client = VppDHCPClient(self, self.pg3.sw_if_index, hostname) + Client.add_vpp_config() + self.assertTrue(Client.query_vpp_config()) + + rx = self.pg3.get_capture(1) + + self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname) + + # + # Send back on offer, expect the request + # + p_offer = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / + IP(src=self.pg3.remote_ip4, dst="255.255.255.255") / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / + BOOTP(op=1, + yiaddr=self.pg3.local_ip4, + chaddr=mac_pton(self.pg3.local_mac)) / + DHCP(options=[('message-type', 'offer'), + ('server_id', self.pg3.remote_ip4), + 'end'])) + + self.pg3.add_stream(p_offer) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg3.get_capture(1) + self.verify_orig_dhcp_request(rx[0], self.pg3, hostname, + self.pg3.local_ip4) + + # + # Send an acknowledgment + # + p_ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / + IP(src=self.pg3.remote_ip4, dst="255.255.255.255") / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / + BOOTP(op=1, yiaddr=self.pg3.local_ip4, + chaddr=mac_pton(self.pg3.local_mac)) / + DHCP(options=[('message-type', 'ack'), + ('subnet_mask', "255.255.255.0"), + ('router', self.pg3.remote_ip4), + ('server_id', self.pg3.remote_ip4), + ('lease_time', 43200), + 'end'])) + + self.pg3.add_stream(p_ack) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # + # We'll get an ARP request for the router address + # + rx = self.pg3.get_capture(1) + + self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4) + self.pg_enable_capture(self.pg_interfaces) + + # + # At the end of this procedure there should be a connected route + # in the FIB + # + self.assertTrue(find_route(self, self.pg3.local_ip4, 24)) + self.assertTrue(find_route(self, self.pg3.local_ip4, 32)) + + # remove the left over ARP entry + self.vapi.ip_neighbor_add_del(self.pg3.sw_if_index, + self.pg3.remote_mac, + self.pg3.remote_ip4, + is_add=0) + + # + # remove the DHCP config + # + Client.remove_vpp_config() + + # + # and now the route should be gone + # + self.assertFalse(find_route(self, self.pg3.local_ip4, 32)) + self.assertFalse(find_route(self, self.pg3.local_ip4, 24)) + + # + # Start the procedure again. this time have VPP send the client-ID + # and set the DSCP value + # + self.pg3.admin_down() + self.sleep(1) + self.pg3.admin_up() + Client.set_client(self.pg3.sw_if_index, hostname, + id=self.pg3.local_mac, + dscp=vdscp.IP_API_DSCP_EF) + Client.add_vpp_config() + + rx = self.pg3.get_capture(1) + + self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname, + self.pg3.local_mac, + dscp=vdscp.IP_API_DSCP_EF) + + # TODO: VPP DHCP client should not accept DHCP OFFER message with + # the XID (Transaction ID) not matching the XID of the most recent + # DHCP DISCOVERY message. + # Such DHCP OFFER message must be silently discarded - RFC2131. + # Reported in Jira ticket: VPP-99 + self.pg3.add_stream(p_offer) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg3.get_capture(1) + self.verify_orig_dhcp_request(rx[0], self.pg3, hostname, + self.pg3.local_ip4, + dscp=vdscp.IP_API_DSCP_EF) + + # + # unicast the ack to the offered address + # + p_ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / + IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / + BOOTP(op=1, yiaddr=self.pg3.local_ip4, + chaddr=mac_pton(self.pg3.local_mac)) / + DHCP(options=[('message-type', 'ack'), + ('subnet_mask', "255.255.255.0"), + ('router', self.pg3.remote_ip4), + ('server_id', self.pg3.remote_ip4), + ('lease_time', 43200), + 'end'])) + + self.pg3.add_stream(p_ack) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # + # We'll get an ARP request for the router address + # + rx = self.pg3.get_capture(1) + + self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4) + self.pg_enable_capture(self.pg_interfaces) + + # + # At the end of this procedure there should be a connected route + # in the FIB + # + self.assertTrue(find_route(self, self.pg3.local_ip4, 32)) + self.assertTrue(find_route(self, self.pg3.local_ip4, 24)) + + # + # remove the DHCP config + # + Client.remove_vpp_config() + + self.assertFalse(find_route(self, self.pg3.local_ip4, 32)) + self.assertFalse(find_route(self, self.pg3.local_ip4, 24)) + + # + # Rince and repeat, this time with VPP configured not to set + # the braodcast flag in the discover and request messages, + # and for the server to unicast the responses. + # + # Configure DHCP client on PG3 and capture the discover sent + # + Client.set_client( + self.pg3.sw_if_index, + hostname, + set_broadcast_flag=False) + Client.add_vpp_config() + + rx = self.pg3.get_capture(1) + + self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname, + broadcast=False) + + # + # Send back on offer, unicasted to the offered address. + # Expect the request. + # + p_offer = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / + IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / + BOOTP(op=1, yiaddr=self.pg3.local_ip4, + chaddr=mac_pton(self.pg3.local_mac)) / + DHCP(options=[('message-type', 'offer'), + ('server_id', self.pg3.remote_ip4), + 'end'])) + + self.pg3.add_stream(p_offer) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg3.get_capture(1) + self.verify_orig_dhcp_request(rx[0], self.pg3, hostname, + self.pg3.local_ip4, + broadcast=False) + + # + # Send an acknowledgment, the lease renewal time is 2 seconds + # so we should expect the renew straight after + # + p_ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / + IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / + BOOTP(op=1, yiaddr=self.pg3.local_ip4, + chaddr=mac_pton(self.pg3.local_mac)) / + DHCP(options=[('message-type', 'ack'), + ('subnet_mask', "255.255.255.0"), + ('router', self.pg3.remote_ip4), + ('server_id', self.pg3.remote_ip4), + ('lease_time', 43200), + ('renewal_time', 2), + 'end'])) + + self.pg3.add_stream(p_ack) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # + # We'll get an ARP request for the router address + # + rx = self.pg3.get_capture(1) + + self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4) + self.pg_enable_capture(self.pg_interfaces) + + # + # At the end of this procedure there should be a connected route + # in the FIB + # + self.assertTrue(find_route(self, self.pg3.local_ip4, 24)) + self.assertTrue(find_route(self, self.pg3.local_ip4, 32)) + + # + # wait for the unicasted renewal + # the first attempt will be an ARP packet, since we have not yet + # responded to VPP's request + # + self.logger.info(self.vapi.cli("sh dhcp client intfc pg3 verbose")) + rx = self.pg3.get_capture(1, timeout=10) + + self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4) + + # respond to the arp + p_arp = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / + ARP(op="is-at", + hwdst=self.pg3.local_mac, + hwsrc=self.pg3.remote_mac, + pdst=self.pg3.local_ip4, + psrc=self.pg3.remote_ip4)) + self.pg3.add_stream(p_arp) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # the next packet is the unicasted renewal + rx = self.pg3.get_capture(1, timeout=10) + self.verify_orig_dhcp_request(rx[0], self.pg3, hostname, + self.pg3.local_ip4, + l2_bc=False, + broadcast=False) + + # + # read the DHCP client details from a dump + # + clients = self.vapi.dhcp_client_dump() + + self.assertEqual(clients[0].client.sw_if_index, + self.pg3.sw_if_index) + self.assertEqual(clients[0].lease.sw_if_index, + self.pg3.sw_if_index) + self.assertEqual(clients[0].client.hostname.rstrip('\0'), + hostname) + self.assertEqual(clients[0].lease.hostname.rstrip('\0'), + hostname) + # 0 = DISCOVER, 1 = REQUEST, 2 = BOUND + self.assertEqual(clients[0].lease.state, 2) + self.assertEqual(clients[0].lease.mask_width, 24) + self.assertEqual(str(clients[0].lease.router_address), + self.pg3.remote_ip4) + self.assertEqual(str(clients[0].lease.host_address), + self.pg3.local_ip4) + + # remove the left over ARP entry + self.vapi.ip_neighbor_add_del(self.pg3.sw_if_index, + self.pg3.remote_mac, + self.pg3.remote_ip4, + is_add=0) + + # + # remove the DHCP config + # + Client.remove_vpp_config() + + # + # and now the route should be gone + # + self.assertFalse(find_route(self, self.pg3.local_ip4, 32)) + self.assertFalse(find_route(self, self.pg3.local_ip4, 24)) + + # + # Start the procedure again. Use requested lease time option. + # + hostname += "-2" + self.pg3.admin_down() + self.sleep(1) + self.pg3.admin_up() + self.pg_enable_capture(self.pg_interfaces) + Client.set_client(self.pg3.sw_if_index, hostname) + Client.add_vpp_config() + + rx = self.pg3.get_capture(1) + + self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname) + + # + # Send back on offer with requested lease time, expect the request + # + lease_time = 1 + p_offer = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / + IP(src=self.pg3.remote_ip4, dst='255.255.255.255') / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / + BOOTP(op=1, + yiaddr=self.pg3.local_ip4, + chaddr=mac_pton(self.pg3.local_mac)) / + DHCP(options=[('message-type', 'offer'), + ('server_id', self.pg3.remote_ip4), + ('lease_time', lease_time), + 'end'])) + + self.pg3.add_stream(p_offer) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg3.get_capture(1) + self.verify_orig_dhcp_request(rx[0], self.pg3, hostname, + self.pg3.local_ip4) + + # + # Send an acknowledgment + # + p_ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / + IP(src=self.pg3.remote_ip4, dst='255.255.255.255') / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / + BOOTP(op=1, yiaddr=self.pg3.local_ip4, + chaddr=mac_pton(self.pg3.local_mac)) / + DHCP(options=[('message-type', 'ack'), + ('subnet_mask', '255.255.255.0'), + ('router', self.pg3.remote_ip4), + ('server_id', self.pg3.remote_ip4), + ('lease_time', lease_time), + 'end'])) + + self.pg3.add_stream(p_ack) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # + # We'll get an ARP request for the router address + # + rx = self.pg3.get_capture(1) + + self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4) + + # + # At the end of this procedure there should be a connected route + # in the FIB + # + self.assertTrue(find_route(self, self.pg3.local_ip4, 32)) + self.assertTrue(find_route(self, self.pg3.local_ip4, 24)) + + # remove the left over ARP entry + self.vapi.ip_neighbor_add_del(self.pg3.sw_if_index, + self.pg3.remote_mac, + self.pg3.remote_ip4, + is_add=0) + + # + # the route should be gone after the lease expires + # + self.assertTrue(self.wait_for_no_route(self.pg3.local_ip4, 32)) + self.assertTrue(self.wait_for_no_route(self.pg3.local_ip4, 24)) + + # + # remove the DHCP config + # + Client.remove_vpp_config() + + def test_dhcp_client_vlan(self): + """ DHCP Client w/ VLAN""" + + vdscp = VppEnum.vl_api_ip_dscp_t + vqos = VppEnum.vl_api_qos_source_t + hostname = 'universal-dp' + + self.pg_enable_capture(self.pg_interfaces) + + vlan_100 = VppDot1QSubint(self, self.pg3, 100) + vlan_100.admin_up() + + output = [scapy.compat.chb(4)] * 256 + os = b''.join(output) + rows = [{'outputs': os}, + {'outputs': os}, + {'outputs': os}, + {'outputs': os}] + + qem1 = VppQosEgressMap(self, 1, rows).add_vpp_config() + qm1 = VppQosMark(self, vlan_100, qem1, + vqos.QOS_API_SOURCE_VLAN).add_vpp_config() + + # + # Configure DHCP client on PG3 and capture the discover sent + # + Client = VppDHCPClient( + self, + vlan_100.sw_if_index, + hostname, + dscp=vdscp.IP_API_DSCP_EF) + Client.add_vpp_config() + + rx = self.pg3.get_capture(1) + + self.assertEqual(rx[0][Dot1Q].vlan, 100) + self.assertEqual(rx[0][Dot1Q].prio, 2) + + self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname, + dscp=vdscp.IP_API_DSCP_EF) + + +if __name__ == '__main__': + unittest.main(testRunner=VppTestRunner) diff --git a/src/plugins/dhcp/test/test_dhcp6.py b/src/plugins/dhcp/test/test_dhcp6.py new file mode 100644 index 00000000000..02f420243cb --- /dev/null +++ b/src/plugins/dhcp/test/test_dhcp6.py @@ -0,0 +1,806 @@ +from socket import AF_INET6 + +from scapy.layers.dhcp6 import DHCP6_Advertise, DHCP6OptClientId, \ + DHCP6OptStatusCode, DHCP6OptPref, DHCP6OptIA_PD, DHCP6OptIAPrefix, \ + DHCP6OptServerId, DHCP6_Solicit, DHCP6_Reply, DHCP6_Request, DHCP6_Renew, \ + DHCP6_Rebind, DUID_LL, DHCP6_Release, DHCP6OptElapsedTime, DHCP6OptIA_NA, \ + DHCP6OptIAAddress +from scapy.layers.inet6 import IPv6, Ether, UDP +from scapy.utils6 import in6_mactoifaceid +from scapy.utils import inet_ntop, inet_pton + +from framework import VppTestCase +from vpp_papi import VppEnum +import util +import os + + +def ip6_normalize(ip6): + return inet_ntop(AF_INET6, inet_pton(AF_INET6, ip6)) + + +class TestDHCPv6DataPlane(VppTestCase): + """ DHCPv6 Data Plane Test Case """ + + @classmethod + def setUpClass(cls): + super(TestDHCPv6DataPlane, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestDHCPv6DataPlane, cls).tearDownClass() + + def setUp(self): + super(TestDHCPv6DataPlane, self).setUp() + + self.create_pg_interfaces(range(1)) + self.interfaces = list(self.pg_interfaces) + for i in self.interfaces: + i.admin_up() + i.config_ip6() + + self.server_duid = DUID_LL(lladdr=self.pg0.remote_mac) + + def tearDown(self): + for i in self.interfaces: + i.unconfig_ip6() + i.admin_down() + super(TestDHCPv6DataPlane, self).tearDown() + + def test_dhcp_ia_na_send_solicit_receive_advertise(self): + """ Verify DHCPv6 IA NA Solicit packet and Advertise event """ + + self.vapi.dhcp6_clients_enable_disable(enable=1) + + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + address = {'address': '1:2:3::5', + 'preferred_time': 60, + 'valid_time': 120} + self.vapi.dhcp6_send_client_message( + server_index=0xffffffff, + mrc=1, + msg_type=VppEnum.vl_api_dhcpv6_msg_type_t.DHCPV6_MSG_API_SOLICIT, + sw_if_index=self.pg0.sw_if_index, + T1=20, + T2=40, + addresses=[address], + n_addresses=len( + [address])) + rx_list = self.pg0.get_capture(1) + self.assertEqual(len(rx_list), 1) + packet = rx_list[0] + + self.assertEqual(packet.haslayer(IPv6), 1) + self.assertEqual(packet[IPv6].haslayer(DHCP6_Solicit), 1) + + client_duid = packet[DHCP6OptClientId].duid + trid = packet[DHCP6_Solicit].trid + + dst = ip6_normalize(packet[IPv6].dst) + dst2 = ip6_normalize("ff02::1:2") + self.assert_equal(dst, dst2) + src = ip6_normalize(packet[IPv6].src) + src2 = ip6_normalize(self.pg0.local_ip6_ll) + self.assert_equal(src, src2) + ia_na = packet[DHCP6OptIA_NA] + self.assert_equal(ia_na.T1, 20) + self.assert_equal(ia_na.T2, 40) + self.assert_equal(len(ia_na.ianaopts), 1) + address = ia_na.ianaopts[0] + self.assert_equal(address.addr, '1:2:3::5') + self.assert_equal(address.preflft, 60) + self.assert_equal(address.validlft, 120) + + self.vapi.want_dhcp6_reply_events(enable_disable=1, + pid=os.getpid()) + + try: + ia_na_opts = DHCP6OptIAAddress(addr='7:8::2', preflft=60, + validlft=120) + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IPv6(src=util.mk_ll_addr(self.pg0.remote_mac), + dst=self.pg0.local_ip6_ll) / + UDP(sport=547, dport=546) / + DHCP6_Advertise(trid=trid) / + DHCP6OptServerId(duid=self.server_duid) / + DHCP6OptClientId(duid=client_duid) / + DHCP6OptPref(prefval=7) / + DHCP6OptStatusCode(statuscode=1) / + DHCP6OptIA_NA(iaid=1, T1=20, T2=40, ianaopts=ia_na_opts) + ) + self.pg0.add_stream([p]) + self.pg_start() + + ev = self.vapi.wait_for_event(1, "dhcp6_reply_event") + + self.assert_equal(ev.preference, 7) + self.assert_equal(ev.status_code, 1) + self.assert_equal(ev.T1, 20) + self.assert_equal(ev.T2, 40) + + reported_address = ev.addresses[0] + address = ia_na_opts.getfieldval("addr") + self.assert_equal(str(reported_address.address), address) + self.assert_equal(reported_address.preferred_time, + ia_na_opts.getfieldval("preflft")) + self.assert_equal(reported_address.valid_time, + ia_na_opts.getfieldval("validlft")) + + finally: + self.vapi.want_dhcp6_reply_events(enable_disable=0) + self.vapi.dhcp6_clients_enable_disable(enable=0) + + def test_dhcp_pd_send_solicit_receive_advertise(self): + """ Verify DHCPv6 PD Solicit packet and Advertise event """ + + self.vapi.dhcp6_clients_enable_disable(enable=1) + + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + prefix = {'prefix': {'address': '1:2:3::', 'len': 50}, + 'preferred_time': 60, + 'valid_time': 120} + prefixes = [prefix] + self.vapi.dhcp6_pd_send_client_message( + server_index=0xffffffff, + mrc=1, + msg_type=VppEnum.vl_api_dhcpv6_msg_type_t.DHCPV6_MSG_API_SOLICIT, + sw_if_index=self.pg0.sw_if_index, + T1=20, + T2=40, + prefixes=prefixes, + n_prefixes=len(prefixes)) + rx_list = self.pg0.get_capture(1) + self.assertEqual(len(rx_list), 1) + packet = rx_list[0] + + self.assertEqual(packet.haslayer(IPv6), 1) + self.assertEqual(packet[IPv6].haslayer(DHCP6_Solicit), 1) + + client_duid = packet[DHCP6OptClientId].duid + trid = packet[DHCP6_Solicit].trid + + dst = ip6_normalize(packet[IPv6].dst) + dst2 = ip6_normalize("ff02::1:2") + self.assert_equal(dst, dst2) + src = ip6_normalize(packet[IPv6].src) + src2 = ip6_normalize(self.pg0.local_ip6_ll) + self.assert_equal(src, src2) + ia_pd = packet[DHCP6OptIA_PD] + self.assert_equal(ia_pd.T1, 20) + self.assert_equal(ia_pd.T2, 40) + self.assert_equal(len(ia_pd.iapdopt), 1) + prefix = ia_pd.iapdopt[0] + self.assert_equal(prefix.prefix, '1:2:3::') + self.assert_equal(prefix.plen, 50) + self.assert_equal(prefix.preflft, 60) + self.assert_equal(prefix.validlft, 120) + + self.vapi.want_dhcp6_pd_reply_events(enable_disable=1, + pid=os.getpid()) + + try: + ia_pd_opts = DHCP6OptIAPrefix(prefix='7:8::', plen=56, preflft=60, + validlft=120) + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IPv6(src=util.mk_ll_addr(self.pg0.remote_mac), + dst=self.pg0.local_ip6_ll) / + UDP(sport=547, dport=546) / + DHCP6_Advertise(trid=trid) / + DHCP6OptServerId(duid=self.server_duid) / + DHCP6OptClientId(duid=client_duid) / + DHCP6OptPref(prefval=7) / + DHCP6OptStatusCode(statuscode=1) / + DHCP6OptIA_PD(iaid=1, T1=20, T2=40, iapdopt=ia_pd_opts) + ) + self.pg0.add_stream([p]) + self.pg_start() + + ev = self.vapi.wait_for_event(1, "dhcp6_pd_reply_event") + + self.assert_equal(ev.preference, 7) + self.assert_equal(ev.status_code, 1) + self.assert_equal(ev.T1, 20) + self.assert_equal(ev.T2, 40) + + reported_prefix = ev.prefixes[0] + prefix = ia_pd_opts.getfieldval("prefix") + self.assert_equal( + str(reported_prefix.prefix).split('/')[0], prefix) + self.assert_equal(int(str(reported_prefix.prefix).split('/')[1]), + ia_pd_opts.getfieldval("plen")) + self.assert_equal(reported_prefix.preferred_time, + ia_pd_opts.getfieldval("preflft")) + self.assert_equal(reported_prefix.valid_time, + ia_pd_opts.getfieldval("validlft")) + + finally: + self.vapi.want_dhcp6_pd_reply_events(enable_disable=0) + self.vapi.dhcp6_clients_enable_disable(enable=0) + + +class TestDHCPv6IANAControlPlane(VppTestCase): + """ DHCPv6 IA NA Control Plane Test Case """ + + @classmethod + def setUpClass(cls): + super(TestDHCPv6IANAControlPlane, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestDHCPv6IANAControlPlane, cls).tearDownClass() + + def setUp(self): + super(TestDHCPv6IANAControlPlane, self).setUp() + + self.create_pg_interfaces(range(1)) + self.interfaces = list(self.pg_interfaces) + for i in self.interfaces: + i.admin_up() + + self.server_duid = DUID_LL(lladdr=self.pg0.remote_mac) + self.client_duid = None + self.T1 = 1 + self.T2 = 2 + + fib = self.vapi.ip_route_dump(0, True) + self.initial_addresses = set(self.get_interface_addresses(fib, + self.pg0)) + + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + self.vapi.dhcp6_client_enable_disable(sw_if_index=self.pg0.sw_if_index, + enable=1) + + def tearDown(self): + self.vapi.dhcp6_client_enable_disable(sw_if_index=self.pg0.sw_if_index, + enable=0) + + for i in self.interfaces: + i.admin_down() + + super(TestDHCPv6IANAControlPlane, self).tearDown() + + @staticmethod + def get_interface_addresses(fib, pg): + lst = [] + for entry in fib: + if entry.route.prefix.prefixlen == 128: + path = entry.route.paths[0] + if path.sw_if_index == pg.sw_if_index: + lst.append(str(entry.route.prefix.network_address)) + return lst + + def get_addresses(self): + fib = self.vapi.ip_route_dump(0, True) + addresses = set(self.get_interface_addresses(fib, self.pg0)) + return addresses.difference(self.initial_addresses) + + def validate_duid_ll(self, duid): + DUID_LL(duid) + + def validate_packet(self, packet, msg_type, is_resend=False): + try: + self.assertEqual(packet.haslayer(msg_type), 1) + client_duid = packet[DHCP6OptClientId].duid + if self.client_duid is None: + self.client_duid = client_duid + self.validate_duid_ll(client_duid) + else: + self.assertEqual(self.client_duid, client_duid) + if msg_type != DHCP6_Solicit and msg_type != DHCP6_Rebind: + server_duid = packet[DHCP6OptServerId].duid + self.assertEqual(server_duid, self.server_duid) + if is_resend: + self.assertEqual(self.trid, packet[msg_type].trid) + else: + self.trid = packet[msg_type].trid + ip = packet[IPv6] + udp = packet[UDP] + self.assertEqual(ip.dst, 'ff02::1:2') + self.assertEqual(udp.sport, 546) + self.assertEqual(udp.dport, 547) + dhcpv6 = packet[msg_type] + elapsed_time = dhcpv6[DHCP6OptElapsedTime] + if (is_resend): + self.assertNotEqual(elapsed_time.elapsedtime, 0) + else: + self.assertEqual(elapsed_time.elapsedtime, 0) + except BaseException: + packet.show() + raise + + def wait_for_packet(self, msg_type, timeout=None, is_resend=False): + if timeout is None: + timeout = 3 + rx_list = self.pg0.get_capture(1, timeout=timeout) + packet = rx_list[0] + self.validate_packet(packet, msg_type, is_resend=is_resend) + + def wait_for_solicit(self, timeout=None, is_resend=False): + self.wait_for_packet(DHCP6_Solicit, timeout, is_resend=is_resend) + + def wait_for_request(self, timeout=None, is_resend=False): + self.wait_for_packet(DHCP6_Request, timeout, is_resend=is_resend) + + def wait_for_renew(self, timeout=None, is_resend=False): + self.wait_for_packet(DHCP6_Renew, timeout, is_resend=is_resend) + + def wait_for_rebind(self, timeout=None, is_resend=False): + self.wait_for_packet(DHCP6_Rebind, timeout, is_resend=is_resend) + + def wait_for_release(self, timeout=None, is_resend=False): + self.wait_for_packet(DHCP6_Release, timeout, is_resend=is_resend) + + def send_packet(self, msg_type, t1=None, t2=None, ianaopts=None): + if t1 is None: + t1 = self.T1 + if t2 is None: + t2 = self.T2 + if ianaopts is None: + opt_ia_na = DHCP6OptIA_NA(iaid=1, T1=t1, T2=t2) + else: + opt_ia_na = DHCP6OptIA_NA(iaid=1, T1=t1, T2=t2, ianaopts=ianaopts) + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IPv6(src=util.mk_ll_addr(self.pg0.remote_mac), + dst=self.pg0.local_ip6_ll) / + UDP(sport=547, dport=546) / + msg_type(trid=self.trid) / + DHCP6OptServerId(duid=self.server_duid) / + DHCP6OptClientId(duid=self.client_duid) / + opt_ia_na + ) + self.pg0.add_stream([p]) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + def send_advertise(self, t1=None, t2=None, ianaopts=None): + self.send_packet(DHCP6_Advertise, t1, t2, ianaopts) + + def send_reply(self, t1=None, t2=None, ianaopts=None): + self.send_packet(DHCP6_Reply, t1, t2, ianaopts) + + def test_T1_and_T2_timeouts(self): + """ Test T1 and T2 timeouts """ + + self.wait_for_solicit() + self.send_advertise() + self.wait_for_request() + self.send_reply() + + self.sleep(1) + + self.wait_for_renew() + + self.pg_enable_capture(self.pg_interfaces) + + self.sleep(1) + + self.wait_for_rebind() + + def test_addresses(self): + """ Test handling of addresses """ + + ia_na_opts = DHCP6OptIAAddress(addr='7:8::2', preflft=1, + validlft=2) + + self.wait_for_solicit() + self.send_advertise(t1=20, t2=40, ianaopts=ia_na_opts) + self.wait_for_request() + self.send_reply(t1=20, t2=40, ianaopts=ia_na_opts) + self.sleep(0.1) + + # check FIB for new address + new_addresses = self.get_addresses() + self.assertEqual(len(new_addresses), 1) + addr = list(new_addresses)[0] + self.assertEqual(addr, '7:8::2') + + self.sleep(2) + + # check that the address is deleted + fib = self.vapi.ip_route_dump(0, True) + addresses = set(self.get_interface_addresses(fib, self.pg0)) + new_addresses = addresses.difference(self.initial_addresses) + self.assertEqual(len(new_addresses), 0) + + def test_sending_client_messages_solicit(self): + """ VPP receives messages from DHCPv6 client """ + + self.wait_for_solicit() + self.send_packet(DHCP6_Solicit) + self.send_packet(DHCP6_Request) + self.send_packet(DHCP6_Renew) + self.send_packet(DHCP6_Rebind) + self.sleep(1) + self.wait_for_solicit(is_resend=True) + + def test_sending_inappropriate_packets(self): + """ Server sends messages with inappropriate message types """ + + self.wait_for_solicit() + self.send_reply() + self.wait_for_solicit(is_resend=True) + self.send_advertise() + self.wait_for_request() + self.send_advertise() + self.wait_for_request(is_resend=True) + self.send_reply() + self.wait_for_renew() + + def test_no_address_available_in_advertise(self): + """ Advertise message contains NoAddrsAvail status code """ + + self.wait_for_solicit() + noavail = DHCP6OptStatusCode(statuscode=2) # NoAddrsAvail + self.send_advertise(ianaopts=noavail) + self.wait_for_solicit(is_resend=True) + + def test_preferred_greater_than_valid_lifetime(self): + """ Preferred lifetime is greater than valid lifetime """ + + self.wait_for_solicit() + self.send_advertise() + self.wait_for_request() + ia_na_opts = DHCP6OptIAAddress(addr='7:8::2', preflft=4, validlft=3) + self.send_reply(ianaopts=ia_na_opts) + + self.sleep(0.5) + + # check FIB contains no addresses + fib = self.vapi.ip_route_dump(0, True) + addresses = set(self.get_interface_addresses(fib, self.pg0)) + new_addresses = addresses.difference(self.initial_addresses) + self.assertEqual(len(new_addresses), 0) + + def test_T1_greater_than_T2(self): + """ T1 is greater than T2 """ + + self.wait_for_solicit() + self.send_advertise() + self.wait_for_request() + ia_na_opts = DHCP6OptIAAddress(addr='7:8::2', preflft=4, validlft=8) + self.send_reply(t1=80, t2=40, ianaopts=ia_na_opts) + + self.sleep(0.5) + + # check FIB contains no addresses + fib = self.vapi.ip_route_dump(0, True) + addresses = set(self.get_interface_addresses(fib, self.pg0)) + new_addresses = addresses.difference(self.initial_addresses) + self.assertEqual(len(new_addresses), 0) + + +class TestDHCPv6PDControlPlane(VppTestCase): + """ DHCPv6 PD Control Plane Test Case """ + + @classmethod + def setUpClass(cls): + super(TestDHCPv6PDControlPlane, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestDHCPv6PDControlPlane, cls).tearDownClass() + + def setUp(self): + super(TestDHCPv6PDControlPlane, self).setUp() + + self.create_pg_interfaces(range(2)) + self.interfaces = list(self.pg_interfaces) + for i in self.interfaces: + i.admin_up() + + self.server_duid = DUID_LL(lladdr=self.pg0.remote_mac) + self.client_duid = None + self.T1 = 1 + self.T2 = 2 + + fib = self.vapi.ip_route_dump(0, True) + self.initial_addresses = set(self.get_interface_addresses(fib, + self.pg1)) + + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + self.prefix_group = 'my-pd-prefix-group' + + self.vapi.dhcp6_pd_client_enable_disable( + enable=1, + sw_if_index=self.pg0.sw_if_index, + prefix_group=self.prefix_group) + + def tearDown(self): + self.vapi.dhcp6_pd_client_enable_disable(self.pg0.sw_if_index, + enable=0) + + for i in self.interfaces: + i.admin_down() + + super(TestDHCPv6PDControlPlane, self).tearDown() + + @staticmethod + def get_interface_addresses(fib, pg): + lst = [] + for entry in fib: + if entry.route.prefix.prefixlen == 128: + path = entry.route.paths[0] + if path.sw_if_index == pg.sw_if_index: + lst.append(str(entry.route.prefix.network_address)) + return lst + + def get_addresses(self): + fib = self.vapi.ip_route_dump(0, True) + addresses = set(self.get_interface_addresses(fib, self.pg1)) + return addresses.difference(self.initial_addresses) + + def validate_duid_ll(self, duid): + DUID_LL(duid) + + def validate_packet(self, packet, msg_type, is_resend=False): + try: + self.assertEqual(packet.haslayer(msg_type), 1) + client_duid = packet[DHCP6OptClientId].duid + if self.client_duid is None: + self.client_duid = client_duid + self.validate_duid_ll(client_duid) + else: + self.assertEqual(self.client_duid, client_duid) + if msg_type != DHCP6_Solicit and msg_type != DHCP6_Rebind: + server_duid = packet[DHCP6OptServerId].duid + self.assertEqual(server_duid, self.server_duid) + if is_resend: + self.assertEqual(self.trid, packet[msg_type].trid) + else: + self.trid = packet[msg_type].trid + ip = packet[IPv6] + udp = packet[UDP] + self.assertEqual(ip.dst, 'ff02::1:2') + self.assertEqual(udp.sport, 546) + self.assertEqual(udp.dport, 547) + dhcpv6 = packet[msg_type] + elapsed_time = dhcpv6[DHCP6OptElapsedTime] + if (is_resend): + self.assertNotEqual(elapsed_time.elapsedtime, 0) + else: + self.assertEqual(elapsed_time.elapsedtime, 0) + except BaseException: + packet.show() + raise + + def wait_for_packet(self, msg_type, timeout=None, is_resend=False): + if timeout is None: + timeout = 3 + rx_list = self.pg0.get_capture(1, timeout=timeout) + packet = rx_list[0] + self.validate_packet(packet, msg_type, is_resend=is_resend) + + def wait_for_solicit(self, timeout=None, is_resend=False): + self.wait_for_packet(DHCP6_Solicit, timeout, is_resend=is_resend) + + def wait_for_request(self, timeout=None, is_resend=False): + self.wait_for_packet(DHCP6_Request, timeout, is_resend=is_resend) + + def wait_for_renew(self, timeout=None, is_resend=False): + self.wait_for_packet(DHCP6_Renew, timeout, is_resend=is_resend) + + def wait_for_rebind(self, timeout=None, is_resend=False): + self.wait_for_packet(DHCP6_Rebind, timeout, is_resend=is_resend) + + def wait_for_release(self, timeout=None, is_resend=False): + self.wait_for_packet(DHCP6_Release, timeout, is_resend=is_resend) + + def send_packet(self, msg_type, t1=None, t2=None, iapdopt=None): + if t1 is None: + t1 = self.T1 + if t2 is None: + t2 = self.T2 + if iapdopt is None: + opt_ia_pd = DHCP6OptIA_PD(iaid=1, T1=t1, T2=t2) + else: + opt_ia_pd = DHCP6OptIA_PD(iaid=1, T1=t1, T2=t2, iapdopt=iapdopt) + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IPv6(src=util.mk_ll_addr(self.pg0.remote_mac), + dst=self.pg0.local_ip6_ll) / + UDP(sport=547, dport=546) / + msg_type(trid=self.trid) / + DHCP6OptServerId(duid=self.server_duid) / + DHCP6OptClientId(duid=self.client_duid) / + opt_ia_pd + ) + self.pg0.add_stream([p]) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + def send_advertise(self, t1=None, t2=None, iapdopt=None): + self.send_packet(DHCP6_Advertise, t1, t2, iapdopt) + + def send_reply(self, t1=None, t2=None, iapdopt=None): + self.send_packet(DHCP6_Reply, t1, t2, iapdopt) + + def test_T1_and_T2_timeouts(self): + """ Test T1 and T2 timeouts """ + + self.wait_for_solicit() + self.send_advertise() + self.wait_for_request() + self.send_reply() + + self.sleep(1) + + self.wait_for_renew() + + self.pg_enable_capture(self.pg_interfaces) + + self.sleep(1) + + self.wait_for_rebind() + + def test_prefixes(self): + """ Test handling of prefixes """ + + address_bin_1 = None + address_bin_2 = None + try: + address_bin_1 = '\x00' * 6 + '\x00\x02' + '\x00' * 6 + '\x04\x05' + address_prefix_length_1 = 60 + self.vapi.ip6_add_del_address_using_prefix(self.pg1.sw_if_index, + address_bin_1, + address_prefix_length_1, + self.prefix_group) + + ia_pd_opts = DHCP6OptIAPrefix(prefix='7:8::', plen=56, preflft=2, + validlft=3) + + self.wait_for_solicit() + self.send_advertise(t1=20, t2=40, iapdopt=ia_pd_opts) + self.wait_for_request() + self.send_reply(t1=20, t2=40, iapdopt=ia_pd_opts) + self.sleep(0.1) + + # check FIB for new address + new_addresses = self.get_addresses() + self.assertEqual(len(new_addresses), 1) + addr = list(new_addresses)[0] + self.assertEqual(addr, '7:8:0:2::405') + + self.sleep(1) + + address_bin_2 = '\x00' * 6 + '\x00\x76' + '\x00' * 6 + '\x04\x06' + address_prefix_length_2 = 62 + self.vapi.ip6_add_del_address_using_prefix(self.pg1.sw_if_index, + address_bin_2, + address_prefix_length_2, + self.prefix_group) + + self.sleep(1) + + # check FIB contains 2 addresses + fib = self.vapi.ip_route_dump(0, True) + addresses = set(self.get_interface_addresses(fib, self.pg1)) + new_addresses = addresses.difference(self.initial_addresses) + self.assertEqual(len(new_addresses), 2) + addr1 = list(new_addresses)[0] + addr2 = list(new_addresses)[1] + if addr1 == '7:8:0:76::406': + addr1, addr2 = addr2, addr1 + self.assertEqual(addr1, '7:8:0:2::405') + self.assertEqual(addr2, '7:8:0:76::406') + + self.sleep(1) + + # check that the addresses are deleted + fib = self.vapi.ip_route_dump(0, True) + addresses = set(self.get_interface_addresses(fib, self.pg1)) + new_addresses = addresses.difference(self.initial_addresses) + self.assertEqual(len(new_addresses), 0) + + finally: + if address_bin_1 is not None: + self.vapi.ip6_add_del_address_using_prefix( + self.pg1.sw_if_index, address_bin_1, + address_prefix_length_1, self.prefix_group, is_add=0) + if address_bin_2 is not None: + self.vapi.ip6_add_del_address_using_prefix( + self.pg1.sw_if_index, address_bin_2, + address_prefix_length_2, self.prefix_group, is_add=0) + + def test_sending_client_messages_solicit(self): + """ VPP receives messages from DHCPv6 client """ + + self.wait_for_solicit() + self.send_packet(DHCP6_Solicit) + self.send_packet(DHCP6_Request) + self.send_packet(DHCP6_Renew) + self.send_packet(DHCP6_Rebind) + self.sleep(1) + self.wait_for_solicit(is_resend=True) + + def test_sending_inappropriate_packets(self): + """ Server sends messages with inappropriate message types """ + + self.wait_for_solicit() + self.send_reply() + self.wait_for_solicit(is_resend=True) + self.send_advertise() + self.wait_for_request() + self.send_advertise() + self.wait_for_request(is_resend=True) + self.send_reply() + self.wait_for_renew() + + def test_no_prefix_available_in_advertise(self): + """ Advertise message contains NoPrefixAvail status code """ + + self.wait_for_solicit() + noavail = DHCP6OptStatusCode(statuscode=6) # NoPrefixAvail + self.send_advertise(iapdopt=noavail) + self.wait_for_solicit(is_resend=True) + + def test_preferred_greater_than_valid_lifetime(self): + """ Preferred lifetime is greater than valid lifetime """ + + try: + address_bin = '\x00' * 6 + '\x00\x02' + '\x00' * 6 + '\x04\x05' + address_prefix_length = 60 + self.vapi.ip6_add_del_address_using_prefix(self.pg1.sw_if_index, + address_bin, + address_prefix_length, + self.prefix_group) + + self.wait_for_solicit() + self.send_advertise() + self.wait_for_request() + ia_pd_opts = DHCP6OptIAPrefix(prefix='7:8::', plen=56, preflft=4, + validlft=3) + self.send_reply(iapdopt=ia_pd_opts) + + self.sleep(0.5) + + # check FIB contains no addresses + fib = self.vapi.ip_route_dump(0, True) + addresses = set(self.get_interface_addresses(fib, self.pg1)) + new_addresses = addresses.difference(self.initial_addresses) + self.assertEqual(len(new_addresses), 0) + + finally: + self.vapi.ip6_add_del_address_using_prefix(self.pg1.sw_if_index, + address_bin, + address_prefix_length, + self.prefix_group, + is_add=0) + + def test_T1_greater_than_T2(self): + """ T1 is greater than T2 """ + + try: + address_bin = '\x00' * 6 + '\x00\x02' + '\x00' * 6 + '\x04\x05' + address_prefix_length = 60 + self.vapi.ip6_add_del_address_using_prefix(self.pg1.sw_if_index, + address_bin, + address_prefix_length, + self.prefix_group) + + self.wait_for_solicit() + self.send_advertise() + self.wait_for_request() + ia_pd_opts = DHCP6OptIAPrefix(prefix='7:8::', plen=56, preflft=4, + validlft=8) + self.send_reply(t1=80, t2=40, iapdopt=ia_pd_opts) + + self.sleep(0.5) + + # check FIB contains no addresses + fib = self.vapi.ip_route_dump(0, True) + addresses = set(self.get_interface_addresses(fib, self.pg1)) + new_addresses = addresses.difference(self.initial_addresses) + self.assertEqual(len(new_addresses), 0) + + finally: + self.vapi.ip6_add_del_address_using_prefix(self.pg1.sw_if_index, + address_bin, + address_prefix_length, + self.prefix_group, + is_add=0) diff --git a/src/plugins/dhcp/test/vpp_dhcp.py b/src/plugins/dhcp/test/vpp_dhcp.py new file mode 100644 index 00000000000..56ec8caa7df --- /dev/null +++ b/src/plugins/dhcp/test/vpp_dhcp.py @@ -0,0 +1,129 @@ +from vpp_object import VppObject + + +class VppDHCPProxy(VppObject): + + def __init__( + self, + test, + dhcp_server, + dhcp_src_address, + rx_vrf_id=0, + server_vrf_id=0, + ): + self._test = test + self._rx_vrf_id = rx_vrf_id + self._server_vrf_id = server_vrf_id + self._dhcp_server = dhcp_server + self._dhcp_src_address = dhcp_src_address + + def set_proxy( + self, + dhcp_server, + dhcp_src_address, + rx_vrf_id=0, + server_vrf_id=0): + if self.query_vpp_config(): + raise Exception('Vpp config present') + self._rx_vrf_id = rx_vrf_id + self._server_vrf_id = server_vrf_id + self._dhcp_server = dhcp_server + self._dhcp_src_address = dhcp_src_address + + def add_vpp_config(self): + self._test.vapi.dhcp_proxy_config( + is_add=1, + rx_vrf_id=self._rx_vrf_id, + server_vrf_id=self._server_vrf_id, + dhcp_server=self._dhcp_server, + dhcp_src_address=self._dhcp_src_address) + self._test.registry.register(self, self._test.logger) + + def remove_vpp_config(self): + self._test.vapi.dhcp_proxy_config( + rx_vrf_id=self._rx_vrf_id, + server_vrf_id=self._server_vrf_id, + dhcp_server=self._dhcp_server, + dhcp_src_address=self._dhcp_src_address, + is_add=0) + + def get_vpp_dump(self): + dump = self._test.vapi.dhcp_proxy_dump() + for entry in dump: + if entry.rx_vrf_id == self._rx_vrf_id: + return entry + + def query_vpp_config(self): + dump = self.get_vpp_dump() + return True if dump else False + + def object_id(self): + return "dhcp-proxy-%d" % self._rx_vrf_id + + +class VppDHCPClient(VppObject): + + def __init__( + self, + test, + sw_if_index, + hostname, + id=None, + want_dhcp_event=False, + set_broadcast_flag=True, + dscp=None, + pid=None): + self._test = test + self._sw_if_index = sw_if_index + self._hostname = hostname + self._id = id + self._want_dhcp_event = want_dhcp_event + self._set_broadcast_flag = set_broadcast_flag + self._dscp = dscp + self._pid = pid + + def set_client( + self, + sw_if_index, + hostname, + id=None, + want_dhcp_event=False, + set_broadcast_flag=True, + dscp=None, + pid=None): + if self.query_vpp_config(): + raise Exception('Vpp config present') + self._sw_if_index = sw_if_index + self._hostname = hostname + self._id = id + self._want_dhcp_event = want_dhcp_event + self._set_broadcast_flag = set_broadcast_flag + self._dscp = dscp + self._pid = pid + + def add_vpp_config(self): + client = {'sw_if_index': self._sw_if_index, 'hostname': self._hostname, + 'id': self._id, 'want_dhcp_event': self._want_dhcp_event, + 'set_broadcast_flag': self._set_broadcast_flag, + 'dscp': self._dscp, 'pid': self._pid} + self._test.vapi.dhcp_client_config(is_add=1, client=client) + self._test.registry.register(self, self._test.logger) + + def remove_vpp_config(self): + client = client = { + 'sw_if_index': self._sw_if_index, + 'hostname': self._hostname} + self._test.vapi.dhcp_client_config(client=client, is_add=0) + + def get_vpp_dump(self): + dump = self._test.vapi.dhcp_client_dump() + for entry in dump: + if entry.client.sw_if_index == self._sw_if_index: + return entry + + def query_vpp_config(self): + dump = self.get_vpp_dump() + return True if dump else False + + def object_id(self): + return "dhcp-client-%s/%d" % (self._hostname, self._sw_if_index) diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 16abf45e3d9..4c1a85f58e6 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -51,7 +51,6 @@ #include <vnet/policer/policer.h> #include <vnet/policer/police.h> #include <vnet/mfib/mfib_types.h> -#include <vnet/dhcp/dhcp_proxy.h> #include <vnet/bonding/node.h> #include <vnet/qos/qos_types.h> #include <vnet/ethernet/ethernet_types_api.h> @@ -2666,33 +2665,6 @@ vl_api_ip_details_t_handler_json (vl_api_ip_details_t * mp) clib_net_to_host_u32 (mp->sw_if_index)); } -static void -vl_api_dhcp_compl_event_t_handler (vl_api_dhcp_compl_event_t * mp) -{ - u8 *s, i; - - s = format (0, "DHCP compl event: pid %d hostname %s host_addr %U " - "host_mac %U router_addr %U", - ntohl (mp->pid), mp->lease.hostname, - format_ip4_address, mp->lease.host_address, - format_ethernet_address, mp->lease.host_mac, - format_ip4_address, mp->lease.router_address); - - for (i = 0; i < mp->lease.count; i++) - s = - format (s, " domain_server_addr %U", format_ip4_address, - mp->lease.domain_server[i].address); - - errmsg ((char *) s); - vec_free (s); -} - -static void vl_api_dhcp_compl_event_t_handler_json - (vl_api_dhcp_compl_event_t * mp) -{ - /* JSON output not supported */ -} - static void vl_api_get_first_msg_id_reply_t_handler (vl_api_get_first_msg_id_reply_t * mp) { @@ -5108,9 +5080,6 @@ _(proxy_arp_intfc_enable_disable_reply) \ _(sw_interface_set_unnumbered_reply) \ _(ip_neighbor_add_del_reply) \ _(reset_fib_reply) \ -_(dhcp_proxy_config_reply) \ -_(dhcp_proxy_set_vss_reply) \ -_(dhcp_client_config_reply) \ _(set_ip_flow_hash_reply) \ _(sw_interface_ip6_enable_disable_reply) \ _(ip6nd_proxy_add_del_reply) \ @@ -5313,10 +5282,6 @@ _(IP_NEIGHBOR_ADD_DEL_REPLY, ip_neighbor_add_del_reply) \ _(CREATE_VLAN_SUBIF_REPLY, create_vlan_subif_reply) \ _(CREATE_SUBIF_REPLY, create_subif_reply) \ _(RESET_FIB_REPLY, reset_fib_reply) \ -_(DHCP_PROXY_CONFIG_REPLY, dhcp_proxy_config_reply) \ -_(DHCP_PROXY_SET_VSS_REPLY, dhcp_proxy_set_vss_reply) \ -_(DHCP_PROXY_DETAILS, dhcp_proxy_details) \ -_(DHCP_CLIENT_CONFIG_REPLY, dhcp_client_config_reply) \ _(SET_IP_FLOW_HASH_REPLY, set_ip_flow_hash_reply) \ _(SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY, \ sw_interface_ip6_enable_disable_reply) \ @@ -5392,7 +5357,6 @@ _(DELETE_LOOPBACK_REPLY, delete_loopback_reply) \ _(BD_IP_MAC_ADD_DEL_REPLY, bd_ip_mac_add_del_reply) \ _(BD_IP_MAC_FLUSH_REPLY, bd_ip_mac_flush_reply) \ _(BD_IP_MAC_DETAILS, bd_ip_mac_details) \ -_(DHCP_COMPL_EVENT, dhcp_compl_event) \ _(WANT_INTERFACE_EVENTS_REPLY, want_interface_events_reply) \ _(GET_FIRST_MSG_ID_REPLY, get_first_msg_id_reply) \ _(COP_INTERFACE_ENABLE_DISABLE_REPLY, cop_interface_enable_disable_reply) \ @@ -9279,358 +9243,6 @@ api_reset_fib (vat_main_t * vam) } static int -api_dhcp_proxy_config (vat_main_t * vam) -{ - unformat_input_t *i = vam->input; - vl_api_dhcp_proxy_config_t *mp; - u32 rx_vrf_id = 0; - u32 server_vrf_id = 0; - u8 is_add = 1; - u8 v4_address_set = 0; - u8 v6_address_set = 0; - ip4_address_t v4address; - ip6_address_t v6address; - u8 v4_src_address_set = 0; - u8 v6_src_address_set = 0; - ip4_address_t v4srcaddress; - ip6_address_t v6srcaddress; - int ret; - - /* Parse args required to build the message */ - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "del")) - is_add = 0; - else if (unformat (i, "rx_vrf_id %d", &rx_vrf_id)) - ; - else if (unformat (i, "server_vrf_id %d", &server_vrf_id)) - ; - else if (unformat (i, "svr %U", unformat_ip4_address, &v4address)) - v4_address_set = 1; - else if (unformat (i, "svr %U", unformat_ip6_address, &v6address)) - v6_address_set = 1; - else if (unformat (i, "src %U", unformat_ip4_address, &v4srcaddress)) - v4_src_address_set = 1; - else if (unformat (i, "src %U", unformat_ip6_address, &v6srcaddress)) - v6_src_address_set = 1; - else - break; - } - - if (v4_address_set && v6_address_set) - { - errmsg ("both v4 and v6 server addresses set"); - return -99; - } - if (!v4_address_set && !v6_address_set) - { - errmsg ("no server addresses set"); - return -99; - } - - if (v4_src_address_set && v6_src_address_set) - { - errmsg ("both v4 and v6 src addresses set"); - return -99; - } - if (!v4_src_address_set && !v6_src_address_set) - { - errmsg ("no src addresses set"); - return -99; - } - - if (!(v4_src_address_set && v4_address_set) && - !(v6_src_address_set && v6_address_set)) - { - errmsg ("no matching server and src addresses set"); - return -99; - } - - /* Construct the API message */ - M (DHCP_PROXY_CONFIG, mp); - - mp->is_add = is_add; - mp->rx_vrf_id = ntohl (rx_vrf_id); - mp->server_vrf_id = ntohl (server_vrf_id); - if (v6_address_set) - { - clib_memcpy (&mp->dhcp_server.un, &v6address, sizeof (v6address)); - clib_memcpy (&mp->dhcp_src_address.un, &v6srcaddress, - sizeof (v6address)); - } - else - { - clib_memcpy (&mp->dhcp_server.un, &v4address, sizeof (v4address)); - clib_memcpy (&mp->dhcp_src_address.un, &v4srcaddress, - sizeof (v4address)); - } - - /* send it... */ - S (mp); - - /* Wait for a reply, return good/bad news */ - W (ret); - return ret; -} - -#define vl_api_dhcp_proxy_details_t_endian vl_noop_handler -#define vl_api_dhcp_proxy_details_t_print vl_noop_handler - -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, Source Address %U, VSS Type %d, " - "VSS ASCII VPN-ID '%s', VSS RFC2685 VPN-ID (oui:id) %d:%d", - ntohl (mp->rx_vrf_id), - format_ip6_address, mp->dhcp_src_address, - mp->vss_type, mp->vss_vpn_ascii_id, - ntohl (mp->vss_oui), ntohl (mp->vss_fib_id)); - else - print (vam->ofp, - "RX Table-ID %d, Source Address %U, VSS Type %d, " - "VSS ASCII VPN-ID '%s', VSS RFC2685 VPN-ID (oui:id) %d:%d", - ntohl (mp->rx_vrf_id), - format_ip4_address, mp->dhcp_src_address, - mp->vss_type, mp->vss_vpn_ascii_id, - 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 - (vl_api_dhcp_proxy_details_t * mp) -{ - 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) - { - ASSERT (VAT_JSON_NONE == vam->json_tree.type); - vat_json_init_array (&vam->json_tree); - } - node = vat_json_array_add (&vam->json_tree); - - 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, "vss-type", ntohl (mp->vss_type)); - vat_json_object_add_string_copy (node, "vss-vpn-ascii-id", - mp->vss_vpn_ascii_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_src_address, sizeof (ip6)); - vat_json_object_add_ip6 (node, "src_address", ip6); - } - else - { - clib_memcpy (&ip4, &mp->dhcp_src_address, sizeof (ip4)); - vat_json_object_add_ip4 (node, "src_address", ip4); - } - - 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 -api_dhcp_proxy_dump (vat_main_t * vam) -{ - unformat_input_t *i = vam->input; - vl_api_control_ping_t *mp_ping; - vl_api_dhcp_proxy_dump_t *mp; - u8 is_ipv6 = 0; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "ipv6")) - is_ipv6 = 1; - else - { - clib_warning ("parse error '%U'", format_unformat_error, i); - return -99; - } - } - - M (DHCP_PROXY_DUMP, mp); - - mp->is_ip6 = is_ipv6; - S (mp); - - /* Use a control ping for synchronization */ - MPING (CONTROL_PING, mp_ping); - S (mp_ping); - - W (ret); - return ret; -} - -static int -api_dhcp_proxy_set_vss (vat_main_t * vam) -{ - unformat_input_t *i = vam->input; - vl_api_dhcp_proxy_set_vss_t *mp; - u8 is_ipv6 = 0; - u8 is_add = 1; - u32 tbl_id = ~0; - u8 vss_type = VSS_TYPE_DEFAULT; - u8 *vpn_ascii_id = 0; - u32 oui = 0; - u32 fib_id = 0; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "tbl_id %d", &tbl_id)) - ; - else if (unformat (i, "vpn_ascii_id %s", &vpn_ascii_id)) - vss_type = VSS_TYPE_ASCII; - else if (unformat (i, "fib_id %d", &fib_id)) - vss_type = VSS_TYPE_VPN_ID; - else if (unformat (i, "oui %d", &oui)) - vss_type = VSS_TYPE_VPN_ID; - else if (unformat (i, "ipv6")) - is_ipv6 = 1; - else if (unformat (i, "del")) - is_add = 0; - else - break; - } - - if (tbl_id == ~0) - { - errmsg ("missing tbl_id "); - vec_free (vpn_ascii_id); - return -99; - } - - if ((vpn_ascii_id) && (vec_len (vpn_ascii_id) > 128)) - { - errmsg ("vpn_ascii_id cannot be longer than 128 "); - vec_free (vpn_ascii_id); - return -99; - } - - M (DHCP_PROXY_SET_VSS, mp); - mp->tbl_id = ntohl (tbl_id); - mp->vss_type = vss_type; - if (vpn_ascii_id) - { - clib_memcpy (mp->vpn_ascii_id, vpn_ascii_id, vec_len (vpn_ascii_id)); - mp->vpn_ascii_id[vec_len (vpn_ascii_id)] = 0; - } - mp->vpn_index = ntohl (fib_id); - mp->oui = ntohl (oui); - mp->is_ipv6 = is_ipv6; - mp->is_add = is_add; - - S (mp); - W (ret); - - vec_free (vpn_ascii_id); - return ret; -} - -static int -api_dhcp_client_config (vat_main_t * vam) -{ - unformat_input_t *i = vam->input; - vl_api_dhcp_client_config_t *mp; - u32 sw_if_index; - u8 sw_if_index_set = 0; - u8 is_add = 1; - u8 *hostname = 0; - u8 disable_event = 0; - int ret; - - /* Parse args required to build the message */ - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "del")) - is_add = 0; - else - if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "sw_if_index %d", &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "hostname %s", &hostname)) - ; - else if (unformat (i, "disable_event")) - disable_event = 1; - else - break; - } - - if (sw_if_index_set == 0) - { - errmsg ("missing interface name or sw_if_index"); - return -99; - } - - if (vec_len (hostname) > 63) - { - errmsg ("hostname too long"); - } - vec_add1 (hostname, 0); - - /* Construct the API message */ - M (DHCP_CLIENT_CONFIG, mp); - - mp->is_add = is_add; - mp->client.sw_if_index = htonl (sw_if_index); - clib_memcpy (mp->client.hostname, hostname, vec_len (hostname)); - vec_free (hostname); - mp->client.want_dhcp_event = disable_event ? 0 : 1; - mp->client.pid = htonl (getpid ()); - - /* send it... */ - S (mp); - - /* Wait for a reply, return good/bad news */ - W (ret); - return ret; -} - -static int api_set_ip_flow_hash (vat_main_t * vam) { unformat_input_t *i = vam->input; @@ -21829,14 +21441,6 @@ _(create_subif, "<intfc> | sw_if_index <id> sub_id <n>\n" \ "[no_tags][one_tag][two_tags][dot1ad][exact_match][default_sub]\n" \ "[outer_vlan_id_any][inner_vlan_id_any]") \ _(reset_fib, "vrf <n> [ipv6]") \ -_(dhcp_proxy_config, \ - "svr <v46-address> src <v46-address>\n" \ - "rx_vrf_id <nn> server_vrf_id <nn> [del]") \ -_(dhcp_proxy_set_vss, \ - "tbl_id <n> [fib_id <n> oui <n> | vpn_ascii_id <text>] [ipv6] [del]") \ -_(dhcp_proxy_dump, "ip6") \ -_(dhcp_client_config, \ - "<intfc> | sw_if_index <id> [hostname <name>] [disable_event] [del]") \ _(set_ip_flow_hash, \ "vrf <n> [src] [dst] [sport] [dport] [proto] [reverse] [ipv6]") \ _(sw_interface_ip6_enable_disable, \ diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt index 6ce383350bf..b107365a105 100644 --- a/src/vnet/CMakeLists.txt +++ b/src/vnet/CMakeLists.txt @@ -891,54 +891,6 @@ list(APPEND VNET_HEADERS list(APPEND VNET_API_FILES lisp-gpe/lisp_gpe.api) ############################################################################## -# DHCP client -############################################################################## -list(APPEND VNET_SOURCES - dhcp/client.c - dhcp/dhcp_client_detect.c - dhcp/dhcp6_client_common_dp.c - dhcp/dhcp6_pd_client_dp.c - dhcp/dhcp6_pd_client_cp.c - dhcp/dhcp6_ia_na_client_dp.c - dhcp/dhcp6_ia_na_client_cp.c - dhcp/dhcp_api.c -) - -list(APPEND VNET_MULTIARCH_SOURCES - dhcp/dhcp_client_detect.c -) - -list(APPEND VNET_HEADERS - dhcp/client.h - dhcp/dhcp6_client_common_dp.h - dhcp/dhcp6_pd_client_dp.h - dhcp/dhcp6_ia_na_client_dp.h -) - -list(APPEND VNET_API_FILES - dhcp/dhcp.api - dhcp/dhcp6_pd_client_cp.api - dhcp/dhcp6_ia_na_client_cp.api -) - -############################################################################## -# DHCP proxy -############################################################################## -list(APPEND VNET_SOURCES - dhcp/dhcp6_proxy_node.c - dhcp/dhcp4_proxy_node.c - dhcp/dhcp_proxy.c -) - -list(APPEND VNET_HEADERS - dhcp/dhcp4_packet.h - dhcp/dhcp6_packet.h - dhcp/dhcp_proxy.h - dhcp/dhcp6_proxy_error.def - dhcp/dhcp4_proxy_error.def -) - -############################################################################## # ipv6 segment routing ############################################################################## diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c deleted file mode 100644 index 252f2df7d6b..00000000000 --- a/src/vnet/dhcp/dhcp_api.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - *------------------------------------------------------------------ - * dhcp_api.c - dhcp api - * - * Copyright (c) 2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - -#include <vnet/vnet.h> -#include <vlibmemory/api.h> - -#include <vnet/interface.h> -#include <vnet/api_errno.h> -#include <vnet/dhcp/dhcp_proxy.h> -#include <vnet/dhcp/client.h> -#include <vnet/dhcp/dhcp6_pd_client_dp.h> -#include <vnet/dhcp/dhcp6_ia_na_client_dp.h> -#include <vnet/dhcp/dhcp6_client_common_dp.h> -#include <vnet/fib/fib_table.h> -#include <vnet/ip/ip_types_api.h> - -#include <vnet/vnet_msg_enum.h> - -#define vl_typedefs /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_typedefs - -#define vl_endianfun /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) -#define vl_printfun -#include <vnet/vnet_all_api_h.h> -#undef vl_printfun - -#include <vlibapi/api_helper_macros.h> - -#define foreach_vpe_api_msg \ -_(DHCP_PROXY_CONFIG,dhcp_proxy_config) \ -_(DHCP_PROXY_DUMP,dhcp_proxy_dump) \ -_(DHCP_PROXY_SET_VSS,dhcp_proxy_set_vss) \ -_(DHCP_CLIENT_CONFIG, dhcp_client_config) \ -_(DHCP_CLIENT_DUMP, dhcp_client_dump) \ -_(WANT_DHCP6_PD_REPLY_EVENTS, want_dhcp6_pd_reply_events) \ -_(DHCP6_PD_SEND_CLIENT_MESSAGE, dhcp6_pd_send_client_message) \ -_(WANT_DHCP6_REPLY_EVENTS, want_dhcp6_reply_events) \ -_(DHCP6_SEND_CLIENT_MESSAGE, dhcp6_send_client_message) \ -_(DHCP6_CLIENTS_ENABLE_DISABLE, dhcp6_clients_enable_disable) \ -_(DHCP6_DUID_LL_SET, dhcp6_duid_ll_set) - - -static void -vl_api_dhcp_proxy_set_vss_t_handler (vl_api_dhcp_proxy_set_vss_t * mp) -{ - vl_api_dhcp_proxy_set_vss_reply_t *rmp; - u8 *vpn_ascii_id; - int rv; - - mp->vpn_ascii_id[sizeof (mp->vpn_ascii_id) - 1] = 0; - vpn_ascii_id = format (0, "%s", mp->vpn_ascii_id); - rv = - dhcp_proxy_set_vss ((mp->is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4), - ntohl (mp->tbl_id), ntohl (mp->vss_type), - vpn_ascii_id, ntohl (mp->oui), ntohl (mp->vpn_index), - mp->is_add == 0); - - REPLY_MACRO (VL_API_DHCP_PROXY_SET_VSS_REPLY); -} - - -static void vl_api_dhcp_proxy_config_t_handler - (vl_api_dhcp_proxy_config_t * mp) -{ - vl_api_dhcp_proxy_set_vss_reply_t *rmp; - ip46_address_t src, server; - int rv = -1; - - if (mp->dhcp_src_address.af != mp->dhcp_server.af) - { - rv = VNET_API_ERROR_INVALID_ARGUMENT; - goto reply; - } - - ip_address_decode (&mp->dhcp_src_address, &src); - ip_address_decode (&mp->dhcp_server, &server); - - if (mp->dhcp_src_address.af == ADDRESS_IP4) - { - rv = dhcp4_proxy_set_server (&server, - &src, - (u32) ntohl (mp->rx_vrf_id), - (u32) ntohl (mp->server_vrf_id), - (int) (mp->is_add == 0)); - } - else - { - rv = dhcp6_proxy_set_server (&server, - &src, - (u32) ntohl (mp->rx_vrf_id), - (u32) ntohl (mp->server_vrf_id), - (int) (mp->is_add == 0)); - } - -reply: - REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); -} - -static void -vl_api_dhcp_proxy_dump_t_handler (vl_api_dhcp_proxy_dump_t * mp) -{ - vl_api_registration_t *reg; - - reg = vl_api_client_index_to_registration (mp->client_index); - if (!reg) - return;; - - dhcp_proxy_dump ((mp->is_ip6 == 1 ? - FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4), reg, mp->context); -} - -void -dhcp_send_details (fib_protocol_t proto, - void *opaque, u32 context, dhcp_proxy_t * proxy) -{ - vl_api_dhcp_proxy_details_t *mp; - vl_api_registration_t *reg = opaque; - 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; - clib_memset (mp, 0, n); - mp->_vl_msg_id = ntohs (VL_API_DHCP_PROXY_DETAILS); - mp->context = context; - 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 (vss) - { - mp->vss_type = ntohl (vss->vss_type); - if (vss->vss_type == VSS_TYPE_ASCII) - { - u32 id_len = vec_len (vss->vpn_ascii_id); - clib_memcpy (mp->vss_vpn_ascii_id, vss->vpn_ascii_id, id_len); - } - else if (vss->vss_type == VSS_TYPE_VPN_ID) - { - u32 oui = ((u32) vss->vpn_id[0] << 16) + ((u32) vss->vpn_id[1] << 8) - + ((u32) vss->vpn_id[2]); - u32 fib_id = ((u32) vss->vpn_id[3] << 24) + - ((u32) vss->vpn_id[4] << 16) + ((u32) vss->vpn_id[5] << 8) + - ((u32) vss->vpn_id[6]); - mp->vss_oui = htonl (oui); - mp->vss_fib_id = htonl (fib_id); - } - } - else - mp->vss_type = VSS_TYPE_INVALID; - - 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.un, &server->dhcp_server.ip6, 16); - } - else - { - /* put the address in the first bytes */ - memcpy (&v_server->dhcp_server.un, &server->dhcp_server.ip4, 4); - } - } - - if (mp->is_ipv6) - { - memcpy (&mp->dhcp_src_address.un, &proxy->dhcp_src_address.ip6, 16); - } - else - { - /* put the address in the first bytes */ - memcpy (&mp->dhcp_src_address.un, &proxy->dhcp_src_address.ip4, 4); - } - vl_api_send_msg (reg, (u8 *) mp); -} - -static void -dhcp_client_lease_encode (vl_api_dhcp_lease_t * lease, - const dhcp_client_t * client) -{ - size_t len; - u8 i; - - lease->is_ipv6 = 0; // only support IPv6 clients - lease->sw_if_index = ntohl (client->sw_if_index); - lease->state = ntohl (client->state); - len = clib_min (sizeof (lease->hostname) - 1, vec_len (client->hostname)); - clib_memcpy (&lease->hostname, client->hostname, len); - lease->hostname[len] = 0; - - lease->mask_width = client->subnet_mask_width; - clib_memcpy (&lease->host_address.un, (u8 *) & client->leased_address, - sizeof (ip4_address_t)); - clib_memcpy (&lease->router_address.un, (u8 *) & client->router_address, - sizeof (ip4_address_t)); - - lease->count = vec_len (client->domain_server_address); - for (i = 0; i < lease->count; i++) - clib_memcpy (&lease->domain_server[i].address, - (u8 *) & client->domain_server_address[i], - sizeof (ip4_address_t)); - - clib_memcpy (&lease->host_mac[0], client->client_hardware_address, 6); -} - -static void -dhcp_client_data_encode (vl_api_dhcp_client_t * vclient, - const dhcp_client_t * client) -{ - size_t len; - - vclient->sw_if_index = ntohl (client->sw_if_index); - len = clib_min (sizeof (vclient->hostname) - 1, vec_len (client->hostname)); - clib_memcpy (&vclient->hostname, client->hostname, len); - vclient->hostname[len] = 0; - - len = clib_min (sizeof (vclient->id) - 1, - vec_len (client->client_identifier)); - clib_memcpy (&vclient->id, client->client_identifier, len); - vclient->id[len] = 0; - - if (NULL != client->event_callback) - vclient->want_dhcp_event = 1; - else - vclient->want_dhcp_event = 0; - vclient->set_broadcast_flag = client->set_broadcast_flag; - vclient->dscp = ip_dscp_encode (client->dscp); - vclient->pid = client->pid; -} - -static void -dhcp_compl_event_callback (u32 client_index, const dhcp_client_t * client) -{ - vl_api_registration_t *reg; - vl_api_dhcp_compl_event_t *mp; - - reg = vl_api_client_index_to_registration (client_index); - if (!reg) - return; - - mp = vl_msg_api_alloc (sizeof (*mp)); - mp->client_index = client_index; - mp->pid = client->pid; - dhcp_client_lease_encode (&mp->lease, client); - - mp->_vl_msg_id = ntohs (VL_API_DHCP_COMPL_EVENT); - - vl_api_send_msg (reg, (u8 *) mp); -} - -static void vl_api_dhcp_client_config_t_handler - (vl_api_dhcp_client_config_t * mp) -{ - vlib_main_t *vm = vlib_get_main (); - vl_api_dhcp_client_config_reply_t *rmp; - u32 sw_if_index; - ip_dscp_t dscp; - int rv = 0; - - VALIDATE_SW_IF_INDEX (&(mp->client)); - - sw_if_index = ntohl (mp->client.sw_if_index); - dscp = ip_dscp_decode (mp->client.dscp); - - rv = dhcp_client_config (mp->is_add, - mp->client_index, - vm, - sw_if_index, - mp->client.hostname, - mp->client.id, - (mp->client.want_dhcp_event ? - dhcp_compl_event_callback : - NULL), - mp->client.set_broadcast_flag, - dscp, mp->client.pid); - - BAD_SW_IF_INDEX_LABEL; - REPLY_MACRO (VL_API_DHCP_CLIENT_CONFIG_REPLY); -} - -typedef struct dhcp_client_send_walk_ctx_t_ -{ - vl_api_registration_t *reg; - u32 context; -} dhcp_client_send_walk_ctx_t; - -static int -send_dhcp_client_entry (const dhcp_client_t * client, void *arg) -{ - dhcp_client_send_walk_ctx_t *ctx; - vl_api_dhcp_client_details_t *mp; - - ctx = arg; - - mp = vl_msg_api_alloc (sizeof (*mp)); - clib_memset (mp, 0, sizeof (*mp)); - - mp->_vl_msg_id = ntohs (VL_API_DHCP_CLIENT_DETAILS); - mp->context = ctx->context; - - dhcp_client_data_encode (&mp->client, client); - dhcp_client_lease_encode (&mp->lease, client); - - vl_api_send_msg (ctx->reg, (u8 *) mp); - - return (1); -} - -static void -vl_api_dhcp_client_dump_t_handler (vl_api_dhcp_client_dump_t * mp) -{ - vl_api_registration_t *reg; - - reg = vl_api_client_index_to_registration (mp->client_index); - if (!reg) - return; - - dhcp_client_send_walk_ctx_t ctx = { - .reg = reg, - .context = mp->context, - }; - dhcp_client_walk (send_dhcp_client_entry, &ctx); -} - -/* - * dhcp_api_hookup - * Add vpe's API message handlers to the table. - * vlib has already mapped shared memory and - * added the client registration handlers. - * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process() - */ -#define vl_msg_name_crc_list -#include <vnet/vnet_all_api_h.h> -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (api_main_t * am) -{ -#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id); - foreach_vl_msg_name_crc_dhcp; -#undef _ -} - -static clib_error_t * -dhcp_api_hookup (vlib_main_t * vm) -{ - api_main_t *am = &api_main; - -#define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N, #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_api_##n##_t_endian, \ - vl_api_##n##_t_print, \ - sizeof(vl_api_##n##_t), 1); - foreach_vpe_api_msg; -#undef _ - - /* - * Set up the (msg_name, crc, message-id) table - */ - setup_message_id_table (am); - - dhcp6_pd_set_publisher_node (dhcp6_pd_reply_process_node.index, - DHCP6_PD_DP_REPLY_REPORT); - dhcp6_set_publisher_node (dhcp6_reply_process_node.index, - DHCP6_DP_REPLY_REPORT); - - return 0; -} - -VLIB_API_INIT_FUNCTION (dhcp_api_hookup); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vnet/vnet_all_api_h.h b/src/vnet/vnet_all_api_h.h index 3b5140e1ed2..519f5219042 100644 --- a/src/vnet/vnet_all_api_h.h +++ b/src/vnet/vnet_all_api_h.h @@ -60,7 +60,6 @@ #include <vnet/srmpls/sr_mpls.api.h> #include <vnet/classify/classify.api.h> #include <vnet/ipfix-export/ipfix_export.api.h> -#include <vnet/dhcp/dhcp.api.h> #include <vnet/cop/cop.api.h> #include <vnet/policer/policer.api.h> #include <vnet/ethernet/p2p_ethernet.api.h> @@ -71,8 +70,6 @@ #include <vnet/pg/pg.api.h> #include <vnet/feature/feature.api.h> #include <vnet/qos/qos.api.h> -#include <vnet/dhcp/dhcp6_pd_client_cp.api.h> -#include <vnet/dhcp/dhcp6_ia_na_client_cp.api.h> #include <vnet/devices/pipe/pipe.api.h> #include <vnet/vxlan-gbp/vxlan_gbp.api.h> #include <vnet/syslog/syslog.api.h> diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index 0d342a5b420..3c6eada0a05 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -24,7 +24,6 @@ #include <vnet/fib/fib_api.h> #include <vnet/unix/tuntap.h> #include <vnet/mpls/mpls.h> -#include <vnet/dhcp/dhcp_proxy.h> #include <vnet/l2tp/l2tp.h> #include <vnet/l2/l2_input.h> #include <vnet/srv6/sr.h> @@ -1037,75 +1036,6 @@ vl_api_reset_fib_t_print (vl_api_reset_fib_t * mp, void *handle) FINISH; } -static void *vl_api_dhcp_proxy_config_t_print - (vl_api_dhcp_proxy_config_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: dhcp_proxy_config_2 "); - - s = format (s, "rx_vrf_id %d ", (mp->rx_vrf_id)); - s = format (s, "server_vrf_id %d ", (mp->server_vrf_id)); - - s = format (s, "svr %U ", format_ip46_address, - (ip46_address_t *) & mp->dhcp_server.un); - s = format (s, "src %U ", format_ip46_address, - (ip46_address_t *) & mp->dhcp_src_address.un); - - if (mp->is_add == 0) - s = format (s, "del "); - - FINISH; -} - -static void *vl_api_dhcp_proxy_set_vss_t_print - (vl_api_dhcp_proxy_set_vss_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: dhcp_proxy_set_vss "); - - s = format (s, "tbl_id %d ", (mp->tbl_id)); - - if (mp->vss_type == VSS_TYPE_VPN_ID) - { - s = format (s, "fib_id %d ", (mp->vpn_index)); - s = format (s, "oui %d ", (mp->oui)); - } - else if (mp->vss_type == VSS_TYPE_ASCII) - s = format (s, "vpn_ascii_id %s", mp->vpn_ascii_id); - - if (mp->is_ipv6 != 0) - s = format (s, "ipv6 "); - - if (mp->is_add == 0) - s = format (s, "del "); - - FINISH; -} - -static void *vl_api_dhcp_client_config_t_print - (vl_api_dhcp_client_config_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: dhcp_client_config "); - - s = format (s, "sw_if_index %d ", (mp->client.sw_if_index)); - - s = format (s, "hostname %s ", mp->client.hostname); - - s = format (s, "want_dhcp_event %d ", mp->client.want_dhcp_event); - - s = format (s, "pid %d ", (mp->client.pid)); - - if (mp->is_add == 0) - s = format (s, "del "); - - FINISH; -} - - static void *vl_api_set_ip_flow_hash_t_print (vl_api_set_ip_flow_hash_t * mp, void *handle) { @@ -3786,8 +3716,6 @@ _(IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del) \ _(CREATE_VLAN_SUBIF, create_vlan_subif) \ _(CREATE_SUBIF, create_subif) \ _(RESET_FIB, reset_fib) \ -_(DHCP_PROXY_CONFIG, dhcp_proxy_config) \ -_(DHCP_PROXY_SET_VSS, dhcp_proxy_set_vss) \ _(SET_IP_FLOW_HASH, set_ip_flow_hash) \ _(SW_INTERFACE_IP6ND_RA_PREFIX, sw_interface_ip6nd_ra_prefix) \ _(SW_INTERFACE_IP6ND_RA_CONFIG, sw_interface_ip6nd_ra_config) \ @@ -3814,7 +3742,6 @@ _(BRIDGE_DOMAIN_SET_MAC_AGE, bridge_domain_set_mac_age) \ _(CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table) \ _(CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables) \ _(ADD_NODE_NEXT, add_node_next) \ -_(DHCP_CLIENT_CONFIG, dhcp_client_config) \ _(L2TPV3_CREATE_TUNNEL, l2tpv3_create_tunnel) \ _(L2TPV3_SET_TUNNEL_COOKIES, l2tpv3_set_tunnel_cookies) \ _(L2TPV3_INTERFACE_ENABLE_DISABLE, l2tpv3_interface_enable_disable) \ |