From c8d8770a3e09c300eeff461a11ef3723b8e029cb Mon Sep 17 00:00:00 2001 From: Pavel Kotucek Date: Wed, 25 Jan 2017 07:25:32 +0100 Subject: API refactoring : dhcp Change-Id: I3829835ed2126e51e96690c907deac623dc77151 Signed-off-by: Pavel Kotucek --- src/vnet/dhcp/dhcp_api.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 src/vnet/dhcp/dhcp_api.c (limited to 'src/vnet/dhcp/dhcp_api.c') diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c new file mode 100644 index 00000000..88b32b24 --- /dev/null +++ b/src/vnet/dhcp/dhcp_api.c @@ -0,0 +1,253 @@ +/* + *------------------------------------------------------------------ + * 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 +#include + +#include +#include +#include +#include +#include + +#include + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun /* define message structures */ +#include +#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 +#undef vl_printfun + +#include + +#define foreach_vpe_api_msg \ +_(DHCP_PROXY_CONFIG,dhcp_proxy_config) \ +_(DHCP_PROXY_CONFIG_2,dhcp_proxy_config_2) \ +_(DHCP_PROXY_SET_VSS,dhcp_proxy_set_vss) \ +_(DHCP_CLIENT_CONFIG, dhcp_client_config) + +static void +dhcpv4_proxy_config (vl_api_dhcp_proxy_config_t * mp) +{ + vl_api_dhcp_proxy_config_reply_t *rmp; + int rv; + + rv = dhcp_proxy_set_server ((ip4_address_t *) (&mp->dhcp_server), + (ip4_address_t *) (&mp->dhcp_src_address), + (u32) ntohl (mp->vrf_id), + (int) mp->insert_circuit_id, + (int) (mp->is_add == 0)); + + REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); +} + + +static void +dhcpv6_proxy_config (vl_api_dhcp_proxy_config_t * mp) +{ + vl_api_dhcp_proxy_config_reply_t *rmp; + int rv = -1; + + rv = dhcpv6_proxy_set_server ((ip6_address_t *) (&mp->dhcp_server), + (ip6_address_t *) (&mp->dhcp_src_address), + (u32) ntohl (mp->vrf_id), + (int) mp->insert_circuit_id, + (int) (mp->is_add == 0)); + + REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); +} + +static void +dhcpv4_proxy_config_2 (vl_api_dhcp_proxy_config_2_t * mp) +{ + vl_api_dhcp_proxy_config_reply_t *rmp; + int rv; + + rv = dhcp_proxy_set_server_2 ((ip4_address_t *) (&mp->dhcp_server), + (ip4_address_t *) (&mp->dhcp_src_address), + (u32) ntohl (mp->rx_vrf_id), + (u32) ntohl (mp->server_vrf_id), + (int) mp->insert_circuit_id, + (int) (mp->is_add == 0)); + + REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_2_REPLY); +} + + +static void +dhcpv6_proxy_config_2 (vl_api_dhcp_proxy_config_2_t * mp) +{ + vl_api_dhcp_proxy_config_reply_t *rmp; + int rv = -1; + + rv = dhcpv6_proxy_set_server_2 ((ip6_address_t *) (&mp->dhcp_server), + (ip6_address_t *) (&mp->dhcp_src_address), + (u32) ntohl (mp->rx_vrf_id), + (u32) ntohl (mp->server_vrf_id), + (int) mp->insert_circuit_id, + (int) (mp->is_add == 0)); + + REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_2_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; + int rv; + if (!mp->is_ipv6) + rv = dhcp_proxy_set_option82_vss (ntohl (mp->tbl_id), + ntohl (mp->oui), + ntohl (mp->fib_id), + (int) mp->is_add == 0); + else + rv = dhcpv6_proxy_set_vss (ntohl (mp->tbl_id), + ntohl (mp->oui), + ntohl (mp->fib_id), (int) 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) +{ + if (mp->is_ipv6 == 0) + dhcpv4_proxy_config (mp); + else + dhcpv6_proxy_config (mp); +} + +void +dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, + u8 is_ipv6, u8 * host_address, u8 * router_address, + u8 * host_mac) +{ + unix_shared_memory_queue_t *q; + vl_api_dhcp_compl_event_t *mp; + + q = vl_api_client_index_to_input_queue (client_index); + if (!q) + return; + + mp = vl_msg_api_alloc (sizeof (*mp)); + mp->client_index = client_index; + mp->pid = pid; + mp->is_ipv6 = is_ipv6; + clib_memcpy (&mp->hostname, hostname, vec_len (hostname)); + mp->hostname[vec_len (hostname) + 1] = '\n'; + clib_memcpy (&mp->host_address[0], host_address, 16); + clib_memcpy (&mp->router_address[0], router_address, 16); + + if (NULL != host_mac) + clib_memcpy (&mp->host_mac[0], host_mac, 6); + + mp->_vl_msg_id = ntohs (VL_API_DHCP_COMPL_EVENT); + + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + +static void vl_api_dhcp_proxy_config_2_t_handler + (vl_api_dhcp_proxy_config_2_t * mp) +{ + if (mp->is_ipv6 == 0) + dhcpv4_proxy_config_2 (mp); + else + dhcpv6_proxy_config_2 (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; + int rv = 0; + + VALIDATE_SW_IF_INDEX (mp); + + rv = dhcp_client_config (vm, ntohl (mp->sw_if_index), + mp->hostname, mp->is_add, mp->client_index, + mp->want_dhcp_event ? dhcp_compl_event_callback : + NULL, mp->pid); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_DHCP_CLIENT_CONFIG_REPLY); +} + +/* + * dhcp_api_hookup + * Add vpe's API message handlers to the table. + * vlib has alread 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 +#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); + + return 0; +} + +VLIB_API_INIT_FUNCTION (dhcp_api_hookup); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg From 20a175a18414c67e38b5ce0709b33fb1df8069c9 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 14 Feb 2017 07:28:41 -0800 Subject: dhcp: multiple additions DHCP additions: 1) DHCPv4 will only relay a message back to the client, if the Option82 information is present. So make this the default. 2) It is no longer possible to select via the API to "insert circuit ID" - since this is now default 3) Remove the version 2 API since it's now the same as version 1. 4) Adding the VSS option is now conditional only on the presence of VSS config (not the 'insert' option in the set API) 5) DHCP proxy dump via API Change-Id: Ia7271ba8c1d4dbf34a02c401d268ccfbb1b74f17 Signed-off-by: Neale Ranns --- src/scripts/vnet/dhcp/proxy | 21 ++ src/vat/api_format.c | 173 ++++++----- src/vnet/dhcp/client.c | 1 + src/vnet/dhcp/client.h | 3 + src/vnet/dhcp/dhcp.api | 67 ++--- src/vnet/dhcp/dhcp_api.c | 112 ++++--- src/vnet/dhcp/proxy.h | 33 ++- src/vnet/dhcp/proxy_error.def | 3 +- src/vnet/dhcp/proxy_node.c | 676 +++++++++++++++++++++++------------------- src/vnet/dhcpv6/proxy.h | 19 +- src/vnet/dhcpv6/proxy_node.c | 513 ++++++++++++++++++-------------- src/vnet/dpo/receive_dpo.c | 5 + src/vpp/api/custom_dump.c | 34 --- test/test_dhcp.py | 166 ++++++----- test/vpp_papi_provider.py | 6 +- 15 files changed, 978 insertions(+), 854 deletions(-) create mode 100644 src/scripts/vnet/dhcp/proxy (limited to 'src/vnet/dhcp/dhcp_api.c') diff --git a/src/scripts/vnet/dhcp/proxy b/src/scripts/vnet/dhcp/proxy new file mode 100644 index 00000000..c709d87d --- /dev/null +++ b/src/scripts/vnet/dhcp/proxy @@ -0,0 +1,21 @@ +loop create +loop create + +set int state loop0 up +set int state loop1 up + +set int ip table loop1 1 +set int ip6 table loop1 1 + +set int ip addr loop0 10.0.0.1/24 +set int ip addr loop0 10.0.1.1/24 + +set int ip addr loop0 2001::1/64 +set int ip addr loop0 2001:1::1/64 + +set dhcp proxy server 10.255.0.1 src-address 10.0.0.1 server-fib-id 0 rx-fib-id 0 +set dhcp proxy server 10.255.0.2 src-address 10.0.1.1 server-fib-id 1 rx-fib-id 1 + +set dhcpv6 proxy server 3001::1 src-address 2001::1 server-fib-id 0 rx-fib-id 0 +set dhcpv6 proxy server 3002::1 src-address 2001:1::1 server-fib-id 1 rx-fib-id 1 + diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 11e68214..78c5e279 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -3819,7 +3819,6 @@ _(reset_vrf_reply) \ _(oam_add_del_reply) \ _(reset_fib_reply) \ _(dhcp_proxy_config_reply) \ -_(dhcp_proxy_config_2_reply) \ _(dhcp_proxy_set_vss_reply) \ _(dhcp_client_config_reply) \ _(set_ip_flow_hash_reply) \ @@ -4033,8 +4032,8 @@ _(CREATE_SUBIF_REPLY, create_subif_reply) \ _(OAM_ADD_DEL_REPLY, oam_add_del_reply) \ _(RESET_FIB_REPLY, reset_fib_reply) \ _(DHCP_PROXY_CONFIG_REPLY, dhcp_proxy_config_reply) \ -_(DHCP_PROXY_CONFIG_2_REPLY, dhcp_proxy_config_2_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, \ @@ -7635,9 +7634,9 @@ api_dhcp_proxy_config (vat_main_t * vam) { unformat_input_t *i = vam->input; vl_api_dhcp_proxy_config_t *mp; - u32 vrf_id = 0; + u32 rx_vrf_id = 0; + u32 server_vrf_id = 0; u8 is_add = 1; - u8 insert_cid = 1; u8 v4_address_set = 0; u8 v6_address_set = 0; ip4_address_t v4address; @@ -7653,9 +7652,9 @@ api_dhcp_proxy_config (vat_main_t * vam) { if (unformat (i, "del")) is_add = 0; - else if (unformat (i, "vrf %d", &vrf_id)) + else if (unformat (i, "rx_vrf_id %d", &rx_vrf_id)) ; - else if (unformat (i, "insert-cid %d", &insert_cid)) + 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; @@ -7701,9 +7700,9 @@ api_dhcp_proxy_config (vat_main_t * vam) /* Construct the API message */ M (DHCP_PROXY_CONFIG, mp); - mp->insert_circuit_id = insert_cid; mp->is_add = is_add; - mp->vrf_id = ntohl (vrf_id); + mp->rx_vrf_id = ntohl (rx_vrf_id); + mp->server_vrf_id = ntohl (server_vrf_id); if (v6_address_set) { mp->is_ipv6 = 1; @@ -7724,100 +7723,98 @@ api_dhcp_proxy_config (vat_main_t * vam) return ret; } -static int -api_dhcp_proxy_config_2 (vat_main_t * vam) +#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) { - unformat_input_t *i = vam->input; - vl_api_dhcp_proxy_config_2_t *mp; - u32 rx_vrf_id = 0; - u32 server_vrf_id = 0; - u8 is_add = 1; - u8 insert_cid = 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; + vat_main_t *vam = &vat_main; - /* 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, "insert-cid %d", &insert_cid)) - ; - 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 (mp->is_ipv6) + print (vam->ofp, + "RX Table-ID %d, Server Table-ID %d, Server Address %U, Source Address %U, VSS FIB-ID %d, VSS OUI %d", + ntohl (mp->rx_vrf_id), + ntohl (mp->server_vrf_id), + format_ip6_address, mp->dhcp_server, + format_ip6_address, mp->dhcp_src_address, + ntohl (mp->vss_oui), ntohl (mp->vss_fib_id)); + else + print (vam->ofp, + "RX Table-ID %d, Server Table-ID %d, Server Address %U, Source Address %U, VSS FIB-ID %d, VSS OUI %d", + ntohl (mp->rx_vrf_id), + ntohl (mp->server_vrf_id), + format_ip4_address, mp->dhcp_server, + format_ip4_address, mp->dhcp_src_address, + ntohl (mp->vss_oui), ntohl (mp->vss_fib_id)); +} - 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; - } +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; + struct in_addr ip4; + struct in6_addr ip6; - if (v4_src_address_set && v6_src_address_set) + if (VAT_JSON_ARRAY != vam->json_tree.type) { - errmsg ("both v4 and v6 src addresses set"); - return -99; + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); } - if (!v4_src_address_set && !v6_src_address_set) + 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, "server-table-id", + ntohl (mp->server_vrf_id)); + if (mp->is_ipv6) { - errmsg ("no src addresses set"); - return -99; + clib_memcpy (&ip6, &mp->dhcp_server, sizeof (ip6)); + vat_json_object_add_ip6 (node, "server_address", ip6); + clib_memcpy (&ip6, &mp->dhcp_src_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "src_address", ip6); } - - if (!(v4_src_address_set && v4_address_set) && - !(v6_src_address_set && v6_address_set)) + else { - errmsg ("no matching server and src addresses set"); - return -99; + clib_memcpy (&ip4, &mp->dhcp_server, sizeof (ip4)); + vat_json_object_add_ip4 (node, "server_address", ip4); + clib_memcpy (&ip4, &mp->dhcp_src_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "src_address", ip4); } + vat_json_object_add_uint (node, "vss-fib-id", ntohl (mp->vss_fib_id)); + vat_json_object_add_uint (node, "vss-oui", ntohl (mp->vss_oui)); +} - /* Construct the API message */ - M (DHCP_PROXY_CONFIG_2, mp); +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; - mp->insert_circuit_id = insert_cid; - 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) - { - mp->is_ipv6 = 1; - clib_memcpy (mp->dhcp_server, &v6address, sizeof (v6address)); - clib_memcpy (mp->dhcp_src_address, &v6srcaddress, sizeof (v6address)); - } - else + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { - clib_memcpy (mp->dhcp_server, &v4address, sizeof (v4address)); - clib_memcpy (mp->dhcp_src_address, &v4srcaddress, sizeof (v4address)); + if (unformat (i, "ipv6")) + is_ipv6 = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } } - /* send it... */ + M (DHCP_PROXY_DUMP, mp); + + mp->is_ip6 = is_ipv6; S (mp); - /* Wait for a reply, return good/bad news */ + /* Use a control ping for synchronization */ + M (CONTROL_PING, mp_ping); + S (mp_ping); + W (ret); return ret; } @@ -18187,12 +18184,10 @@ _(oam_add_del, "src dst [vrf ] [del]") \ _(reset_fib, "vrf [ipv6]") \ _(dhcp_proxy_config, \ "svr src \n" \ - "insert-cid [del]") \ -_(dhcp_proxy_config_2, \ - "svr src \n" \ - "rx_vrf_id server_vrf_id insert-cid [del]") \ + "rx_vrf_id server_vrf_id [del]") \ _(dhcp_proxy_set_vss, \ "tbl_id fib_id oui [ipv6] [del]") \ +_(dhcp_proxy_dump, "ip6") \ _(dhcp_client_config, \ " | sw_if_index [hostname ] [disable_event] [del]") \ _(set_ip_flow_hash, \ diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index c352e310..8a1a43b3 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -13,6 +13,7 @@ * limitations under the License. */ #include +#include #include #include diff --git a/src/vnet/dhcp/client.h b/src/vnet/dhcp/client.h index d15e686b..a74368cb 100644 --- a/src/vnet/dhcp/client.h +++ b/src/vnet/dhcp/client.h @@ -19,6 +19,9 @@ #ifndef included_dhcp_client_h #define included_dhcp_client_h +#include +#include + #define foreach_dhcp_client_state \ _(DHCP_DISCOVER) \ _(DHCP_REQUEST) \ diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api index c228cd04..8daadd8c 100644 --- a/src/vnet/dhcp/dhcp.api +++ b/src/vnet/dhcp/dhcp.api @@ -16,7 +16,8 @@ /** \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 - @param vrf_id - vrf id + @param rx_vrf_id - Rx/interface vrf id + @param server_vrf_id - server vrf id @param if_ipv6 - ipv6 if non-zero, else ipv4 @param is_add - add the config if non-zero, else delete @param insert_circuit_id - option82 suboption 1 fib number @@ -27,10 +28,10 @@ define dhcp_proxy_config { u32 client_index; u32 context; - u32 vrf_id; + u32 rx_vrf_id; + u32 server_vrf_id; u8 is_ipv6; u8 is_add; - u8 insert_circuit_id; u8 dhcp_server[16]; u8 dhcp_src_address[16]; }; @@ -45,40 +46,6 @@ define dhcp_proxy_config_reply i32 retval; }; -/** \brief DHCP Proxy config 2 add / del request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param rx_vrf_id - receive vrf id - @param server_vrf_id - server vrf id - @param if_ipv6 - ipv6 if non-zero, else ipv4 - @param is_add - add the config if non-zero, else delete - @param insert_circuit_id - option82 suboption 1 fib number - @param dhcp_server[] - server address - @param dhcp_src_address[] - -*/ -define dhcp_proxy_config_2 -{ - u32 client_index; - u32 context; - u32 rx_vrf_id; - u32 server_vrf_id; - u8 is_ipv6; - u8 is_add; - u8 insert_circuit_id; - u8 dhcp_server[16]; - u8 dhcp_src_address[16]; -}; - -/** \brief DHCP Proxy config 2 add / del response - @param context - sender context, to match reply w/ request - @param retval - return code for request -*/ -define dhcp_proxy_config_2_reply -{ - u32 context; - i32 retval; -}; - /** \brief DHCP Proxy set / unset vss request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -159,6 +126,32 @@ define dhcp_compl_event u8 host_mac[6]; }; +/** \brief Dump DHCP proxy table + @param client_index - opaque cookie to identify the sender + @param True for IPv6 proxy table +*/ +define dhcp_proxy_dump +{ + u32 client_index; + u32 context; + u8 is_ip6; +}; + +/** \brief Tell client about a DHCP completion event + @param client_index - opaque cookie to identify the sender +*/ +define dhcp_proxy_details +{ + u32 context; + u32 rx_vrf_id; + u32 server_vrf_id; + u32 vss_oui; + u32 vss_fib_id; + u8 is_ipv6; + u8 dhcp_server[16]; + u8 dhcp_src_address[16]; +}; + /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index 88b32b24..ce9039b7 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -46,7 +46,8 @@ #define foreach_vpe_api_msg \ _(DHCP_PROXY_CONFIG,dhcp_proxy_config) \ -_(DHCP_PROXY_CONFIG_2,dhcp_proxy_config_2) \ +_(DHCP_PROXY_DUMP,dhcp_proxy_dump) \ +_(DHCP_PROXY_DETAILS,dhcp_proxy_details) \ _(DHCP_PROXY_SET_VSS,dhcp_proxy_set_vss) \ _(DHCP_CLIENT_CONFIG, dhcp_client_config) @@ -58,8 +59,8 @@ dhcpv4_proxy_config (vl_api_dhcp_proxy_config_t * mp) rv = dhcp_proxy_set_server ((ip4_address_t *) (&mp->dhcp_server), (ip4_address_t *) (&mp->dhcp_src_address), - (u32) ntohl (mp->vrf_id), - (int) mp->insert_circuit_id, + (u32) ntohl (mp->rx_vrf_id), + (u32) ntohl (mp->server_vrf_id), (int) (mp->is_add == 0)); REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); @@ -74,44 +75,11 @@ dhcpv6_proxy_config (vl_api_dhcp_proxy_config_t * mp) rv = dhcpv6_proxy_set_server ((ip6_address_t *) (&mp->dhcp_server), (ip6_address_t *) (&mp->dhcp_src_address), - (u32) ntohl (mp->vrf_id), - (int) mp->insert_circuit_id, - (int) (mp->is_add == 0)); - - REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); -} - -static void -dhcpv4_proxy_config_2 (vl_api_dhcp_proxy_config_2_t * mp) -{ - vl_api_dhcp_proxy_config_reply_t *rmp; - int rv; - - rv = dhcp_proxy_set_server_2 ((ip4_address_t *) (&mp->dhcp_server), - (ip4_address_t *) (&mp->dhcp_src_address), (u32) ntohl (mp->rx_vrf_id), (u32) ntohl (mp->server_vrf_id), - (int) mp->insert_circuit_id, (int) (mp->is_add == 0)); - REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_2_REPLY); -} - - -static void -dhcpv6_proxy_config_2 (vl_api_dhcp_proxy_config_2_t * mp) -{ - vl_api_dhcp_proxy_config_reply_t *rmp; - int rv = -1; - - rv = dhcpv6_proxy_set_server_2 ((ip6_address_t *) (&mp->dhcp_server), - (ip6_address_t *) (&mp->dhcp_src_address), - (u32) ntohl (mp->rx_vrf_id), - (u32) ntohl (mp->server_vrf_id), - (int) mp->insert_circuit_id, - (int) (mp->is_add == 0)); - - REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_2_REPLY); + REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); } @@ -143,6 +111,67 @@ static void vl_api_dhcp_proxy_config_t_handler dhcpv6_proxy_config (mp); } +static void +vl_api_dhcp_proxy_dump_t_handler (vl_api_dhcp_proxy_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + if (mp->is_ip6 == 0) + dhcp_proxy_dump (q, mp->context); + else + dhcpv6_proxy_dump (q, mp->context); +} + +void +dhcp_send_details (void *opaque, + u32 context, + const ip46_address_t * server, + const ip46_address_t * src, + u32 server_fib_id, + u32 rx_fib_id, u32 vss_fib_id, u32 vss_oui) +{ + vl_api_dhcp_proxy_details_t *mp; + unix_shared_memory_queue_t *q = opaque; + + mp = vl_msg_api_alloc (sizeof (*mp)); + if (!mp) + return; + memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_DHCP_PROXY_DETAILS); + mp->context = context; + + mp->rx_vrf_id = htonl (rx_fib_id); + mp->server_vrf_id = htonl (server_fib_id); + mp->vss_oui = htonl (vss_oui); + mp->vss_fib_id = htonl (vss_fib_id); + + mp->is_ipv6 = !ip46_address_is_ip4 (server); + + if (mp->is_ipv6) + { + memcpy (mp->dhcp_server, server, 16); + memcpy (mp->dhcp_src_address, src, 16); + } + else + { + /* put the address in the first bytes */ + memcpy (mp->dhcp_server, &server->ip4, 4); + memcpy (mp->dhcp_src_address, &src->ip4, 4); + } + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + + +static void +vl_api_dhcp_proxy_details_t_handler (vl_api_dhcp_proxy_details_t * mp) +{ + clib_warning ("BUG"); +} + void dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, u8 is_ipv6, u8 * host_address, u8 * router_address, @@ -172,15 +201,6 @@ dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, vl_msg_api_send_shmem (q, (u8 *) & mp); } -static void vl_api_dhcp_proxy_config_2_t_handler - (vl_api_dhcp_proxy_config_2_t * mp) -{ - if (mp->is_ipv6 == 0) - dhcpv4_proxy_config_2 (mp); - else - dhcpv6_proxy_config_2 (mp); -} - static void vl_api_dhcp_client_config_t_handler (vl_api_dhcp_client_config_t * mp) { diff --git a/src/vnet/dhcp/proxy.h b/src/vnet/dhcp/proxy.h index e12c0d00..4b115c74 100644 --- a/src/vnet/dhcp/proxy.h +++ b/src/vnet/dhcp/proxy.h @@ -27,7 +27,6 @@ #include #include #include -#include typedef enum { #define dhcp_proxy_error(n,s) DHCP_PROXY_ERROR_##n, @@ -49,9 +48,7 @@ typedef union { typedef struct { ip4_address_t dhcp_server; ip4_address_t dhcp_src_address; - u32 insert_option_82; u32 server_fib_index; - u32 valid; } dhcp_server_t; typedef struct { @@ -64,29 +61,39 @@ typedef struct { /* to drop pkts in server-to-client direction */ u32 error_drop_node_index; - vss_info *opt82vss; + vss_info *vss; /* hash lookup specific vrf_id -> option 82 vss suboption */ - uword * opt82vss_index_by_vrf_id; + u32 *vss_index_by_rx_fib_index; /* convenience */ - dhcp_client_main_t * dhcp_client_main; vlib_main_t * vlib_main; vnet_main_t * vnet_main; } dhcp_proxy_main_t; -dhcp_proxy_main_t dhcp_proxy_main; +extern dhcp_proxy_main_t dhcp_proxy_main; -int dhcp_proxy_set_server (ip4_address_t *addr, ip4_address_t *src_address, - u32 fib_id, int insert_option_82, int is_del); +void dhcp_send_details (void *opaque, + u32 context, + const ip46_address_t *server, + const ip46_address_t *src, + u32 server_fib_id, + u32 rx_fib_id, + u32 vss_fib_id, + u32 vss_oui); -int dhcp_proxy_set_server_2 (ip4_address_t *addr, ip4_address_t *src_address, - u32 rx_fib_id, - u32 server_fib_id, - int insert_option_82, int is_del); +int dhcp_proxy_set_server (ip4_address_t *addr, + ip4_address_t *src_address, + u32 fib_id, + u32 server_fib_id, + int is_del); int dhcp_proxy_set_option82_vss(u32 vrf_id, u32 oui, u32 fib_id, int is_del); + +void dhcp_proxy_dump(void *opaque, + u32 context); + #endif /* included_dhcp_proxy_h */ diff --git a/src/vnet/dhcp/proxy_error.def b/src/vnet/dhcp/proxy_error.def index 6aa06eb5..6d790d73 100644 --- a/src/vnet/dhcp/proxy_error.def +++ b/src/vnet/dhcp/proxy_error.def @@ -21,7 +21,8 @@ dhcp_proxy_error (RELAY_TO_SERVER, "DHCP packets relayed to the server") dhcp_proxy_error (RELAY_TO_CLIENT, "DHCP packets relayed to clients") dhcp_proxy_error (OPTION_82_ERROR, "DHCP failed to insert option 82") dhcp_proxy_error (NO_OPTION_82, "DHCP option 82 missing") -dhcp_proxy_error (BAD_OPTION_82, "Bad DHCP option 82 value") +dhcp_proxy_error (BAD_OPTION_82_ITF, "Bad DHCP option 82 interface value") +dhcp_proxy_error (BAD_OPTION_82_ADDR, "Bad DHCP option 82 address value") dhcp_proxy_error (BAD_FIB_ID, "DHCP option 82 fib-id to fib-index map failure") dhcp_proxy_error (NO_INTERFACE_ADDRESS, "DHCP no interface address") dhcp_proxy_error (OPTION_82_VSS_NOT_PROCESSED, "DHCP VSS not processed by DHCP server") diff --git a/src/vnet/dhcp/proxy_node.c b/src/vnet/dhcp/proxy_node.c index 6a58fcdb..ab6819fe 100644 --- a/src/vnet/dhcp/proxy_node.c +++ b/src/vnet/dhcp/proxy_node.c @@ -18,6 +18,7 @@ #include #include #include +#include #include static char * dhcp_proxy_error_strings[] = { @@ -57,6 +58,8 @@ typedef struct { vlib_node_registration_t dhcp_proxy_to_server_node; vlib_node_registration_t dhcp_proxy_to_client_node; +dhcp_proxy_main_t dhcp_proxy_main; + u8 * format_dhcp_proxy_trace (u8 * s, va_list * args) { CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); @@ -94,6 +97,42 @@ u8 * format_dhcp_proxy_header_with_length (u8 * s, va_list * args) return s; } +static inline vss_info * +dhcp_get_vss_info (dhcp_proxy_main_t *dm, + u32 rx_fib_index) +{ + vss_info *v; + + if (vec_len(dm->vss_index_by_rx_fib_index) <= rx_fib_index || + dm->vss_index_by_rx_fib_index[rx_fib_index] == ~0) + { + v = NULL; + } + else + { + v = pool_elt_at_index (dm->vss, + dm->vss_index_by_rx_fib_index[rx_fib_index]); + } + + return (v); +} + +static inline dhcp_server_t * +dhcp_get_server (dhcp_proxy_main_t *dm, + u32 rx_fib_index) +{ + dhcp_server_t *s = NULL; + + if (vec_len(dm->dhcp_server_index_by_rx_fib_index) > rx_fib_index && + dm->dhcp_server_index_by_rx_fib_index[rx_fib_index] != ~0) + { + s = pool_elt_at_index (dm->dhcp_servers, + dm->dhcp_server_index_by_rx_fib_index[rx_fib_index]); + } + + return (s); +} + static uword dhcp_proxy_to_server_input (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -131,9 +170,12 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, u32 sw_if_index = 0; u32 original_sw_if_index = 0; u8 *end = NULL; - u32 fib_index, server_index; + u32 fib_index; dhcp_server_t * server; u32 rx_sw_if_index; + dhcp_option_t *o; + u32 len = 0; + vlib_buffer_free_list_t *fl; bi0 = from[0]; to_next[0] = bi0; @@ -166,26 +208,16 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, rx_sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; fib_index = im->fib_index_by_sw_if_index [rx_sw_if_index]; - - if (fib_index < vec_len(dpm->dhcp_server_index_by_rx_fib_index)) - server_index = dpm->dhcp_server_index_by_rx_fib_index[fib_index]; - else - server_index = 0; + server = dhcp_get_server(dpm, fib_index); - if (PREDICT_FALSE (pool_is_free_index (dpm->dhcp_servers, - server_index))) + if (PREDICT_FALSE (NULL == server)) { - no_server: error0 = DHCP_PROXY_ERROR_NO_SERVER; next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; pkts_no_server++; goto do_trace; } - server = pool_elt_at_index (dpm->dhcp_servers, server_index); - if (server->valid == 0) - goto no_server; - vlib_buffer_advance (b0, -(sizeof(*ip0))); ip0 = vlib_buffer_get_current (b0); @@ -216,142 +248,131 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, h0->gateway_ip_address.as_u32 = server->dhcp_src_address.as_u32; pkts_to_server++; - if (server->insert_option_82) - { - u32 fib_index, fib_id, opt82_fib_id=0, opt82_oui=0; - ip4_fib_t * fib; - dhcp_option_t *o = (dhcp_option_t *) h0->options; - u32 len = 0; - vlib_buffer_free_list_t *fl; + o = (dhcp_option_t *) h0->options; - fib_index = im->fib_index_by_sw_if_index - [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; - fib = ip4_fib_get (fib_index); - fib_id = fib->table_id; - - end = b0->data + b0->current_data + b0->current_length; - /* TLVs are not performance-friendly... */ - while (o->option != 0xFF /* end of options */ && (u8 *)o < end) - o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); - - fl = vlib_buffer_get_free_list (vm, b0->free_list_index); - // start write at (option*)o, some packets have padding - if (((u8 *)o - (u8 *)b0->data + VPP_DHCP_OPTION82_SIZE) > fl->n_data_bytes) - { - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_too_big++; - goto do_trace; - } + fib_index = im->fib_index_by_sw_if_index + [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; + + end = b0->data + b0->current_data + b0->current_length; + /* TLVs are not performance-friendly... */ + while (o->option != 0xFF /* end of options */ && (u8 *)o < end) + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); - if ((o->option == 0xFF) && ((u8 *)o <= end)) - { - vnet_main_t *vnm = vnet_get_main(); - u16 old_l0, new_l0; - ip4_address_t _ia0, * ia0 = &_ia0; - uword *p_vss; - vss_info *vss; - vnet_sw_interface_t *swif; - sw_if_index = 0; - original_sw_if_index = 0; + fl = vlib_buffer_get_free_list (vm, b0->free_list_index); + // start write at (option*)o, some packets have padding + if (((u8 *)o - (u8 *)b0->data + VPP_DHCP_OPTION82_SIZE) > fl->n_data_bytes) + { + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_too_big++; + goto do_trace; + } + + if ((o->option == 0xFF) && ((u8 *)o <= end)) + { + vnet_main_t *vnm = vnet_get_main(); + u16 old_l0, new_l0; + ip4_address_t _ia0, * ia0 = &_ia0; + vss_info *vss; + vnet_sw_interface_t *swif; + sw_if_index = 0; + original_sw_if_index = 0; - original_sw_if_index = sw_if_index = - vnet_buffer(b0)->sw_if_index[VLIB_RX]; - swif = vnet_get_sw_interface (vnm, sw_if_index); - if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) - sw_if_index = swif->unnumbered_sw_if_index; + original_sw_if_index = sw_if_index = + vnet_buffer(b0)->sw_if_index[VLIB_RX]; + swif = vnet_get_sw_interface (vnm, sw_if_index); + if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) + sw_if_index = swif->unnumbered_sw_if_index; - p_vss = hash_get (dpm->opt82vss_index_by_vrf_id, - fib_id); - if (p_vss) - { - vss = pool_elt_at_index (dpm->opt82vss, p_vss[0]); - opt82_oui = vss->vpn_id.oui; - opt82_fib_id = vss->vpn_id.fib_id; - } - /* - * Get the first ip4 address on the [client-side] - * RX interface, if not unnumbered. otherwise use - * the loopback interface's ip address. - */ - ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); + /* + * Get the first ip4 address on the [client-side] + * RX interface, if not unnumbered. otherwise use + * the loopback interface's ip address. + */ + ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); - if (ia0 == 0) - { - error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS; - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_interface_address++; - goto do_trace; - } - - /* Add option 82 */ - o->option = 82; /* option 82 */ - o->length = 12; /* 12 octets to follow */ - o->data[0] = 1; /* suboption 1, circuit ID (=FIB id) */ - o->data[1] = 4; /* length of suboption */ - o->data[2] = (original_sw_if_index >> 24) & 0xFF; - o->data[3] = (original_sw_if_index >> 16) & 0xFF; - o->data[4] = (original_sw_if_index >> 8) & 0xFF; - o->data[5] = (original_sw_if_index >> 0) & 0xFF; - o->data[6] = 5; /* suboption 5 (client RX intfc address) */ - o->data[7] = 4; /* length 4 */ - o->data[8] = ia0->as_u8[0]; - o->data[9] = ia0->as_u8[1]; - o->data[10] = ia0->as_u8[2]; - o->data[11] = ia0->as_u8[3]; - o->data[12] = 0xFF; - if (opt82_oui !=0 || opt82_fib_id != 0) - { - o->data[12] = 151; /* vss suboption */ - if (255 == opt82_fib_id) { - o->data[13] = 1; /* length */ - o->data[14] = 255; /* vss option type */ - o->data[15] = 152; /* vss control suboption */ - o->data[16] = 0; /* length */ - /* and a new "end-of-options" option (0xff) */ - o->data[17] = 0xFF; - o->length += 5; - } else { - o->data[13] = 8; /* length */ - o->data[14] = 1; /* vss option type */ - o->data[15] = (opt82_oui >> 16) & 0xff; - o->data[16] = (opt82_oui >> 8) & 0xff; - o->data[17] = (opt82_oui ) & 0xff; - o->data[18] = (opt82_fib_id >> 24) & 0xff; - o->data[19] = (opt82_fib_id >> 16) & 0xff; - o->data[20] = (opt82_fib_id >> 8) & 0xff; - o->data[21] = (opt82_fib_id) & 0xff; - o->data[22] = 152; /* vss control suboption */ - o->data[23] = 0; /* length */ + if (ia0 == 0) + { + error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS; + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_interface_address++; + goto do_trace; + } + + /* Add option 82 */ + o->option = 82; /* option 82 */ + o->length = 12; /* 12 octets to follow */ + o->data[0] = 1; /* suboption 1, circuit ID (=FIB id) */ + o->data[1] = 4; /* length of suboption */ + o->data[2] = (original_sw_if_index >> 24) & 0xFF; + o->data[3] = (original_sw_if_index >> 16) & 0xFF; + o->data[4] = (original_sw_if_index >> 8) & 0xFF; + o->data[5] = (original_sw_if_index >> 0) & 0xFF; + o->data[6] = 5; /* suboption 5 (client RX intfc address) */ + o->data[7] = 4; /* length 4 */ + o->data[8] = ia0->as_u8[0]; + o->data[9] = ia0->as_u8[1]; + o->data[10] = ia0->as_u8[2]; + o->data[11] = ia0->as_u8[3]; + o->data[12] = 0xFF; + + vss = dhcp_get_vss_info (dpm, fib_index); + if (NULL != vss) + { + u32 opt82_fib_id=0, opt82_oui=0; + + opt82_oui = vss->vpn_id.oui; + opt82_fib_id = vss->vpn_id.fib_id; + + o->data[12] = 151; /* vss suboption */ + if (255 == opt82_fib_id) { + o->data[13] = 1; /* length */ + o->data[14] = 255; /* vss option type */ + o->data[15] = 152; /* vss control suboption */ + o->data[16] = 0; /* length */ + /* and a new "end-of-options" option (0xff) */ + o->data[17] = 0xFF; + o->length += 5; + } else { + o->data[13] = 8; /* length */ + o->data[14] = 1; /* vss option type */ + o->data[15] = (opt82_oui >> 16) & 0xff; + o->data[16] = (opt82_oui >> 8) & 0xff; + o->data[17] = (opt82_oui ) & 0xff; + o->data[18] = (opt82_fib_id >> 24) & 0xff; + o->data[19] = (opt82_fib_id >> 16) & 0xff; + o->data[20] = (opt82_fib_id >> 8) & 0xff; + o->data[21] = (opt82_fib_id) & 0xff; + o->data[22] = 152; /* vss control suboption */ + o->data[23] = 0; /* length */ - /* and a new "end-of-options" option (0xff) */ - o->data[24] = 0xFF; - o->length += 12; - } + /* and a new "end-of-options" option (0xff) */ + o->data[24] = 0xFF; + o->length += 12; } - - len = o->length + 3; - b0->current_length += len; - /* Fix IP header length and checksum */ - old_l0 = ip0->length; - new_l0 = clib_net_to_host_u16 (old_l0); - new_l0 += len; - new_l0 = clib_host_to_net_u16 (new_l0); - ip0->length = new_l0; - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, - length /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - /* Fix UDP length */ - new_l0 = clib_net_to_host_u16 (u0->length); - new_l0 += len; - u0->length = clib_host_to_net_u16 (new_l0); - } else { - vlib_node_increment_counter - (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_OPTION_82_ERROR, 1); - } - } + } + + len = o->length + 3; + b0->current_length += len; + /* Fix IP header length and checksum */ + old_l0 = ip0->length; + new_l0 = clib_net_to_host_u16 (old_l0); + new_l0 += len; + new_l0 = clib_host_to_net_u16 (new_l0); + ip0->length = new_l0; + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, + length /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + /* Fix UDP length */ + new_l0 = clib_net_to_host_u16 (u0->length); + new_l0 += len; + u0->length = clib_host_to_net_u16 (new_l0); + } else { + vlib_node_increment_counter + (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_OPTION_82_ERROR, 1); + } next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; @@ -451,11 +472,13 @@ dhcp_proxy_to_client_input (vlib_main_t * vm, vnet_sw_interface_t *si0; u32 error0 = (u32)~0; vnet_sw_interface_t *swif; - u32 server_index; u32 fib_index; dhcp_server_t * server; u32 original_sw_if_index = (u32) ~0; - + ip4_address_t relay_addr = { + .as_u32 = 0, + }; + bi0 = from[0]; from += 1; n_left_from -= 1; @@ -501,13 +524,21 @@ dhcp_proxy_to_client_input (vlib_main_t * vm, and the sw_if_index */ if (sub->option == 1 && sub->length == 4) { - sw_if_index = (o->data[2] << 24) - | (o->data[3] << 16) - | (o->data[4] << 8) - | (o->data[5]); - } else if (sub->option == 151 && - sub->length == 7 && - sub->data[0] == 1) + sw_if_index = ((sub->data[0] << 24) | + (sub->data[1] << 16) | + (sub->data[2] << 8) | + (sub->data[3])); + } + else if (sub->option == 5 && sub->length == 4) + { + relay_addr.as_u8[0] = sub->data[0]; + relay_addr.as_u8[1] = sub->data[1]; + relay_addr.as_u8[2] = sub->data[2]; + relay_addr.as_u8[3] = sub->data[3]; + } + else if (sub->option == 151 && + sub->length == 7 && + sub->data[0] == 1) vss_exist = 1; else if (sub->option == 152 && sub->length == 0) vss_ctrl = 1; @@ -539,34 +570,27 @@ dhcp_proxy_to_client_input (vlib_main_t * vm, goto do_trace; } + if (relay_addr.as_u32 == 0) + { + error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ADDR; + goto drop_packet; + } if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index)) { - error0 = DHCP_PROXY_ERROR_BAD_OPTION_82; + error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ITF; goto drop_packet; } fib_index = im->fib_index_by_sw_if_index [sw_if_index]; + server = dhcp_get_server(dpm, fib_index); - if (fib_index < vec_len(dpm->dhcp_server_index_by_rx_fib_index)) - server_index = dpm->dhcp_server_index_by_rx_fib_index[fib_index]; - else - server_index = 0; - - if (PREDICT_FALSE (pool_is_free_index (dpm->dhcp_servers, - server_index))) - { - error0 = DHCP_PROXY_ERROR_BAD_OPTION_82; - goto drop_packet; - } - - server = pool_elt_at_index (dpm->dhcp_servers, server_index); - if (server->valid == 0) + if (PREDICT_FALSE (NULL == server)) { error0 = DHCP_PROXY_ERROR_NO_SERVER; goto drop_packet; } - + if (ip0->src_address.as_u32 != server->dhcp_server.as_u32) { error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; @@ -587,6 +611,12 @@ dhcp_proxy_to_client_input (vlib_main_t * vm, goto drop_packet; } + if (relay_addr.as_u32 != ia0->as_u32) + { + error0 = DHCP_PROXY_ERROR_BAD_YIADDR; + goto drop_packet; + } + u0->checksum = 0; u0->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcp_to_client); sum0 = ip0->checksum; @@ -677,7 +707,7 @@ clib_error_t * dhcp_proxy_init (vlib_main_t * vm) error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); dm->error_drop_node_index = error_drop_node->index; - dm->opt82vss_index_by_vrf_id = hash_create (0, sizeof (uword)); + dm->vss_index_by_rx_fib_index = NULL; udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_client, dhcp_proxy_to_client_node.index, 1 /* is_ip4 */); @@ -694,15 +724,17 @@ clib_error_t * dhcp_proxy_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (dhcp_proxy_init); -int dhcp_proxy_set_server_2 (ip4_address_t *addr, ip4_address_t *src_address, - u32 rx_fib_id, - u32 server_fib_id, - int insert_option_82, int is_del) +int dhcp_proxy_set_server (ip4_address_t *addr, + ip4_address_t *src_address, + u32 rx_fib_id, + u32 server_fib_id, + int is_del) { dhcp_proxy_main_t * dpm = &dhcp_proxy_main; dhcp_server_t * server = 0; u32 server_index = 0; u32 rx_fib_index = 0; + const fib_prefix_t all_1s = { .fp_len = 32, @@ -719,97 +751,68 @@ int dhcp_proxy_set_server_2 (ip4_address_t *addr, ip4_address_t *src_address, rx_fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, rx_fib_id); - if (rx_fib_id == 0) - { - server = pool_elt_at_index (dpm->dhcp_servers, 0); - - if (is_del) - { - memset (server, 0, sizeof (*server)); - fib_table_entry_special_remove(rx_fib_index, - &all_1s, - FIB_SOURCE_DHCP); - return 0; - } - if (!server->valid) - fib_table_entry_special_add(rx_fib_index, - &all_1s, - FIB_SOURCE_DHCP, - FIB_ENTRY_FLAG_LOCAL, - ADJ_INDEX_INVALID); - - goto initialize_it; - } - if (is_del) { if (rx_fib_index >= vec_len(dpm->dhcp_server_index_by_rx_fib_index)) return VNET_API_ERROR_NO_SUCH_ENTRY; server_index = dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index]; - ASSERT(server_index > 0); + + if (server_index == ~0) + return VNET_API_ERROR_NO_SUCH_ENTRY; /* Use the default server again. */ - dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = 0; + dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = ~0; server = pool_elt_at_index (dpm->dhcp_servers, server_index); - memset (server, 0, sizeof (*server)); - pool_put (dpm->dhcp_servers, server); fib_table_entry_special_remove(rx_fib_index, &all_1s, FIB_SOURCE_DHCP); + fib_table_unlock (rx_fib_index, + FIB_PROTOCOL_IP4); + fib_table_unlock (server->server_fib_index, + FIB_PROTOCOL_IP4); + memset (server, 0, sizeof (*server)); + pool_put (dpm->dhcp_servers, server); return 0; } - - if (rx_fib_index < vec_len(dpm->dhcp_server_index_by_rx_fib_index)) - { - server_index = dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index]; - if (server_index != 0) - { - server = pool_elt_at_index (dpm->dhcp_servers, server_index); - goto initialize_it; - } - } - - pool_get (dpm->dhcp_servers, server); - - fib_table_entry_special_add(rx_fib_index, - &all_1s, - FIB_SOURCE_DHCP, - FIB_ENTRY_FLAG_LOCAL, - ADJ_INDEX_INVALID); - - initialize_it: - - - server->dhcp_server.as_u32 = addr->as_u32; - server->server_fib_index = - fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, - server_fib_id); - server->dhcp_src_address.as_u32 = src_address->as_u32; - server->insert_option_82 = insert_option_82; - server->valid = 1; - if (rx_fib_index) - { - vec_validate (dpm->dhcp_server_index_by_rx_fib_index, rx_fib_index); + else + { + vec_validate_init_empty(dpm->dhcp_server_index_by_rx_fib_index, + rx_fib_index, + ~0); + + pool_get (dpm->dhcp_servers, server); + + server->dhcp_server.as_u32 = addr->as_u32; + server->dhcp_src_address.as_u32 = src_address->as_u32; + + fib_table_entry_special_add(rx_fib_index, + &all_1s, + FIB_SOURCE_DHCP, + FIB_ENTRY_FLAG_LOCAL, + ADJ_INDEX_INVALID); + fib_table_lock (rx_fib_index, + FIB_PROTOCOL_IP4); + + server->server_fib_index = + fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, + server_fib_id); + + vec_validate_init_empty (dpm->dhcp_server_index_by_rx_fib_index, + rx_fib_index, + ~0); dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = - server - dpm->dhcp_servers; - } + server - dpm->dhcp_servers; + } - return 0; -} + fib_table_unlock (rx_fib_index, + FIB_PROTOCOL_IP4); -/* Old API, manipulates the default server (only) */ -int dhcp_proxy_set_server (ip4_address_t *addr, ip4_address_t *src_address, - u32 fib_id, int insert_option_82, int is_del) -{ - return dhcp_proxy_set_server_2 (addr, src_address, 0 /* rx_fib_id */, - fib_id /* server_fib_id */, - insert_option_82, is_del); + return 0; } - static clib_error_t * dhcp_proxy_set_command_fn (vlib_main_t * vm, unformat_input_t * input, @@ -818,7 +821,6 @@ dhcp_proxy_set_command_fn (vlib_main_t * vm, ip4_address_t server_addr, src_addr; u32 server_fib_id = 0, rx_fib_id = 0; int is_del = 0; - int add_option_82 = 0; int set_src = 0, set_server = 0; while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) @@ -833,9 +835,6 @@ dhcp_proxy_set_command_fn (vlib_main_t * vm, else if (unformat(input, "src-address %U", unformat_ip4_address, &src_addr)) set_src = 1; - else if (unformat (input, "add-option-82") - || unformat (input, "insert-option-82")) - add_option_82 = 1; else if (unformat (input, "delete") || unformat (input, "del")) is_del = 1; @@ -847,8 +846,8 @@ dhcp_proxy_set_command_fn (vlib_main_t * vm, { int rv; - rv = dhcp_proxy_set_server_2 (&server_addr, &src_addr, rx_fib_id, - server_fib_id, add_option_82, is_del); + rv = dhcp_proxy_set_server (&server_addr, &src_addr, rx_fib_id, + server_fib_id, is_del); switch (rv) { case 0: @@ -882,7 +881,7 @@ dhcp_proxy_set_command_fn (vlib_main_t * vm, VLIB_CLI_COMMAND (dhcp_proxy_set_command, static) = { .path = "set dhcp proxy", - .short_help = "set dhcp proxy [del] server src-address [add-option-82] [server-fib-id ] [rx-fib-id ]", + .short_help = "set dhcp proxy [del] server src-address [server-fib-id ] [rx-fib-id ]", .function = dhcp_proxy_set_command_fn, }; @@ -896,8 +895,8 @@ u8 * format_dhcp_proxy_server (u8 * s, va_list * args) if (dm == 0) { - s = format (s, "%=16s%=16s%=14s%=14s%=20s", "Server", "Src Address", - "Server FIB", "RX FIB", "Insert Option 82"); + s = format (s, "%=16s%=16s%=14s%=14s", "Server", "Src Address", + "Server FIB", "RX FIB"); return s; } @@ -911,11 +910,10 @@ u8 * format_dhcp_proxy_server (u8 * s, va_list * args) if (rx_fib) rx_fib_id = rx_fib->table_id; - s = format (s, "%=16U%=16U%=14u%=14u%=20s", + s = format (s, "%=16U%=16U%=14u%=14u", format_ip4_address, &server->dhcp_server, format_ip4_address, &server->dhcp_src_address, - server_fib_id, rx_fib_id, - server->insert_option_82 ? "yes" : "no"); + server_fib_id, rx_fib_id); return s; } @@ -925,24 +923,22 @@ dhcp_proxy_show_command_fn (vlib_main_t * vm, vlib_cli_command_t * cmd) { dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - ip4_main_t * im = &ip4_main; dhcp_server_t * server; - u32 server_index; - int i; + u32 server_index, i; vlib_cli_output (vm, "%U", format_dhcp_proxy_server, 0 /* header line */, 0, 0); - for (i = 0; i < vec_len (im->fibs); i++) - { - if (i < vec_len(dpm->dhcp_server_index_by_rx_fib_index)) - server_index = dpm->dhcp_server_index_by_rx_fib_index[i]; - else - server_index = 0; + vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index) + { + server_index = dpm->dhcp_server_index_by_rx_fib_index[i]; + if (~0 == server_index) + continue; + server = pool_elt_at_index (dpm->dhcp_servers, server_index); - if (server->valid) - vlib_cli_output (vm, "%U", format_dhcp_proxy_server, dpm, - server, i); + + vlib_cli_output (vm, "%U", format_dhcp_proxy_server, dpm, + server, i); } return 0; @@ -954,50 +950,104 @@ VLIB_CLI_COMMAND (dhcp_proxy_show_command, static) = { .function = dhcp_proxy_show_command_fn, }; +void +dhcp_proxy_dump (void *opaque, + u32 context) +{ + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + ip4_fib_t *s_fib, *r_fib; + dhcp_server_t * server; + u32 server_index, i; + vss_info *v; + + vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index) + { + server_index = dpm->dhcp_server_index_by_rx_fib_index[i]; + if (~0 == server_index) + continue; + + server = pool_elt_at_index (dpm->dhcp_servers, server_index); + v = dhcp_get_vss_info(dpm, i); + + ip46_address_t src_addr = { + .ip4 = server->dhcp_src_address, + }; + ip46_address_t server_addr = { + .ip4 = server->dhcp_server, + }; + + s_fib = ip4_fib_get(server->server_fib_index); + r_fib = ip4_fib_get(i); + + dhcp_send_details(opaque, + context, + &server_addr, + &src_addr, + s_fib->table_id, + r_fib->table_id, + (v ? v->vpn_id.fib_id : 0), + (v ? v->vpn_id.oui : 0)); + } +} -int dhcp_proxy_set_option82_vss( u32 vrf_id, - u32 oui, - u32 fib_id, - int is_del) +int dhcp_proxy_set_option82_vss(u32 tbl_id, + u32 oui, + u32 fib_id, + int is_del) { dhcp_proxy_main_t *dm = &dhcp_proxy_main; - uword *p; - vss_info *a; - u32 old_oui=0, old_fib_id=0; + vss_info *v = NULL; + u32 rx_fib_index; + int rc = 0; - p = hash_get (dm->opt82vss_index_by_vrf_id, vrf_id); + rx_fib_index = ip4_fib_table_find_or_create_and_lock(tbl_id); + v = dhcp_get_vss_info(dm, rx_fib_index); - if (p) - { - a = pool_elt_at_index (dm->opt82vss, p[0]); - if (!a) - return VNET_API_ERROR_NO_SUCH_FIB; - old_oui = a->vpn_id.oui; - old_fib_id = a->vpn_id.fib_id; - + if (NULL != v) + { if (is_del) - { - if (old_oui == oui && - old_fib_id == fib_id) - { - pool_put(dm->opt82vss, a); - hash_unset (dm->opt82vss_index_by_vrf_id, vrf_id); - return 0; - } - else - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - pool_put(dm->opt82vss, a); - hash_unset (dm->opt82vss_index_by_vrf_id, vrf_id); - } else if (is_del) - return VNET_API_ERROR_NO_SUCH_ENTRY; - pool_get (dm->opt82vss, a); - memset (a, ~0, sizeof (a[0])); - a->vpn_id.oui = oui; - a->vpn_id.fib_id = fib_id; - hash_set (dm->opt82vss_index_by_vrf_id, vrf_id, a - dm->opt82vss); + { + /* release the lock held on the table when the VSS + * info was created */ + fib_table_unlock (rx_fib_index, + FIB_PROTOCOL_IP4); + + pool_put (dm->vss, v); + dm->vss_index_by_rx_fib_index[rx_fib_index] = ~0; + } + else + { + /* this is a modify */ + v->vpn_id.fib_id = fib_id; + v->vpn_id.oui = oui; + } + } + else + { + if (is_del) + rc = VNET_API_ERROR_NO_SUCH_ENTRY; + else + { + /* create a new entry */ + vec_validate_init_empty(dm->vss_index_by_rx_fib_index, + rx_fib_index, ~0); + + /* hold a lock on the table whilst the VSS info exist */ + fib_table_lock (rx_fib_index, + FIB_PROTOCOL_IP4); + + pool_get (dm->vss, v); + v->vpn_id.fib_id = fib_id; + v->vpn_id.oui = oui; + dm->vss_index_by_rx_fib_index[rx_fib_index] = v - dm->vss; + } + } + + /* Release the lock taken during the create_or_lock at the start */ + fib_table_unlock (rx_fib_index, + FIB_PROTOCOL_IP4); - return 0; + return (rc); } static clib_error_t * @@ -1065,20 +1115,20 @@ dhcp_vss_show_command_fn (vlib_main_t * vm, { dhcp_proxy_main_t * dm = &dhcp_proxy_main; + ip4_fib_t *fib; + u32 *fib_index; vss_info *v; - u32 oui; - u32 fib_id; - u32 tbl_id; - uword index; vlib_cli_output (vm, "%=9s%=11s%=12s","Table", "OUI", "VPN-ID"); - hash_foreach (tbl_id, index, dm->opt82vss_index_by_vrf_id, + pool_foreach (fib_index, dm->vss_index_by_rx_fib_index, ({ - v = pool_elt_at_index (dm->opt82vss, index); - oui = v->vpn_id.oui; - fib_id = v->vpn_id.fib_id; - vlib_cli_output (vm, "%=9d 0x%08x%=12d", - tbl_id, oui, fib_id); + fib = ip4_fib_get (*fib_index); + v = pool_elt_at_index (dm->vss, *fib_index); + + vlib_cli_output (vm, "%=6d%=6d%=12d", + fib->table_id, + v->vpn_id.oui, + v->vpn_id.fib_id); })); return 0; diff --git a/src/vnet/dhcpv6/proxy.h b/src/vnet/dhcpv6/proxy.h index 9e18913a..77ced361 100644 --- a/src/vnet/dhcpv6/proxy.h +++ b/src/vnet/dhcpv6/proxy.h @@ -48,9 +48,7 @@ typedef union { typedef struct { ip6_address_t dhcp6_server; ip6_address_t dhcp6_src_address; - u32 insert_vss; u32 server_fib6_index; - u32 valid; } dhcpv6_server_t; typedef struct { @@ -70,7 +68,7 @@ typedef struct { dhcpv6_vss_info *vss; /* hash lookup specific vrf_id -> VSS vector index*/ - uword *vss_index_by_vrf_id; + u32 *vss_index_by_rx_fib_index; /* convenience */ vlib_main_t * vlib_main; @@ -79,17 +77,18 @@ typedef struct { dhcpv6_proxy_main_t dhcpv6_proxy_main; -int dhcpv6_proxy_set_server (ip6_address_t *addr, ip6_address_t *src_address, - u32 fib_id, int insert_vss, int is_del); - int dhcpv6_proxy_set_vss(u32 tbl_id, u32 oui, u32 fib_id, int is_del); -int dhcpv6_proxy_set_server_2 (ip6_address_t *addr, ip6_address_t *src_address, - u32 rx_fib_id, - u32 server_fib_id, - int insert_vss, int is_del); +int dhcpv6_proxy_set_server(ip6_address_t *addr, + ip6_address_t *src_address, + u32 rx_fib_id, + u32 server_fib_id, + int is_del); + +void dhcpv6_proxy_dump(void *opaque, + u32 context); #endif /* included_dhcpv6_proxy_h */ diff --git a/src/vnet/dhcpv6/proxy_node.c b/src/vnet/dhcpv6/proxy_node.c index 4137624c..f40798e6 100644 --- a/src/vnet/dhcpv6/proxy_node.c +++ b/src/vnet/dhcpv6/proxy_node.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -117,6 +118,42 @@ static inline void copy_ip6_address (ip6_address_t *dst, ip6_address_t *src) dst->as_u64[1] = src->as_u64[1]; } +static inline dhcpv6_vss_info * +dhcpv6_get_vss_info (dhcpv6_proxy_main_t *dm, + u32 rx_fib_index) +{ + dhcpv6_vss_info *v; + + if (vec_len(dm->vss_index_by_rx_fib_index) <= rx_fib_index || + dm->vss_index_by_rx_fib_index[rx_fib_index] == ~0) + { + v = NULL; + } + else + { + v = pool_elt_at_index (dm->vss, + dm->vss_index_by_rx_fib_index[rx_fib_index]); + } + + return (v); +} + +static inline dhcpv6_server_t * +dhcpv6_get_server (dhcpv6_proxy_main_t *dm, + u32 rx_fib_index) +{ + dhcpv6_server_t *s = NULL; + + if (vec_len(dm->dhcp6_server_index_by_rx_fib_index) > rx_fib_index && + dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] != ~0) + { + s = pool_elt_at_index (dm->dhcp6_servers, + dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index]); + } + + return (s); +} + static uword dhcpv6_proxy_to_server_input (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -132,13 +169,10 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, u32 pkts_wrong_msg_type=0; u32 pkts_too_big=0; ip6_main_t * im = &ip6_main; - ip6_fib_t * fib; ip6_address_t * src; int bogus_length; dhcpv6_server_t * server; u32 rx_fib_idx = 0, server_fib_idx = 0; - u32 server_idx; - u32 fib_id1 = 0; next_index = node->cached_next_index; @@ -172,12 +206,8 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, ethernet_header_t * e_h0; u8 client_src_mac[6]; vlib_buffer_free_list_t *fl; - - uword *p_vss; - u32 oui1=0; dhcpv6_vss_info *vss; - bi0 = from[0]; to_next[0] = bi0; from += 1; @@ -228,25 +258,15 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, /* Send to DHCPV6 server via the configured FIB */ rx_sw_if_index = sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; rx_fib_idx = im->fib_index_by_sw_if_index [rx_sw_if_index]; + server = dhcpv6_get_server(dpm, rx_fib_idx); - if (vec_len(dpm->dhcp6_server_index_by_rx_fib_index) <= rx_fib_idx) - goto no_server; - - server_idx = dpm->dhcp6_server_index_by_rx_fib_index[rx_fib_idx]; - - if (PREDICT_FALSE (pool_is_free_index (dpm->dhcp6_servers, - server_idx))) - { - no_server: - error0 = DHCPV6_PROXY_ERROR_NO_SERVER; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_server++; - goto do_trace; - } - - server = pool_elt_at_index(dpm->dhcp6_servers, server_idx); - if (server->valid == 0) - goto no_server; + if (PREDICT_FALSE (NULL == server)) + { + error0 = DHCPV6_PROXY_ERROR_NO_SERVER; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_server++; + goto do_trace; + } server_fib_idx = server->server_fib6_index; vnet_buffer(b0)->sw_if_index[VLIB_TX] = server_fib_idx; @@ -331,19 +351,6 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, id1 = (dhcpv6_int_id_t *) (((uword) ip1) + b0->current_length); b0->current_length += (sizeof (*id1)); - - fib = ip6_fib_get (rx_fib_idx); - - //TODO: Revisit if hash makes sense here - p_vss = hash_get (dpm->vss_index_by_vrf_id, - fib->table_id); - if (p_vss) - { - vss = pool_elt_at_index (dpm->vss, p_vss[0]); - oui1 = vss->vpn_id.oui; - fib_id1 = vss->vpn_id.fib_id; - } - id1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_INTERFACE_ID); id1->opt.length = clib_host_to_net_u16(sizeof(rx_sw_if_index)); id1->int_idx = clib_host_to_net_u32(rx_sw_if_index); @@ -360,20 +367,24 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, clib_memcpy(cmac->data, client_src_mac, 6); u1->length += sizeof(*cmac); } - if (server->insert_vss !=0 ) { + + //TODO: Revisit if hash makes sense here + vss = dhcpv6_get_vss_info(dpm, rx_fib_idx); + + if (NULL != vss) { vss1 = (dhcpv6_vss_t *) (((uword) ip1) + b0->current_length); b0->current_length += (sizeof (*vss1)); vss1->opt.length =clib_host_to_net_u16(sizeof(*vss1) - sizeof(vss1->opt)); vss1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_VSS); vss1->data[0] = 1; // type - vss1->data[1] = oui1>>16 & 0xff; - vss1->data[2] = oui1>>8 & 0xff; - vss1->data[3] = oui1 & 0xff; - vss1->data[4] = fib_id1>>24 & 0xff; - vss1->data[5] = fib_id1>>16 & 0xff; - vss1->data[6] = fib_id1>>8 & 0xff; - vss1->data[7] = fib_id1 & 0xff; + vss1->data[1] = vss->vpn_id.oui >>16 & 0xff; + vss1->data[2] = vss->vpn_id.oui >>8 & 0xff; + vss1->data[3] = vss->vpn_id.oui & 0xff; + vss1->data[4] = vss->vpn_id.fib_id >> 24 & 0xff; + vss1->data[5] = vss->vpn_id.fib_id >> 16 & 0xff; + vss1->data[6] = vss->vpn_id.fib_id >> 8 & 0xff; + vss1->data[7] = vss->vpn_id.fib_id & 0xff; u1->length += sizeof(*vss1); } @@ -524,9 +535,8 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, u16 len = 0; u8 interface_opt_flag = 0; u8 relay_msg_opt_flag = 0; - ip6_fib_t * svr_fib; ip6_main_t * im = &ip6_main; - u32 server_fib_idx, svr_fib_id, client_fib_idx, server_idx; + u32 server_fib_idx, client_fib_idx; bi0 = from[0]; from += 1; @@ -608,31 +618,18 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, vlib_buffer_advance (b0, sizeof(*r0)); client_fib_idx = im->fib_index_by_sw_if_index[sw_if_index]; - if (client_fib_idx < vec_len(dm->dhcp6_server_index_by_rx_fib_index)) - server_idx = dm->dhcp6_server_index_by_rx_fib_index[client_fib_idx]; - else - server_idx = 0; - - if (PREDICT_FALSE (pool_is_free_index (dm->dhcp6_servers, server_idx))) - { - error0 = DHCPV6_PROXY_ERROR_WRONG_INTERFACE_ID_OPTION; - goto drop_packet; - } + server = dhcpv6_get_server(dm, client_fib_idx); - server = pool_elt_at_index (dm->dhcp6_servers, server_idx); - if (server->valid == 0) + if (NULL == server) { error0 = DHCPV6_PROXY_ERROR_NO_SERVER; goto drop_packet; } - server_fib_idx = im->fib_index_by_sw_if_index [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; - svr_fib = ip6_fib_get (server_fib_idx); - svr_fib_id = svr_fib->table_id; - if (svr_fib_id != server->server_fib6_index || + if (server_fib_idx != server->server_fib6_index || ip0->src_address.as_u64[0] != server->dhcp6_server.as_u64[0] || ip0->src_address.as_u64[1] != server->dhcp6_server.as_u64[1]) { @@ -760,7 +757,7 @@ clib_error_t * dhcpv6_proxy_init (vlib_main_t * vm) error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); dm->error_drop_node_index = error_drop_node->index; - dm->vss_index_by_vrf_id = hash_create (0, sizeof (uword)); + dm->vss_index_by_rx_fib_index = NULL; /* RFC says this is the dhcpv6 server address */ dm->all_dhcpv6_server_address.as_u64[0] = clib_host_to_net_u64 (0xFF05000000000000); @@ -785,121 +782,138 @@ clib_error_t * dhcpv6_proxy_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (dhcpv6_proxy_init); -/* Old API, manipulates a single server (only) shared by all Rx VRFs */ -int dhcpv6_proxy_set_server (ip6_address_t *addr, ip6_address_t *src_address, - u32 fib_id, int insert_vss, int is_del) -{ - return dhcpv6_proxy_set_server_2 (addr, src_address, - 0, fib_id, - insert_vss, is_del); -} - -int dhcpv6_proxy_set_server_2 (ip6_address_t *addr, ip6_address_t *src_address, - u32 rx_fib_id, u32 server_fib_id, - int insert_vss, int is_del) +int dhcpv6_proxy_set_server (ip6_address_t *addr, + ip6_address_t *src_address, + u32 rx_fib_id, + u32 server_fib_id, + int is_del) { dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; dhcpv6_server_t * server = 0; - u32 server_fib_index = 0; u32 rx_fib_index = 0; + int rc = 0; rx_fib_index = ip6_mfib_table_find_or_create_and_lock(rx_fib_id); - server_fib_index = ip6_fib_table_find_or_create_and_lock(server_fib_id); - - if (is_del) - { - - if (rx_fib_index >= vec_len(dm->dhcp6_server_index_by_rx_fib_index)) - return VNET_API_ERROR_NO_SUCH_ENTRY; - server_fib_index = dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index]; - - dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] = 0; - server = pool_elt_at_index (dm->dhcp6_servers, server_fib_index); - memset (server, 0, sizeof (*server)); - pool_put (dm->dhcp6_servers, server); - return 0; + const mfib_prefix_t all_dhcp_servers = { + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_grp_addr = { + .ip6 = dm->all_dhcpv6_server_relay_agent_address, } + }; - if (addr->as_u64[0] == 0 && - addr->as_u64[1] == 0 ) - return VNET_API_ERROR_INVALID_DST_ADDRESS; - - if (src_address->as_u64[0] == 0 && - src_address->as_u64[1] == 0) - return VNET_API_ERROR_INVALID_SRC_ADDRESS; - - if (rx_fib_id == 0) + if (is_del) { - server = pool_elt_at_index (dm->dhcp6_servers, 0); - if (server->valid) - goto reconfigure_it; - else - goto initialize_it; - } + server = dhcpv6_get_server(dm, rx_fib_index); - if (rx_fib_index < vec_len(dm->dhcp6_server_index_by_rx_fib_index)) - { - server_fib_index = dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index]; - if (server_fib_index != 0) + if (NULL == server) { - server = pool_elt_at_index (dm->dhcp6_servers, server_fib_index); - goto initialize_it; + rc = VNET_API_ERROR_NO_SUCH_ENTRY; + goto out; } - } - /*Allocate a new server*/ - pool_get (dm->dhcp6_servers, server); - - initialize_it: - { - const mfib_prefix_t all_dhcp_servers = { - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - .fp_grp_addr = { - .ip6 = dm->all_dhcpv6_server_relay_agent_address, - } - }; - const fib_route_path_t path_for_us = { - .frp_proto = FIB_PROTOCOL_IP6, - .frp_addr = zero_addr, - .frp_sw_if_index = 0xffffffff, - .frp_fib_index = ~0, - .frp_weight = 0, - .frp_flags = FIB_ROUTE_PATH_LOCAL, - }; - mfib_table_entry_path_update(rx_fib_index, - &all_dhcp_servers, - MFIB_SOURCE_DHCP, - &path_for_us, - MFIB_ITF_FLAG_FORWARD); /* - * Each interface that is enabled in this table, needs to be added - * as an accepting interface, but this is not easily doable in VPP. - * So we cheat. Add a flag to the entry that indicates accept form - * any interface. - * We will still only accept on v6 enabled interfaces, since the input - * feature ensures this. + * release the locks held on the server fib and rx mfib */ - mfib_table_entry_update(rx_fib_index, + mfib_table_entry_delete(rx_fib_index, &all_dhcp_servers, - MFIB_SOURCE_DHCP, - MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF); - } + MFIB_SOURCE_DHCP); + mfib_table_unlock(rx_fib_index, FIB_PROTOCOL_IP6); + fib_table_unlock(server->server_fib6_index, FIB_PROTOCOL_IP6); -reconfigure_it: + dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] = ~0; - copy_ip6_address(&server->dhcp6_server, addr); - copy_ip6_address(&server->dhcp6_src_address, src_address); - server->server_fib6_index = server_fib_index; - server->valid = 1; - server->insert_vss = insert_vss; + memset (server, 0, sizeof (*server)); + pool_put (dm->dhcp6_servers, server); + } + else + { + if (addr->as_u64[0] == 0 && + addr->as_u64[1] == 0 ) + { + rc = VNET_API_ERROR_INVALID_DST_ADDRESS; + goto out; + } + if (src_address->as_u64[0] == 0 && + src_address->as_u64[1] == 0) + { + rc = VNET_API_ERROR_INVALID_SRC_ADDRESS; + goto out; + } - vec_validate (dm->dhcp6_server_index_by_rx_fib_index, rx_fib_index); - dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] = - server - dm->dhcp6_servers; + server = dhcpv6_get_server(dm, rx_fib_index); - return 0; + if (NULL != server) + { + /* modify of an existing entry */ + ip6_fib_t *fib; + + fib = ip6_fib_get(server->server_fib6_index); + + if (fib->table_id != server_fib_id) + { + /* swap tables */ + fib_table_unlock(server->server_fib6_index, FIB_PROTOCOL_IP6); + server->server_fib6_index = + ip6_fib_table_find_or_create_and_lock(server_fib_id); + } + } + else + { + /* Allocate a new server */ + pool_get (dm->dhcp6_servers, server); + + vec_validate_init_empty (dm->dhcp6_server_index_by_rx_fib_index, + rx_fib_index, ~0); + dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] = + server - dm->dhcp6_servers; + + server->server_fib6_index = + ip6_fib_table_find_or_create_and_lock(server_fib_id); + mfib_table_lock(rx_fib_index, FIB_PROTOCOL_IP6); + + const mfib_prefix_t all_dhcp_servers = { + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_grp_addr = { + .ip6 = dm->all_dhcpv6_server_relay_agent_address, + } + }; + const fib_route_path_t path_for_us = { + .frp_proto = FIB_PROTOCOL_IP6, + .frp_addr = zero_addr, + .frp_sw_if_index = 0xffffffff, + .frp_fib_index = ~0, + .frp_weight = 0, + .frp_flags = FIB_ROUTE_PATH_LOCAL, + }; + mfib_table_entry_path_update(rx_fib_index, + &all_dhcp_servers, + MFIB_SOURCE_DHCP, + &path_for_us, + MFIB_ITF_FLAG_FORWARD); + /* + * Each interface that is enabled in this table, needs to be added + * as an accepting interface, but this is not easily doable in VPP. + * So we cheat. Add a flag to the entry that indicates accept form + * any interface. + * We will still only accept on v6 enabled interfaces, since the + * input feature ensures this. + */ + mfib_table_entry_update(rx_fib_index, + &all_dhcp_servers, + MFIB_SOURCE_DHCP, + MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF); + } + copy_ip6_address(&server->dhcp6_server, addr); + copy_ip6_address(&server->dhcp6_src_address, src_address); + } + +out: + mfib_table_unlock(rx_fib_index, FIB_PROTOCOL_IP6); + + return (rc); } static clib_error_t * @@ -910,7 +924,7 @@ dhcpv6_proxy_set_command_fn (vlib_main_t * vm, ip6_address_t addr, src_addr; int set_server = 0, set_src_address = 0; u32 rx_fib_id = 0, server_fib_id = 0; - int is_del = 0, add_vss = 0; + int is_del = 0; while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { @@ -924,9 +938,6 @@ dhcpv6_proxy_set_command_fn (vlib_main_t * vm, ; else if (unformat (input, "rx-fib-id %d", &rx_fib_id)) ; - else if (unformat (input, "add-vss-option") - || unformat (input, "insert-option")) - add_vss = 1; else if (unformat (input, "delete") || unformat (input, "del")) is_del = 1; @@ -938,8 +949,8 @@ dhcpv6_proxy_set_command_fn (vlib_main_t * vm, { int rv; - rv = dhcpv6_proxy_set_server_2 (&addr, &src_addr, rx_fib_id, - server_fib_id, add_vss, is_del); + rv = dhcpv6_proxy_set_server (&addr, &src_addr, rx_fib_id, + server_fib_id, is_del); //TODO: Complete the errors switch (rv) @@ -962,7 +973,7 @@ dhcpv6_proxy_set_command_fn (vlib_main_t * vm, VLIB_CLI_COMMAND (dhcpv6_proxy_set_command, static) = { .path = "set dhcpv6 proxy", .short_help = "set dhcpv6 proxy [del] server src-address " - "[add-vss-option] [server-fib-id ] [rx-fib-id ] ", + "[server-fib-id ] [rx-fib-id ] ", .function = dhcpv6_proxy_set_command_fn, }; @@ -976,8 +987,8 @@ u8 * format_dhcpv6_proxy_server (u8 * s, va_list * args) if (dm == 0) { - s = format (s, "%=40s%=40s%=14s%=14s%=20s", "Server Address", "Source Address", - "Server FIB", "RX FIB", "Insert VSS Option"); + s = format (s, "%=40s%=40s%=14s%=14s", "Server Address", "Source Address", + "Server FIB", "RX FIB"); return s; } @@ -990,11 +1001,10 @@ u8 * format_dhcpv6_proxy_server (u8 * s, va_list * args) if (rx_fib) rx_fib_id = rx_fib->table_id; - s = format (s, "%=40U%=40U%=14u%=14u%=20s", + s = format (s, "%=40U%=40U%=14u%=14u", format_ip6_address, &server->dhcp6_server, format_ip6_address, &server->dhcp6_src_address, - server_fib_id, rx_fib_id, - server->insert_vss ? "yes" : "no"); + server_fib_id, rx_fib_id); return s; } @@ -1003,25 +1013,25 @@ dhcpv6_proxy_show_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; - ip6_main_t * im = &ip6_main; + dhcpv6_proxy_main_t * dpm = &dhcpv6_proxy_main; int i; u32 server_index; dhcpv6_server_t * server; vlib_cli_output (vm, "%U", format_dhcpv6_proxy_server, 0 /* header line */, 0, 0); - for (i = 0; i < vec_len (im->fibs); i++) - { - if (i < vec_len(dm->dhcp6_server_index_by_rx_fib_index)) - server_index = dm->dhcp6_server_index_by_rx_fib_index[i]; - else - server_index = 0; - server = pool_elt_at_index (dm->dhcp6_servers, server_index); - if (server->valid) - vlib_cli_output (vm, "%U", format_dhcpv6_proxy_server, dm, - server, i); - } + vec_foreach_index (i, dpm->dhcp6_server_index_by_rx_fib_index) + { + server_index = dpm->dhcp6_server_index_by_rx_fib_index[i]; + if (~0 == server_index) + continue; + + server = pool_elt_at_index (dpm->dhcp6_servers, server_index); + + vlib_cli_output (vm, "%U", format_dhcpv6_proxy_server, dpm, + server, i); + } + return 0; } @@ -1031,51 +1041,104 @@ VLIB_CLI_COMMAND (dhcpv6_proxy_show_command, static) = { .function = dhcpv6_proxy_show_command_fn, }; +void +dhcpv6_proxy_dump (void *opaque, + u32 context) +{ + dhcpv6_proxy_main_t * dpm = &dhcpv6_proxy_main; + ip6_fib_t *s_fib, *r_fib; + dhcpv6_server_t * server; + u32 server_index, i; + dhcpv6_vss_info *v; + + vec_foreach_index (i, dpm->dhcp6_server_index_by_rx_fib_index) + { + server_index = dpm->dhcp6_server_index_by_rx_fib_index[i]; + if (~0 == server_index) + continue; + + server = pool_elt_at_index (dpm->dhcp6_servers, server_index); + v = dhcpv6_get_vss_info(dpm, i); + + ip46_address_t src_addr = { + .ip6 = server->dhcp6_src_address, + }; + ip46_address_t server_addr = { + .ip6 = server->dhcp6_server, + }; + + s_fib = ip6_fib_get(server->server_fib6_index); + r_fib = ip6_fib_get(i); + + dhcp_send_details(opaque, + context, + &server_addr, + &src_addr, + s_fib->table_id, + r_fib->table_id, + (v ? v->vpn_id.fib_id : 0), + (v ? v->vpn_id.oui : 0)); + } +} + int dhcpv6_proxy_set_vss(u32 tbl_id, u32 oui, u32 fib_id, int is_del) { dhcpv6_proxy_main_t *dm = &dhcpv6_proxy_main; - u32 old_oui, old_fib_id; - uword *p; - dhcpv6_vss_info *v; + dhcpv6_vss_info *v = NULL; + u32 rx_fib_index; + int rc = 0; - p = hash_get (dm->vss_index_by_vrf_id, tbl_id); + rx_fib_index = ip6_fib_table_find_or_create_and_lock(tbl_id); + v = dhcpv6_get_vss_info(dm, rx_fib_index); - if (p) { - v = pool_elt_at_index (dm->vss, p[0]); - if (!v) - return VNET_API_ERROR_NO_SUCH_FIB; - - old_oui = v->vpn_id.oui; - old_fib_id = v->vpn_id.fib_id; + if (NULL != v) + { + if (is_del) + { + /* release the lock held on the table when the VSS + * info was created */ + fib_table_unlock (rx_fib_index, + FIB_PROTOCOL_IP6); + pool_put (dm->vss, v); + dm->vss_index_by_rx_fib_index[rx_fib_index] = ~0; + } + else + { + /* this is a modify */ + v->vpn_id.fib_id = fib_id; + v->vpn_id.oui = oui; + } + } + else + { if (is_del) + rc = VNET_API_ERROR_NO_SUCH_ENTRY; + else { - if (old_oui == oui && - old_fib_id == fib_id ) - { - pool_put(dm->vss, v); - hash_unset (dm->vss_index_by_vrf_id, tbl_id); - return 0; - } - else - return VNET_API_ERROR_NO_SUCH_ENTRY; + /* create a new entry */ + vec_validate_init_empty(dm->vss_index_by_rx_fib_index, + rx_fib_index, ~0); + + /* hold a lock on the table whilst the VSS info exist */ + fib_table_lock (rx_fib_index, + FIB_PROTOCOL_IP6); + + pool_get (dm->vss, v); + v->vpn_id.fib_id = fib_id; + v->vpn_id.oui = oui; + dm->vss_index_by_rx_fib_index[rx_fib_index] = v - dm->vss; } + } - pool_put(dm->vss, v); - hash_unset (dm->vss_index_by_vrf_id, tbl_id); - } else if (is_del) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - pool_get (dm->vss, v); - memset (v, ~0, sizeof (*v)); - v->vpn_id.fib_id = fib_id; - v->vpn_id.oui = oui; - hash_set (dm->vss_index_by_vrf_id, tbl_id, v - dm->vss); + /* Release the lock taken during the create_or_lock at the start */ + fib_table_unlock (rx_fib_index, + FIB_PROTOCOL_IP6); - return 0; + return (rc); } @@ -1147,19 +1210,19 @@ dhcpv6_vss_show_command_fn (vlib_main_t * vm, { dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; dhcpv6_vss_info *v; - u32 oui; - u32 fib_id; - u32 tbl_id; - uword index; + ip6_fib_t *fib; + u32 *fib_index; vlib_cli_output (vm, "%=6s%=6s%=12s","Table", "OUI", "VPN ID"); - hash_foreach (tbl_id, index, dm->vss_index_by_vrf_id, + pool_foreach (fib_index, dm->vss_index_by_rx_fib_index, ({ - v = pool_elt_at_index (dm->vss, index); - oui = v->vpn_id.oui; - fib_id = v->vpn_id.fib_id; - vlib_cli_output (vm, "%=6d%=6d%=12d", - tbl_id, oui, fib_id); + fib = ip6_fib_get (*fib_index); + v = pool_elt_at_index (dm->vss, *fib_index); + + vlib_cli_output (vm, "%=6d%=6d%=12d", + fib->table_id, + v->vpn_id.oui, + v->vpn_id.fib_id); })); return 0; diff --git a/src/vnet/dpo/receive_dpo.c b/src/vnet/dpo/receive_dpo.c index 2b2571c6..83e33ed8 100644 --- a/src/vnet/dpo/receive_dpo.c +++ b/src/vnet/dpo/receive_dpo.c @@ -102,6 +102,11 @@ format_receive_dpo (u8 *s, va_list *ap) vnet_main_t * vnm = vnet_get_main(); receive_dpo_t *rd; + if (pool_is_free_index(receive_dpo_pool, index)) + { + return (format(s, "dpo-receive DELETED")); + } + rd = receive_dpo_get(index); if (~0 != rd->rd_sw_if_index) diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index a7dca989..70b4e4c9 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -772,37 +772,6 @@ static void *vl_api_dhcp_proxy_config_t_print { u8 *s; - s = format (0, "SCRIPT: dhcp_proxy_config "); - - s = format (s, "vrf_id %d ", ntohl (mp->vrf_id)); - - if (mp->is_ipv6) - { - s = format (s, "svr %U ", format_ip6_address, - (ip6_address_t *) mp->dhcp_server); - s = format (s, "src %U ", format_ip6_address, - (ip6_address_t *) mp->dhcp_src_address); - } - else - { - s = format (s, "svr %U ", format_ip4_address, - (ip4_address_t *) mp->dhcp_server); - s = format (s, "src %U ", format_ip4_address, - (ip4_address_t *) mp->dhcp_src_address); - } - if (mp->is_add == 0) - s = format (s, "del "); - - s = format (s, "insert-cid %d ", mp->insert_circuit_id); - - FINISH; -} - -static void *vl_api_dhcp_proxy_config_2_t_print - (vl_api_dhcp_proxy_config_2_t * mp, void *handle) -{ - u8 *s; - s = format (0, "SCRIPT: dhcp_proxy_config_2 "); s = format (s, "rx_vrf_id %d ", ntohl (mp->rx_vrf_id)); @@ -825,8 +794,6 @@ static void *vl_api_dhcp_proxy_config_2_t_print if (mp->is_add == 0) s = format (s, "del "); - s = format (s, "insert-cid %d ", mp->insert_circuit_id); - FINISH; } @@ -2954,7 +2921,6 @@ _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ _(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_PROXY_CONFIG_2, dhcp_proxy_config_2) \ _(DHCP_CLIENT_CONFIG, dhcp_client_config) \ _(L2TPV3_CREATE_TUNNEL, l2tpv3_create_tunnel) \ _(L2TPV3_SET_TUNNEL_COOKIES, l2tpv3_set_tunnel_cookies) \ diff --git a/test/test_dhcp.py b/test/test_dhcp.py index 04ab2e11..fbfb8a0c 100644 --- a/test/test_dhcp.py +++ b/test/test_dhcp.py @@ -65,7 +65,7 @@ class TestDHCP(VppTestCase): for i in self.pg_interfaces: i.assert_nothing_captured(remark=remark) - def validate_option_82(self, pkt, intf, ip_addr): + def validate_relay_options(self, pkt, intf, ip_addr, fib_id, oui): dhcp = pkt[DHCP] found = 0 data = [] @@ -77,7 +77,10 @@ class TestDHCP(VppTestCase): # There are two sb-options present - each of length 6. # data = i[1] - self.assertEqual(len(data), 12) + if oui != 0: + self.assertEqual(len(data), 24) + else: + self.assertEqual(len(data), 12) # # First sub-option is ID 1, len 4, then encoded @@ -107,12 +110,30 @@ class TestDHCP(VppTestCase): self.assertEqual(data[10], claddr[2]) self.assertEqual(data[11], claddr[3]) + if oui != 0: + # sub-option 151 encodes the 3 byte oui + # and the 4 byte fib_id + 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) + found = 1 self.assertTrue(found) return data - def verify_dhcp_offer(self, pkt, intf, check_option_82=True): + def verify_dhcp_offer(self, pkt, intf): ether = pkt[Ether] self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") self.assertEqual(ether.src, intf.local_mac) @@ -134,11 +155,9 @@ class TestDHCP(VppTestCase): is_offer = True self.assertTrue(is_offer) - if check_option_82: - data = self.validate_option_82(pkt, intf, intf.local_ip4) + data = self.validate_relay_options(pkt, intf, intf.local_ip4, 0, 0) - def verify_dhcp_discover(self, pkt, intf, src_intf=None, - option_82_present=True): + def verify_dhcp_discover(self, pkt, intf, src_intf=None, fib_id=0, oui=0): ether = pkt[Ether] self.assertEqual(ether.dst, intf.remote_mac) self.assertEqual(ether.src, intf.local_mac) @@ -161,13 +180,10 @@ class TestDHCP(VppTestCase): is_discover = True self.assertTrue(is_discover) - if option_82_present: - data = self.validate_option_82(pkt, src_intf, src_intf.local_ip4) - return data - else: - for i in dhcp.options: - if type(i) is tuple: - self.assertNotEqual(i[0], "relay_agent_Information") + data = self.validate_relay_options(pkt, src_intf, + src_intf.local_ip4, + fib_id, oui) + return data def verify_dhcp6_solicit(self, pkt, intf, peer_ip, peer_mac, @@ -193,18 +209,19 @@ class TestDHCP(VppTestCase): self.assertEqual(cll.lltype, 1) self.assertEqual(cll.clladdr, peer_mac) - 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 fib_id != 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) # the relay message should be an encoded Solicit msg = pkt[DHCP6OptRelayMsg] @@ -267,29 +284,16 @@ class TestDHCP(VppTestCase): rx_table_id=0) # - # Now a DHCP request on pg2, which is in the same VRF - # as the DHCP config, will result in a relayed DHCP - # message to the [fake] server - # - self.pg2.add_stream(pkts_disc_vrf0) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - rx = self.pg0.get_capture(1) - rx = rx[0] - - # - # 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 + # Discover packets from the client are dropped because there is no + # IP address configured on the client facing interface # - self.verify_dhcp_discover(rx, self.pg0, option_82_present=False) + self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, + "Discover DHCP no relay address") # # Inject a response from the server - # VPP will only relay the offer if option 82 is present. - # so this one is dropped + # dropped, because there is no IP addrees on the + # clinet 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) / @@ -298,24 +302,8 @@ class TestDHCP(VppTestCase): DHCP(options=[('message-type', 'offer'), ('end')])) pkts = [p] - self.send_and_assert_no_replies(self.pg0, pkts, - "DHCP offer no option 82") - - # - # Configure sending option 82 in relayed messages - # - self.vapi.dhcp_proxy_config(server_addr, - src_addr, - rx_table_id=0, - insert_circuit_id=1) - - # - # Send a request: - # again dropped, but ths time because there is no IP addrees on the - # clinet interfce to fill in the option. - # - self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, - "DHCP no relay address") + self.send_and_assert_no_replies(self.pg2, pkts, + "Offer DHCP no relay address") # # configure an IP address on the client facing interface @@ -376,15 +364,8 @@ class TestDHCP(VppTestCase): ('relay_agent_Information', bad_ip), ('end')])) pkts = [p] - - self.pg0.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - rx = self.pg2.get_capture(1) - rx = rx[0] - - self.verify_dhcp_offer(rx, self.pg2, check_option_82=False) - self.pg0.assert_nothing_captured(remark="") + 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] + chr(33) + option_82[3:] @@ -413,8 +394,7 @@ class TestDHCP(VppTestCase): self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=0, - is_add=0, - insert_circuit_id=1) + is_add=0) self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, "DHCP config removed VRF 0") @@ -429,8 +409,7 @@ class TestDHCP(VppTestCase): self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=1, - server_table_id=1, - insert_circuit_id=1) + server_table_id=1) # # Confim DHCP requests ok in VRF 1. @@ -452,14 +431,41 @@ class TestDHCP(VppTestCase): rx = rx[0] self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3) + # + # Add VSS config + # table=1, fib=id=1, oui=4 + self.vapi.dhcp_proxy_set_vss(1, 1, 4) + + self.pg3.add_stream(pkts_disc_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + rx = rx[0] + self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3, + fib_id=1, oui=4) + + # + # Remove the VSS config + # relayed DHCP has default vlaues in the option. + # + self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_add=0) + + self.pg3.add_stream(pkts_disc_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + rx = rx[0] + self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3) + # # remove DHCP config to cleanup # self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=1, - server_table_id=1, - insert_circuit_id=1, + server_table_id=11, is_add=0) self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, @@ -510,7 +516,6 @@ class TestDHCP(VppTestCase): src_addr_vrf0, rx_table_id=0, server_table_id=0, - insert_circuit_id=1, is_ipv6=1) self.send_and_assert_no_replies(self.pg2, pkts_solicit_vrf0, @@ -630,7 +635,6 @@ class TestDHCP(VppTestCase): src_addr_vrf1, rx_table_id=1, server_table_id=1, - insert_circuit_id=1, is_ipv6=1) self.pg3.config_ip6() @@ -708,14 +712,12 @@ class TestDHCP(VppTestCase): src_addr_vrf1, rx_table_id=1, server_table_id=1, - insert_circuit_id=1, is_ipv6=1, is_add=0) self.vapi.dhcp_proxy_config(server_addr_vrf1, src_addr_vrf1, rx_table_id=0, server_table_id=0, - insert_circuit_id=1, is_ipv6=1, is_add=0) diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 32680424..59e58ad0 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -1240,16 +1240,14 @@ class VppPapiProvider(object): rx_table_id=0, server_table_id=0, is_add=1, - is_ipv6=0, - insert_circuit_id=0): + is_ipv6=0): return self.api( - self.papi.dhcp_proxy_config_2, + self.papi.dhcp_proxy_config, { 'rx_vrf_id': rx_table_id, 'server_vrf_id': server_table_id, 'is_ipv6': is_ipv6, 'is_add': is_add, - 'insert_circuit_id': insert_circuit_id, 'dhcp_server': dhcp_server, 'dhcp_src_address': dhcp_src_address, }) -- cgit 1.2.3-korg From 2dd6852d8109e39d15a5c60f7ba58f1abcf9e455 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 16 Feb 2017 03:38:59 -0800 Subject: Consolidate DHCP v4 and V6 implementation. No functional change intended The DHCP proxy and VSS information maintained by VPP is the same for v4 and v6, so we can manage this state using the same code. Packet handling is cleary different, so this is kept separate. Change-Id: I10f10cc1f7f19debcd4c4b099c6de64e56bb0c69 Signed-off-by: Neale Ranns --- src/vnet.am | 26 +- src/vnet/dhcp/client.c | 2 +- src/vnet/dhcp/client.h | 2 +- src/vnet/dhcp/dhcp4_packet.h | 61 ++ src/vnet/dhcp/dhcp4_proxy_error.def | 32 + src/vnet/dhcp/dhcp4_proxy_node.c | 983 +++++++++++++++++++++++++++ src/vnet/dhcp/dhcp6_packet.h | 183 +++++ src/vnet/dhcp/dhcp6_proxy_error.def | 29 + src/vnet/dhcp/dhcp6_proxy_node.c | 1065 +++++++++++++++++++++++++++++ src/vnet/dhcp/dhcp_api.c | 95 ++- src/vnet/dhcp/dhcp_proxy.c | 275 ++++++++ src/vnet/dhcp/dhcp_proxy.h | 248 +++++++ src/vnet/dhcp/packet.h | 61 -- src/vnet/dhcp/proxy.h | 99 --- src/vnet/dhcp/proxy_error.def | 31 - src/vnet/dhcp/proxy_node.c | 1192 -------------------------------- src/vnet/dhcpv6/packet.h | 183 ----- src/vnet/dhcpv6/proxy.h | 94 --- src/vnet/dhcpv6/proxy_error.def | 29 - src/vnet/dhcpv6/proxy_node.c | 1280 ----------------------------------- src/vpp/api/custom_dump.c | 3 +- test/test_dhcp.py | 2 +- 22 files changed, 2933 insertions(+), 3042 deletions(-) create mode 100644 src/vnet/dhcp/dhcp4_packet.h create mode 100644 src/vnet/dhcp/dhcp4_proxy_error.def create mode 100644 src/vnet/dhcp/dhcp4_proxy_node.c create mode 100644 src/vnet/dhcp/dhcp6_packet.h create mode 100644 src/vnet/dhcp/dhcp6_proxy_error.def create mode 100644 src/vnet/dhcp/dhcp6_proxy_node.c create mode 100644 src/vnet/dhcp/dhcp_proxy.c create mode 100644 src/vnet/dhcp/dhcp_proxy.h delete mode 100644 src/vnet/dhcp/packet.h delete mode 100644 src/vnet/dhcp/proxy.h delete mode 100644 src/vnet/dhcp/proxy_error.def delete mode 100644 src/vnet/dhcp/proxy_node.c delete mode 100644 src/vnet/dhcpv6/packet.h delete mode 100644 src/vnet/dhcpv6/proxy.h delete mode 100644 src/vnet/dhcpv6/proxy_error.def delete mode 100644 src/vnet/dhcpv6/proxy_node.c (limited to 'src/vnet/dhcp/dhcp_api.c') diff --git a/src/vnet.am b/src/vnet.am index 70f1e7e9..64484e18 100644 --- a/src/vnet.am +++ b/src/vnet.am @@ -674,7 +674,7 @@ libvnet_la_SOURCES += \ vnet/dhcp/dhcp_api.c nobase_include_HEADERS += \ - vnet/dhcp/client.h \ + vnet/dhcp/client.h \ vnet/dhcp/dhcp.api.h API_FILES += vnet/dhcp/dhcp.api @@ -683,13 +683,16 @@ API_FILES += vnet/dhcp/dhcp.api # DHCP proxy ######################################## libvnet_la_SOURCES += \ - vnet/dhcp/proxy_node.c \ - vnet/dhcp/proxy.h + vnet/dhcp/dhcp6_proxy_node.c \ + vnet/dhcp/dhcp4_proxy_node.c \ + vnet/dhcp/dhcp_proxy.c nobase_include_HEADERS += \ - vnet/dhcp/packet.h \ - vnet/dhcp/proxy.h \ - vnet/dhcp/proxy_error.def + vnet/dhcp/dhcp4_packet.h \ + vnet/dhcp/dhcp6_packet.h \ + vnet/dhcp/dhcp_proxy.h \ + vnet/dhcp/dhcp6_proxy_error.def \ + vnet/dhcp/dhcp4_proxy_error.def ######################################## # ipv6 segment routing @@ -709,17 +712,6 @@ nobase_include_HEADERS += \ API_FILES += vnet/sr/sr.api -######################################## -# DHCPv6 proxy -######################################## -libvnet_la_SOURCES += \ - vnet/dhcpv6/proxy_node.c - -nobase_include_HEADERS += \ - vnet/dhcpv6/packet.h \ - vnet/dhcpv6/proxy.h \ - vnet/dhcpv6/proxy_error.def - ######################################## # IPFIX / netflow v10 ######################################## diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index 8a1a43b3..d34c5a64 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -14,7 +14,7 @@ */ #include #include -#include +#include #include dhcp_client_main_t dhcp_client_main; diff --git a/src/vnet/dhcp/client.h b/src/vnet/dhcp/client.h index a74368cb..1f85d7ce 100644 --- a/src/vnet/dhcp/client.h +++ b/src/vnet/dhcp/client.h @@ -20,7 +20,7 @@ #define included_dhcp_client_h #include -#include +#include #define foreach_dhcp_client_state \ _(DHCP_DISCOVER) \ diff --git a/src/vnet/dhcp/dhcp4_packet.h b/src/vnet/dhcp/dhcp4_packet.h new file mode 100644 index 00000000..28c4b156 --- /dev/null +++ b/src/vnet/dhcp/dhcp4_packet.h @@ -0,0 +1,61 @@ +#ifndef included_vnet_dhcp4_packet_h +#define included_vnet_dhcp4_packet_h + +/* + * DHCP packet format + * + * Copyright (c) 2013 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 + +typedef struct { + u8 opcode; /* 1 = request, 2 = reply */ + u8 hardware_type; /* 1 = ethernet */ + u8 hardware_address_length; + u8 hops; + u32 transaction_identifier; + u16 seconds; + u16 flags; +#define DHCP_FLAG_BROADCAST (1<<15) + ip4_address_t client_ip_address; + ip4_address_t your_ip_address; /* use this one */ + ip4_address_t server_ip_address; + ip4_address_t gateway_ip_address; /* use option 3, not this one */ + u8 client_hardware_address[16]; + u8 server_name[64]; + u8 boot_filename[128]; + ip4_address_t magic_cookie; + u8 options[0]; +} dhcp_header_t; + +typedef struct { + u8 option; + u8 length; + union { + u8 data[0]; + u32 data_as_u32[0]; + }; +} __attribute__((packed)) dhcp_option_t; + +typedef enum { + DHCP_PACKET_DISCOVER=1, + DHCP_PACKET_OFFER, + DHCP_PACKET_REQUEST, + DHCP_PACKET_ACK=5, +} dhcp_packet_type_t; + +/* charming antique: 99.130.83.99 is the dhcp magic cookie */ +#define DHCP_MAGIC (clib_host_to_net_u32(0x63825363)) + +#endif /* included_vnet_dhcp4_packet_h */ diff --git a/src/vnet/dhcp/dhcp4_proxy_error.def b/src/vnet/dhcp/dhcp4_proxy_error.def new file mode 100644 index 00000000..adf04808 --- /dev/null +++ b/src/vnet/dhcp/dhcp4_proxy_error.def @@ -0,0 +1,32 @@ +/* + * dhcp_proxy_error.def: dhcp proxy errors + * + * Copyright (c) 2013 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. + */ + +dhcp_proxy_error (NONE, "no error") +dhcp_proxy_error (NO_SERVER, "no dhcp server configured") +dhcp_proxy_error (RELAY_TO_SERVER, "DHCP packets relayed to the server") +dhcp_proxy_error (RELAY_TO_CLIENT, "DHCP packets relayed to clients") +dhcp_proxy_error (OPTION_82_ERROR, "DHCP failed to insert option 82") +dhcp_proxy_error (NO_OPTION_82, "DHCP option 82 missing") +dhcp_proxy_error (BAD_OPTION_82_ITF, "Bad DHCP option 82 interface value") +dhcp_proxy_error (BAD_OPTION_82_ADDR, "Bad DHCP option 82 address value") +dhcp_proxy_error (BAD_FIB_ID, "DHCP option 82 fib-id to fib-index map failure") +dhcp_proxy_error (NO_INTERFACE_ADDRESS, "DHCP no interface address") +dhcp_proxy_error (OPTION_82_VSS_NOT_PROCESSED, "DHCP VSS not processed by DHCP server") +dhcp_proxy_error (BAD_YIADDR, "DHCP packets with bad your_ip_address fields") +dhcp_proxy_error (BAD_SVR_FIB_OR_ADDRESS, "DHCP packets not from DHCP server or server FIB.") +dhcp_proxy_error (PKT_TOO_BIG, "DHCP packets which are too big.") + diff --git a/src/vnet/dhcp/dhcp4_proxy_node.c b/src/vnet/dhcp/dhcp4_proxy_node.c new file mode 100644 index 00000000..88a99249 --- /dev/null +++ b/src/vnet/dhcp/dhcp4_proxy_node.c @@ -0,0 +1,983 @@ +/* + * proxy_node.c: dhcp proxy node processing + * + * Copyright (c) 2013 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 +#include +#include +#include +#include + +static char * dhcp_proxy_error_strings[] = { +#define dhcp_proxy_error(n,s) s, +#include +#undef dhcp_proxy_error +}; + +#define foreach_dhcp_proxy_to_server_input_next \ + _ (DROP, "error-drop") \ + _ (LOOKUP, "ip4-lookup") \ + _ (SEND_TO_CLIENT, "dhcp-proxy-to-client") + +typedef enum { +#define _(s,n) DHCP_PROXY_TO_SERVER_INPUT_NEXT_##s, + foreach_dhcp_proxy_to_server_input_next +#undef _ + DHCP_PROXY_TO_SERVER_INPUT_N_NEXT, +} dhcp_proxy_to_server_input_next_t; + +typedef struct { + /* 0 => to server, 1 => to client */ + int which; + ip4_address_t trace_ip4_address; + u32 error; + u32 sw_if_index; + u32 original_sw_if_index; +} dhcp_proxy_trace_t; + +#define VPP_DHCP_OPTION82_SUB1_SIZE 6 +#define VPP_DHCP_OPTION82_SUB5_SIZE 6 +#define VPP_DHCP_OPTION82_VSS_SIZE 12 +#define VPP_DHCP_OPTION82_SIZE (VPP_DHCP_OPTION82_SUB1_SIZE + \ + VPP_DHCP_OPTION82_SUB5_SIZE + \ + VPP_DHCP_OPTION82_VSS_SIZE +3) + +static vlib_node_registration_t dhcp_proxy_to_server_node; +static vlib_node_registration_t dhcp_proxy_to_client_node; + +static u8 * +format_dhcp_proxy_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + dhcp_proxy_trace_t * t = va_arg (*args, dhcp_proxy_trace_t *); + + if (t->which == 0) + s = format (s, "DHCP proxy: sent to server %U\n", + format_ip4_address, &t->trace_ip4_address, t->error); + else + s = format (s, "DHCP proxy: broadcast to client from %U\n", + format_ip4_address, &t->trace_ip4_address); + + if (t->error != (u32)~0) + s = format (s, " error: %s\n", dhcp_proxy_error_strings[t->error]); + + s = format (s, " original_sw_if_index: %d, sw_if_index: %d\n", + t->original_sw_if_index, t->sw_if_index); + + return s; +} + +static u8 * +format_dhcp_proxy_header_with_length (u8 * s, va_list * args) +{ + dhcp_header_t * h = va_arg (*args, dhcp_header_t *); + u32 max_header_bytes = va_arg (*args, u32); + u32 header_bytes; + + header_bytes = sizeof (h[0]); + if (max_header_bytes != 0 && header_bytes > max_header_bytes) + return format (s, "dhcp header truncated"); + + s = format (s, "DHCP Proxy"); + + return s; +} + +static uword +dhcp_proxy_to_server_input (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + u32 n_left_from, next_index, * from, * to_next; + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + u32 pkts_to_server=0, pkts_to_client=0, pkts_no_server=0; + u32 pkts_no_interface_address=0; + u32 pkts_too_big=0; + ip4_main_t * im = &ip4_main; + + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, + to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t * b0; + udp_header_t * u0; + dhcp_header_t * h0; + ip4_header_t * ip0; + u32 next0; + u32 old0, new0; + ip_csum_t sum0; + u32 error0 = (u32) ~0; + u32 sw_if_index = 0; + u32 original_sw_if_index = 0; + u8 *end = NULL; + u32 fib_index; + dhcp_server_t * server; + u32 rx_sw_if_index; + dhcp_option_t *o; + u32 len = 0; + vlib_buffer_free_list_t *fl; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + h0 = vlib_buffer_get_current (b0); + + /* + * udp_local hands us the DHCP header, need udp hdr, + * ip hdr to relay to server + */ + vlib_buffer_advance (b0, -(sizeof(*u0))); + u0 = vlib_buffer_get_current (b0); + + /* This blows. Return traffic has src_port = 67, dst_port = 67 */ + if (u0->src_port == clib_net_to_host_u16(UDP_DST_PORT_dhcp_to_server)) + { + vlib_buffer_advance (b0, sizeof(*u0)); + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT; + error0 = 0; + pkts_to_client++; + goto do_enqueue; + } + + rx_sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + + fib_index = im->fib_index_by_sw_if_index [rx_sw_if_index]; + server = dhcp_get_server(dpm, fib_index, FIB_PROTOCOL_IP4); + + if (PREDICT_FALSE (NULL == server)) + { + error0 = DHCP_PROXY_ERROR_NO_SERVER; + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_server++; + goto do_trace; + } + + vlib_buffer_advance (b0, -(sizeof(*ip0))); + ip0 = vlib_buffer_get_current (b0); + + /* disable UDP checksum */ + u0->checksum = 0; + sum0 = ip0->checksum; + old0 = ip0->dst_address.as_u32; + new0 = server->dhcp_server.ip4.as_u32; + ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32; + sum0 = ip_csum_update (sum0, old0, new0, + ip4_header_t /* structure */, + dst_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + sum0 = ip0->checksum; + old0 = ip0->src_address.as_u32; + new0 = server->dhcp_src_address.ip4.as_u32; + ip0->src_address.as_u32 = new0; + sum0 = ip_csum_update (sum0, old0, new0, + ip4_header_t /* structure */, + src_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + /* Send to DHCP server via the configured FIB */ + vnet_buffer(b0)->sw_if_index[VLIB_TX] = + server->server_fib_index; + + h0->gateway_ip_address.as_u32 = server->dhcp_src_address.ip4.as_u32; + pkts_to_server++; + + o = (dhcp_option_t *) h0->options; + + fib_index = im->fib_index_by_sw_if_index + [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; + + end = b0->data + b0->current_data + b0->current_length; + /* TLVs are not performance-friendly... */ + while (o->option != 0xFF /* end of options */ && (u8 *)o < end) + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + + fl = vlib_buffer_get_free_list (vm, b0->free_list_index); + // start write at (option*)o, some packets have padding + if (((u8 *)o - (u8 *)b0->data + VPP_DHCP_OPTION82_SIZE) > fl->n_data_bytes) + { + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_too_big++; + goto do_trace; + } + + if ((o->option == 0xFF) && ((u8 *)o <= end)) + { + vnet_main_t *vnm = vnet_get_main(); + u16 old_l0, new_l0; + ip4_address_t _ia0, * ia0 = &_ia0; + dhcp_vss_t *vss; + vnet_sw_interface_t *swif; + sw_if_index = 0; + original_sw_if_index = 0; + + original_sw_if_index = sw_if_index = + vnet_buffer(b0)->sw_if_index[VLIB_RX]; + swif = vnet_get_sw_interface (vnm, sw_if_index); + if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) + sw_if_index = swif->unnumbered_sw_if_index; + + /* + * Get the first ip4 address on the [client-side] + * RX interface, if not unnumbered. otherwise use + * the loopback interface's ip address. + */ + ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); + + if (ia0 == 0) + { + error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS; + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_interface_address++; + goto do_trace; + } + + /* Add option 82 */ + o->option = 82; /* option 82 */ + o->length = 12; /* 12 octets to follow */ + o->data[0] = 1; /* suboption 1, circuit ID (=FIB id) */ + o->data[1] = 4; /* length of suboption */ + o->data[2] = (original_sw_if_index >> 24) & 0xFF; + o->data[3] = (original_sw_if_index >> 16) & 0xFF; + o->data[4] = (original_sw_if_index >> 8) & 0xFF; + o->data[5] = (original_sw_if_index >> 0) & 0xFF; + o->data[6] = 5; /* suboption 5 (client RX intfc address) */ + o->data[7] = 4; /* length 4 */ + o->data[8] = ia0->as_u8[0]; + o->data[9] = ia0->as_u8[1]; + o->data[10] = ia0->as_u8[2]; + o->data[11] = ia0->as_u8[3]; + o->data[12] = 0xFF; + + vss = dhcp_get_vss_info (dpm, fib_index, FIB_PROTOCOL_IP4); + if (NULL != vss) + { + u32 opt82_fib_id=0, opt82_oui=0; + + opt82_oui = vss->oui; + opt82_fib_id = vss->fib_id; + + o->data[12] = 151; /* vss suboption */ + if (255 == opt82_fib_id) { + o->data[13] = 1; /* length */ + o->data[14] = 255; /* vss option type */ + o->data[15] = 152; /* vss control suboption */ + o->data[16] = 0; /* length */ + /* and a new "end-of-options" option (0xff) */ + o->data[17] = 0xFF; + o->length += 5; + } else { + o->data[13] = 8; /* length */ + o->data[14] = 1; /* vss option type */ + o->data[15] = (opt82_oui >> 16) & 0xff; + o->data[16] = (opt82_oui >> 8) & 0xff; + o->data[17] = (opt82_oui ) & 0xff; + o->data[18] = (opt82_fib_id >> 24) & 0xff; + o->data[19] = (opt82_fib_id >> 16) & 0xff; + o->data[20] = (opt82_fib_id >> 8) & 0xff; + o->data[21] = (opt82_fib_id) & 0xff; + o->data[22] = 152; /* vss control suboption */ + o->data[23] = 0; /* length */ + + /* and a new "end-of-options" option (0xff) */ + o->data[24] = 0xFF; + o->length += 12; + } + } + + len = o->length + 3; + b0->current_length += len; + /* Fix IP header length and checksum */ + old_l0 = ip0->length; + new_l0 = clib_net_to_host_u16 (old_l0); + new_l0 += len; + new_l0 = clib_host_to_net_u16 (new_l0); + ip0->length = new_l0; + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, + length /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + /* Fix UDP length */ + new_l0 = clib_net_to_host_u16 (u0->length); + new_l0 += len; + u0->length = clib_host_to_net_u16 (new_l0); + } else { + vlib_node_increment_counter + (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_OPTION_82_ERROR, 1); + } + + next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; + + do_trace: + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, + b0, sizeof (*tr)); + tr->which = 0; /* to server */ + tr->error = error0; + tr->original_sw_if_index = original_sw_if_index; + tr->sw_if_index = sw_if_index; + if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP) + tr->trace_ip4_address.as_u32 = server->dhcp_server.ip4.as_u32; + } + + do_enqueue: + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_RELAY_TO_CLIENT, + pkts_to_client); + vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_RELAY_TO_SERVER, + pkts_to_server); + vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_NO_SERVER, + pkts_no_server); + vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS, + pkts_no_interface_address); + vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, + DHCP_PROXY_ERROR_PKT_TOO_BIG, + pkts_too_big); + return from_frame->n_vectors; +} + +VLIB_REGISTER_NODE (dhcp_proxy_to_server_node, static) = { + .function = dhcp_proxy_to_server_input, + .name = "dhcp-proxy-to-server", + /* Takes a vector of packets. */ + .vector_size = sizeof (u32), + + .n_errors = DHCP_PROXY_N_ERROR, + .error_strings = dhcp_proxy_error_strings, + + .n_next_nodes = DHCP_PROXY_TO_SERVER_INPUT_N_NEXT, + .next_nodes = { +#define _(s,n) [DHCP_PROXY_TO_SERVER_INPUT_NEXT_##s] = n, + foreach_dhcp_proxy_to_server_input_next +#undef _ + }, + + .format_buffer = format_dhcp_proxy_header_with_length, + .format_trace = format_dhcp_proxy_trace, +#if 0 + .unformat_buffer = unformat_dhcp_proxy_header, +#endif +}; + +static uword +dhcp_proxy_to_client_input (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + u32 n_left_from, * from; + ethernet_main_t *em = ethernet_get_main (vm); + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + vnet_main_t * vnm = vnet_get_main(); + ip4_main_t * im = &ip4_main; + + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + + while (n_left_from > 0) + { + u32 bi0; + vlib_buffer_t * b0; + udp_header_t * u0; + dhcp_header_t * h0; + ip4_header_t * ip0 = 0; + ip4_address_t * ia0 = 0; + u32 old0, new0; + ip_csum_t sum0; + ethernet_interface_t *ei0; + ethernet_header_t *mac0; + vnet_hw_interface_t *hi0; + vlib_frame_t *f0; + u32 * to_next0; + u32 sw_if_index = ~0; + vnet_sw_interface_t *si0; + u32 error0 = (u32)~0; + vnet_sw_interface_t *swif; + u32 fib_index; + dhcp_server_t * server; + u32 original_sw_if_index = (u32) ~0; + ip4_address_t relay_addr = { + .as_u32 = 0, + }; + + bi0 = from[0]; + from += 1; + n_left_from -= 1; + + b0 = vlib_get_buffer (vm, bi0); + h0 = vlib_buffer_get_current (b0); + + /* + * udp_local hands us the DHCP header, need udp hdr, + * ip hdr to relay to client + */ + vlib_buffer_advance (b0, -(sizeof(*u0))); + u0 = vlib_buffer_get_current (b0); + + vlib_buffer_advance (b0, -(sizeof(*ip0))); + ip0 = vlib_buffer_get_current (b0); + + /* Consumed by dhcp client code? */ + if (dhcp_client_for_us (bi0, b0, ip0, u0, h0)) + continue; + + if (1 /* dpm->insert_option_82 */) + { + dhcp_option_t *o = (dhcp_option_t *) h0->options; + dhcp_option_t *sub; + + /* Parse through TLVs looking for option 82. + The circuit-ID is the FIB number we need + to track down the client-facing interface */ + + while (o->option != 0xFF /* end of options */ && + (u8 *) o < (b0->data + b0->current_data + b0->current_length)) + { + if (o->option == 82) + { + u32 vss_exist = 0; + u32 vss_ctrl = 0; + sub = (dhcp_option_t *) &o->data[0]; + while (sub->option != 0xFF /* end of options */ && + (u8 *) sub < (u8 *)(o + o->length)) { + /* If this is one of ours, it will have + total length 12, circuit-id suboption type, + and the sw_if_index */ + if (sub->option == 1 && sub->length == 4) + { + sw_if_index = ((sub->data[0] << 24) | + (sub->data[1] << 16) | + (sub->data[2] << 8) | + (sub->data[3])); + } + else if (sub->option == 5 && sub->length == 4) + { + relay_addr.as_u8[0] = sub->data[0]; + relay_addr.as_u8[1] = sub->data[1]; + relay_addr.as_u8[2] = sub->data[2]; + relay_addr.as_u8[3] = sub->data[3]; + } + else if (sub->option == 151 && + sub->length == 7 && + sub->data[0] == 1) + vss_exist = 1; + else if (sub->option == 152 && sub->length == 0) + vss_ctrl = 1; + sub = (dhcp_option_t *) + (((uword) sub) + (sub->length + 2)); + } + if (vss_ctrl && vss_exist) + vlib_node_increment_counter + (vm, dhcp_proxy_to_client_node.index, + DHCP_PROXY_ERROR_OPTION_82_VSS_NOT_PROCESSED, 1); + + } + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + } + } + + if (sw_if_index == (u32)~0) + { + error0 = DHCP_PROXY_ERROR_NO_OPTION_82; + + drop_packet: + vlib_node_increment_counter (vm, dhcp_proxy_to_client_node.index, + error0, 1); + f0 = vlib_get_frame_to_node (vm, dpm->error_drop_node_index); + to_next0 = vlib_frame_vector_args (f0); + to_next0[0] = bi0; + f0->n_vectors = 1; + vlib_put_frame_to_node (vm, dpm->error_drop_node_index, f0); + goto do_trace; + } + + if (relay_addr.as_u32 == 0) + { + error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ADDR; + goto drop_packet; + } + + if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index)) + { + error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ITF; + goto drop_packet; + } + + fib_index = im->fib_index_by_sw_if_index [sw_if_index]; + server = dhcp_get_server(dpm, fib_index, FIB_PROTOCOL_IP4); + + if (PREDICT_FALSE (NULL == server)) + { + error0 = DHCP_PROXY_ERROR_NO_SERVER; + goto drop_packet; + } + + if (ip0->src_address.as_u32 != server->dhcp_server.ip4.as_u32) + { + error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; + goto drop_packet; + } + + vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index; + + swif = vnet_get_sw_interface (vnm, sw_if_index); + original_sw_if_index = sw_if_index; + if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) + sw_if_index = swif->unnumbered_sw_if_index; + + ia0 = ip4_interface_first_address (&ip4_main, sw_if_index, 0); + if (ia0 == 0) + { + error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS; + goto drop_packet; + } + + if (relay_addr.as_u32 != ia0->as_u32) + { + error0 = DHCP_PROXY_ERROR_BAD_YIADDR; + goto drop_packet; + } + + u0->checksum = 0; + u0->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcp_to_client); + sum0 = ip0->checksum; + old0 = ip0->dst_address.as_u32; + new0 = 0xFFFFFFFF; + ip0->dst_address.as_u32 = new0; + sum0 = ip_csum_update (sum0, old0, new0, + ip4_header_t /* structure */, + dst_address /* offset of changed member */); + ip0->checksum = ip_csum_fold (sum0); + + sum0 = ip0->checksum; + old0 = ip0->src_address.as_u32; + new0 = ia0->as_u32; + ip0->src_address.as_u32 = new0; + sum0 = ip_csum_update (sum0, old0, new0, + ip4_header_t /* structure */, + src_address /* offset of changed member */); + ip0->checksum = ip_csum_fold (sum0); + + vlib_buffer_advance (b0, -(sizeof(ethernet_header_t))); + si0 = vnet_get_sw_interface (vnm, original_sw_if_index); + if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) + vlib_buffer_advance (b0, -4 /* space for VLAN tag */); + + mac0 = vlib_buffer_get_current (b0); + + hi0 = vnet_get_sup_hw_interface (vnm, original_sw_if_index); + ei0 = pool_elt_at_index (em->interfaces, hi0->hw_instance); + clib_memcpy (mac0->src_address, ei0->address, sizeof (ei0->address)); + memset (mac0->dst_address, 0xff, sizeof (mac0->dst_address)); + mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ? + clib_net_to_host_u16(0x8100) : clib_net_to_host_u16 (0x0800); + + if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) + { + u32 * vlan_tag = (u32 *)(mac0+1); + u32 tmp; + tmp = (si0->sub.id << 16) | 0x0800; + *vlan_tag = clib_host_to_net_u32 (tmp); + } + + /* $$$ This needs to be rewritten, for sure */ + f0 = vlib_get_frame_to_node (vm, hi0->output_node_index); + to_next0 = vlib_frame_vector_args (f0); + to_next0[0] = bi0; + f0->n_vectors = 1; + vlib_put_frame_to_node (vm, hi0->output_node_index, f0); + + do_trace: + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, + b0, sizeof (*tr)); + tr->which = 1; /* to client */ + tr->trace_ip4_address.as_u32 = ia0 ? ia0->as_u32 : 0; + tr->error = error0; + tr->original_sw_if_index = original_sw_if_index; + tr->sw_if_index = sw_if_index; + } + } + return from_frame->n_vectors; +} + +VLIB_REGISTER_NODE (dhcp_proxy_to_client_node, static) = { + .function = dhcp_proxy_to_client_input, + .name = "dhcp-proxy-to-client", + /* Takes a vector of packets. */ + .vector_size = sizeof (u32), + + .n_errors = DHCP_PROXY_N_ERROR, + .error_strings = dhcp_proxy_error_strings, + .format_buffer = format_dhcp_proxy_header_with_length, + .format_trace = format_dhcp_proxy_trace, +#if 0 + .unformat_buffer = unformat_dhcp_proxy_header, +#endif +}; + +static clib_error_t * +dhcp4_proxy_init (vlib_main_t * vm) +{ + dhcp_proxy_main_t * dm = &dhcp_proxy_main; + vlib_node_t * error_drop_node; + + error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); + dm->error_drop_node_index = error_drop_node->index; + + udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_client, + dhcp_proxy_to_client_node.index, 1 /* is_ip4 */); + + udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_server, + dhcp_proxy_to_server_node.index, 1 /* is_ip4 */); + + return 0; +} + + +VLIB_INIT_FUNCTION (dhcp4_proxy_init); + +int +dhcp4_proxy_set_server (ip46_address_t *addr, + ip46_address_t *src_addr, + u32 rx_table_id, + u32 server_table_id, + int is_del) +{ + u32 rx_fib_index = 0; + int rc = 0; + + const fib_prefix_t all_1s = + { + .fp_len = 32, + .fp_addr.ip4.as_u32 = 0xffffffff, + .fp_proto = FIB_PROTOCOL_IP4, + }; + + if (ip46_address_is_zero(addr)) + return VNET_API_ERROR_INVALID_DST_ADDRESS; + + if (ip46_address_is_zero(src_addr)) + return VNET_API_ERROR_INVALID_SRC_ADDRESS; + + rx_fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, + rx_table_id); + + if (is_del) + { + rc = dhcp_proxy_server_del (FIB_PROTOCOL_IP4, rx_fib_index); + + if (0 == rc) + { + fib_table_entry_special_remove(rx_fib_index, + &all_1s, + FIB_SOURCE_DHCP); + fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4); + } + } + else + { + if (dhcp_proxy_server_add (FIB_PROTOCOL_IP4, + addr, src_addr, + rx_fib_index, server_table_id)) + { + fib_table_entry_special_add(rx_fib_index, + &all_1s, + FIB_SOURCE_DHCP, + FIB_ENTRY_FLAG_LOCAL, + ADJ_INDEX_INVALID); + fib_table_lock (rx_fib_index, FIB_PROTOCOL_IP4); + } + } + fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4); + + return (rc); +} + +static clib_error_t * +dhcp4_proxy_set_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + ip46_address_t server_addr, src_addr; + u32 server_table_id = 0, rx_table_id = 0; + int is_del = 0; + int set_src = 0, set_server = 0; + + memset(&server_addr, 0, sizeof(server_addr)); + memset(&src_addr, 0, sizeof(src_addr)); + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "server %U", + unformat_ip4_address, &server_addr.ip4)) + set_server = 1; + else if (unformat (input, "server-fib-id %d", &server_table_id)) + ; + else if (unformat (input, "rx-fib-id %d", &rx_table_id)) + ; + else if (unformat(input, "src-address %U", + unformat_ip4_address, &src_addr.ip4)) + set_src = 1; + else if (unformat (input, "delete") || + unformat (input, "del")) + is_del = 1; + else + break; + } + + if (is_del || (set_server && set_src)) + { + int rv; + + rv = dhcp4_proxy_set_server (&server_addr, &src_addr, rx_table_id, + server_table_id, is_del); + switch (rv) + { + case 0: + return 0; + + case VNET_API_ERROR_INVALID_DST_ADDRESS: + return clib_error_return (0, "Invalid server address"); + + case VNET_API_ERROR_INVALID_SRC_ADDRESS: + return clib_error_return (0, "Invalid src address"); + + case VNET_API_ERROR_NO_SUCH_ENTRY: + return clib_error_return + (0, "Fib id %d: no per-fib DHCP server configured", rx_table_id); + + default: + return clib_error_return (0, "BUG: rv %d", rv); + } + } + else + return clib_error_return (0, "parse error`%U'", + format_unformat_error, input); +} + +VLIB_CLI_COMMAND (dhcp_proxy_set_command, static) = { + .path = "set dhcp proxy", + .short_help = "set dhcp proxy [del] server src-address [server-fib-id ] [rx-fib-id ]", + .function = dhcp4_proxy_set_command_fn, +}; + +static u8 * +format_dhcp4_proxy_server (u8 * s, va_list * args) +{ + dhcp_server_t * server = va_arg (*args, dhcp_server_t *); + ip4_fib_t * rx_fib, * server_fib; + + if (server == 0) + { + s = format (s, "%=16s%=16s%=14s%=14s", "Server", "Src Address", + "Server FIB", "RX FIB"); + return s; + } + + server_fib = ip4_fib_get(server->server_fib_index); + rx_fib = ip4_fib_get(server->rx_fib_index); + + s = format (s, "%=16U%=16U%=14u%=14u", + format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY, + format_ip46_address, &server->dhcp_src_address, IP46_TYPE_ANY, + server_fib->table_id, + rx_fib->table_id); + return s; +} + +static int +dhcp4_proxy_show_walk (dhcp_server_t *server, + void *ctx) +{ + vlib_main_t * vm = ctx; + + vlib_cli_output (vm, "%U", format_dhcp4_proxy_server, server); + + return (1); +} + +static clib_error_t * +dhcp4_proxy_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vlib_cli_output (vm, "%U", format_dhcp4_proxy_server, NULL /* header line */); + + dhcp_proxy_walk(FIB_PROTOCOL_IP4, dhcp4_proxy_show_walk, vm); + + return (NULL); +} + +VLIB_CLI_COMMAND (dhcp_proxy_show_command, static) = { + .path = "show dhcp proxy", + .short_help = "Display dhcp proxy server info", + .function = dhcp4_proxy_show_command_fn, +}; + +static clib_error_t * +dhcp_option_82_vss_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + int is_del = 0, got_new_vpn_id=0; + u32 oui=0, fib_id=0, tbl_id=~0; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + + if (unformat(input, "delete") || unformat(input, "del")) + is_del = 1; + else if (unformat (input, "oui %d", &oui)) + got_new_vpn_id = 1; + else if (unformat (input, "vpn-id %d", &fib_id)) + got_new_vpn_id = 1; + else if (unformat (input, "table %d", &tbl_id)) + got_new_vpn_id = 1; + else + break; + } + if (tbl_id == ~0) + return clib_error_return (0, "no table ID specified."); + + if (is_del || got_new_vpn_id) + { + int rv; + rv = dhcp_proxy_set_vss(FIB_PROTOCOL_IP4, tbl_id, oui, fib_id, is_del); + switch (rv) + { + case 0: + return 0; + + case VNET_API_ERROR_NO_SUCH_FIB: + return clib_error_return (0, "option 82 vss(oui:%d, vpn-id:%d) not found in table %d", + oui, fib_id, tbl_id); + + case VNET_API_ERROR_NO_SUCH_ENTRY: + return clib_error_return (0, "option 82 vss for table %d not found in in pool.", + tbl_id); + default: + return clib_error_return (0, "BUG: rv %d", rv); + } + } + else + return clib_error_return (0, "parse error`%U'", + format_unformat_error, input); +} + +VLIB_CLI_COMMAND (dhcp_proxy_vss_command,static) = { + .path = "set dhcp option-82 vss", + .short_help = "set dhcp option-82 vss [del] table oui vpn-id ", + .function = dhcp_option_82_vss_fn, +}; + +static clib_error_t * +dhcp_vss_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) + +{ + dhcp_vss_walk(FIB_PROTOCOL_IP4, dhcp_vss_show_walk, vm); + + return (NULL); +} + +VLIB_CLI_COMMAND (dhcp_proxy_vss_show_command, static) = { + .path = "show dhcp vss", + .short_help = "show dhcp VSS", + .function = dhcp_vss_show_command_fn, +}; + +static clib_error_t * +dhcp_option_82_address_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) + +{ + vnet_main_t *vnm = vnet_get_main(); + u32 sw_if_index0=0, sw_if_index; + vnet_sw_interface_t *swif; + ip4_address_t *ia0; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + + if (unformat(input, "%U", + unformat_vnet_sw_interface, vnm, &sw_if_index0)) + { + swif = vnet_get_sw_interface (vnm, sw_if_index0); + sw_if_index = (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) ? + swif->unnumbered_sw_if_index : sw_if_index0; + ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); + if (ia0) + { + vlib_cli_output (vm, "%=20s%=20s", "interface", + "source IP address"); + + vlib_cli_output (vm, "%=20U%=20U", + format_vnet_sw_if_index_name, + vnm, sw_if_index0, + format_ip4_address, ia0); + } + else + vlib_cli_output (vm, "%=34s %=20U", + "No IPv4 address configured on", + format_vnet_sw_if_index_name, + vnm, sw_if_index); + } + else + break; + } + + return 0; +} + +VLIB_CLI_COMMAND (dhcp_proxy_address_show_command,static) = { + .path = "show dhcp option-82-address interface", + .short_help = "show dhcp option-82-address interface ", + .function = dhcp_option_82_address_show_command_fn, +}; diff --git a/src/vnet/dhcp/dhcp6_packet.h b/src/vnet/dhcp/dhcp6_packet.h new file mode 100644 index 00000000..ddcde7a0 --- /dev/null +++ b/src/vnet/dhcp/dhcp6_packet.h @@ -0,0 +1,183 @@ +#ifndef included_vnet_dhcp6_packet_h +#define included_vnet_dhcp6_packet_h + +/* + * DHCP packet format + * + * Copyright (c) 2013 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 + +// #define DHCP_VRF_NAME_MAX_LEN L3VM_MAX_NAME_STR_LEN +// #define DHCPV6_MAX_VRF_NAME_LEN L3VM_MAX_NAME_STR_LEN +#define DHCP_MAX_RELAY_ADDR 16 +#define PROTO_UDP 17 +#define DHCPV6_CLIENT_PORT 546 +#define DHCPV6_SERVER_PORT 547 +#define HOP_COUNT_LIMIT 32 +#define DHCPV6_CISCO_ENT_NUM 9 + +/* + * DHCPv6 message types + */ +typedef enum dhcpv6_msg_type_{ + DHCPV6_MSG_SOLICIT = 1, + DHCPV6_MSG_ADVERTISE = 2, + DHCPV6_MSG_REQUEST = 3, + DHCPV6_MSG_CONFIRM = 4, + DHCPV6_MSG_RENEW = 5, + DHCPV6_MSG_REBIND = 6, + DHCPV6_MSG_REPLY = 7, + DHCPV6_MSG_RELEASE = 8, + DHCPV6_MSG_DECLINE = 9, + DHCPV6_MSG_RECONFIGURE = 10, + DHCPV6_MSG_INFORMATION_REQUEST = 11, + DHCPV6_MSG_RELAY_FORW = 12, + DHCPV6_MSG_RELAY_REPL = 13, +} dhcpv6_msg_type_t; + +/* + * DHCPv6 options types + */ +enum { + DHCPV6_OPTION_CLIENTID = 1, + DHCPV6_OPTION_SERVERID = 2, + DHCPV6_OPTION_IA_NA = 3, + DHCPV6_OPTION_IA_TA = 4, + DHCPV6_OPTION_IAADDR = 5, + DHCPV6_OPTION_ORO = 6, + DHCPV6_OPTION_PREFERENCE = 7, + DHCPV6_OPTION_ELAPSED_TIME = 8, + DHCPV6_OPTION_RELAY_MSG = 9, + DHCPV6_OPTION_AUTH = 11, + DHCPV6_OPTION_UNICAST = 12, + DHCPV6_OPTION_STATUS_CODE = 13, + DHCPV6_OPTION_RAPID_COMMIT = 14, + DHCPV6_OPTION_USER_CLASS = 15, + DHCPV6_OPTION_VENDOR_CLASS = 16, + DHCPV6_OPTION_VENDOR_OPTS = 17, + DHCPV6_OPTION_INTERFACE_ID = 18, // relay agent fills this + DHCPV6_OPTION_RECONF_MSG = 19, + DHCPV6_OPTION_RECONF_ACCEPT = 20, + DHCPV6_OPTION_REMOTEID = 37, // relay agent fills this + DHCPV6_OPTION_VSS = 68, // relay agent fills this + DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS = 79, + DHCPV6_OPTION_MAX +}; + +/* +* DHCPv6 status codes + */ +enum { + DHCPV6_STATUS_SUCCESS = 0, + DHCPV6_STATUS_UNSPEC_FAIL = 1, + DHCPV6_STATUS_NOADDRS_AVAIL = 2, + DHCPV6_STATUS_NO_BINDING = 3, + DHCPV6_STATUS_NOT_ONLINK = 4, + DHCPV6_STATUS_USE_MULTICAST = 5, +}; + +/* + * DHCPv6 DUID types + */ +enum { + DHCPV6_DUID_LLT = 1, /* DUID Based on Link-layer Address Plus Time */ + DHCPV6_DUID_EN = 2, /* DUID Based on Enterprise Number */ + DHCPV6_DUID_LL = 3, /* DUID Based on Link-layer Address */ +}; + +//Structure for DHCPv6 payload from client +typedef struct dhcpv6_hdr_ { + union { + u8 msg_type; //DHCP msg type + u32 xid; // transaction id + }u; + u8 data[0]; +} dhcpv6_header_t; + + + +typedef CLIB_PACKED (struct dhcpv6_relay_ctx_ { + dhcpv6_header_t *pkt; + u32 pkt_len; + u32 dhcpv6_len; //DHCPv6 payload load +// if_ordinal iod; + u32 if_index; + u32 ctx_id; + char ctx_name[32+1]; + u8 dhcp_msg_type; +}) dhcpv6_relay_ctx_t; + +//Structure for DHCPv6 RELAY-FORWARD and DHCPv6 RELAY-REPLY pkts +typedef CLIB_PACKED (struct dhcpv6_relay_hdr_ { + u8 msg_type; + u8 hop_count; + ip6_address_t link_addr; + ip6_address_t peer_addr; + u8 data[0]; +}) dhcpv6_relay_hdr_t; + +typedef enum dhcp_stats_action_type_ { + DHCP_STATS_ACTION_FORWARDED=1, + DHCP_STATS_ACTION_RECEIVED, + DHCP_STATS_ACTION_DROPPED +} dhcp_stats_action_type_t; +//Generic counters for a packet +typedef struct dhcp_stats_counters_ { + u64 rx_pkts; //counter for received pkts + u64 tx_pkts; //counter for forwarded pkts + u64 drops; //counter for dropped pkts +} dhcp_stats_counters_t; + + +typedef enum dhcpv6_stats_drop_reason_ { + DHCPV6_RELAY_PKT_DROP_RELAYDISABLE = 1, + DHCPV6_RELAY_PKT_DROP_MAX_HOPS, + DHCPV6_RELAY_PKT_DROP_VALIDATION_FAIL, + DHCPV6_RELAY_PKT_DROP_UNKNOWN_OP_INTF, + DHCPV6_RELAY_PKT_DROP_BAD_CONTEXT, + DHCPV6_RELAY_PKT_DROP_OPT_INSERT_FAIL, + DHCPV6_RELAY_PKT_DROP_REPLY_FROM_CLIENT, +} dhcpv6_stats_drop_reason_t; + +typedef CLIB_PACKED (struct { + u16 option; + u16 length; + u8 data[0]; +}) dhcpv6_option_t; + +typedef CLIB_PACKED (struct { + dhcpv6_option_t opt; + u32 int_idx; +}) dhcpv6_int_id_t; + +typedef CLIB_PACKED (struct { + dhcpv6_option_t opt; + u8 data[8]; // data[0]:type, data[1..7]: VPN ID +}) dhcpv6_vss_t; + +typedef CLIB_PACKED (struct { + dhcpv6_option_t opt; + u32 ent_num; + u32 rmt_id; +}) dhcpv6_rmt_id_t; + +typedef CLIB_PACKED (struct { + dhcpv6_option_t opt; + u16 link_type; + u8 data[6]; // data[0]:data[5]: MAC address +}) dhcpv6_client_mac_t; + + +#endif /* included_vnet_dhcp6_packet_h */ diff --git a/src/vnet/dhcp/dhcp6_proxy_error.def b/src/vnet/dhcp/dhcp6_proxy_error.def new file mode 100644 index 00000000..55fa7317 --- /dev/null +++ b/src/vnet/dhcp/dhcp6_proxy_error.def @@ -0,0 +1,29 @@ +/* + * dhcp_proxy_error.def: dhcp proxy errors + * + * Copyright (c) 2013 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. + */ + +dhcpv6_proxy_error (NONE, "no error") +dhcpv6_proxy_error (NO_SERVER, "no dhcpv6 server configured") +dhcpv6_proxy_error (RELAY_TO_SERVER, "DHCPV6 packets relayed to the server") +dhcpv6_proxy_error (RELAY_TO_CLIENT, "DHCPV6 packets relayed to clients") +dhcpv6_proxy_error (NO_INTERFACE_ADDRESS, "DHCPV6 no interface address") +dhcpv6_proxy_error (WRONG_MESSAGE_TYPE, "DHCPV6 wrong message type.") +dhcpv6_proxy_error (NO_SRC_ADDRESS, "DHCPV6 no srouce IPv6 address configured.") +dhcpv6_proxy_error (NO_CIRCUIT_ID_OPTION, "DHCPv6 reply packets without circuit ID option") +dhcpv6_proxy_error (NO_RELAY_MESSAGE_OPTION, "DHCPv6 reply packets without relay message option") +dhcpv6_proxy_error (BAD_SVR_FIB_OR_ADDRESS, "DHCPv6 packets not from DHCPv6 server or server FIB.") +dhcpv6_proxy_error (PKT_TOO_BIG, "DHCPv6 packets which are too big.") +dhcpv6_proxy_error (WRONG_INTERFACE_ID_OPTION, "DHCPv6 reply to invalid interface.") diff --git a/src/vnet/dhcp/dhcp6_proxy_node.c b/src/vnet/dhcp/dhcp6_proxy_node.c new file mode 100644 index 00000000..ed44977d --- /dev/null +++ b/src/vnet/dhcp/dhcp6_proxy_node.c @@ -0,0 +1,1065 @@ +/* + * dhcp6_proxy_node.c: dhcpv6 proxy node processing + * + * Copyright (c) 2013 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 +#include +#include +#include +#include +#include +#include + +static char * dhcpv6_proxy_error_strings[] = { +#define dhcpv6_proxy_error(n,s) s, +#include +#undef dhcpv6_proxy_error +}; + +#define foreach_dhcpv6_proxy_to_server_input_next \ + _ (DROP, "error-drop") \ + _ (LOOKUP, "ip6-lookup") \ + _ (SEND_TO_CLIENT, "dhcpv6-proxy-to-client") + + +typedef enum { +#define _(s,n) DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_##s, + foreach_dhcpv6_proxy_to_server_input_next +#undef _ + DHCPV6_PROXY_TO_SERVER_INPUT_N_NEXT, +} dhcpv6_proxy_to_server_input_next_t; + +typedef struct { + /* 0 => to server, 1 => to client */ + int which; + u8 packet_data[64]; + u32 error; + u32 sw_if_index; + u32 original_sw_if_index; +} dhcpv6_proxy_trace_t; + +static vlib_node_registration_t dhcpv6_proxy_to_server_node; +static vlib_node_registration_t dhcpv6_proxy_to_client_node; + +/* all DHCP servers address */ +static ip6_address_t all_dhcpv6_server_address; +static ip6_address_t all_dhcpv6_server_relay_agent_address; + +static u8 * +format_dhcpv6_proxy_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + dhcpv6_proxy_trace_t * t = va_arg (*args, dhcpv6_proxy_trace_t *); + + if (t->which == 0) + s = format (s, "DHCPV6 proxy: sent to server %U", + format_ip6_address, &t->packet_data, sizeof (ip6_address_t)); + else + s = format (s, "DHCPV6 proxy: sent to client from %U", + format_ip6_address, &t->packet_data, sizeof (ip6_address_t)); + if (t->error != (u32)~0) + s = format (s, " error: %s\n", dhcpv6_proxy_error_strings[t->error]); + + s = format (s, " original_sw_if_index: %d, sw_if_index: %d\n", + t->original_sw_if_index, t->sw_if_index); + + return s; +} + +static u8 * +format_dhcpv6_proxy_header_with_length (u8 * s, va_list * args) +{ + dhcpv6_header_t * h = va_arg (*args, dhcpv6_header_t *); + u32 max_header_bytes = va_arg (*args, u32); + u32 header_bytes; + + header_bytes = sizeof (h[0]); + if (max_header_bytes != 0 && header_bytes > max_header_bytes) + return format (s, "dhcpv6 header truncated"); + + s = format (s, "DHCPV6 Proxy"); + + return s; +} +/* get first interface address */ +static ip6_address_t * +ip6_interface_first_global_or_site_address (ip6_main_t * im, u32 sw_if_index) +{ + ip_lookup_main_t * lm = &im->lookup_main; + ip_interface_address_t * ia = 0; + ip6_address_t * result = 0; + + foreach_ip_interface_address (lm, ia, sw_if_index, + 1 /* honor unnumbered */, + ({ + ip6_address_t * a = ip_interface_address_get_address (lm, ia); + if ((a->as_u8[0] & 0xe0) == 0x20 || + (a->as_u8[0] & 0xfe) == 0xfc) { + result = a; + break; + } + })); + return result; +} + +static inline void copy_ip6_address (ip6_address_t *dst, + ip6_address_t *src) +{ + dst->as_u64[0] = src->as_u64[0]; + dst->as_u64[1] = src->as_u64[1]; +} + +static uword +dhcpv6_proxy_to_server_input (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + u32 n_left_from, next_index, * from, * to_next; + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + u32 pkts_to_server=0, pkts_to_client=0, pkts_no_server=0; + u32 pkts_no_interface_address=0, pkts_no_exceeding_max_hop=0; + u32 pkts_no_src_address=0; + u32 pkts_wrong_msg_type=0; + u32 pkts_too_big=0; + ip6_main_t * im = &ip6_main; + ip6_address_t * src; + int bogus_length; + dhcp_server_t * server; + u32 rx_fib_idx = 0, server_fib_idx = 0; + + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, + to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + vnet_main_t *vnm = vnet_get_main(); + u32 sw_if_index = 0; + u32 rx_sw_if_index = 0; + vnet_sw_interface_t *swif; + u32 bi0; + vlib_buffer_t * b0; + udp_header_t * u0, *u1; + dhcpv6_header_t * h0; // client msg hdr + ip6_header_t * ip0, *ip1; + ip6_address_t _ia0, *ia0=&_ia0; + u32 next0; + u32 error0 = (u32) ~0; + dhcpv6_option_t *fwd_opt; + dhcpv6_relay_hdr_t *r1; + u16 len; + dhcpv6_int_id_t *id1; + dhcpv6_vss_t *vss1; + dhcpv6_client_mac_t *cmac; // client mac + ethernet_header_t * e_h0; + u8 client_src_mac[6]; + vlib_buffer_free_list_t *fl; + dhcp_vss_t *vss; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + h0 = vlib_buffer_get_current (b0); + + /* + * udp_local hands us the DHCPV6 header. + */ + u0 = (void *)h0 -(sizeof(*u0)); + ip0 = (void *)u0 -(sizeof(*ip0)); + e_h0 = (void *)ip0 - ethernet_buffer_header_size(b0); + + clib_memcpy(client_src_mac, e_h0->src_address, 6); + + switch (h0->u.msg_type) { + case DHCPV6_MSG_SOLICIT: + case DHCPV6_MSG_REQUEST: + case DHCPV6_MSG_CONFIRM: + case DHCPV6_MSG_RENEW: + case DHCPV6_MSG_REBIND: + case DHCPV6_MSG_RELEASE: + case DHCPV6_MSG_DECLINE: + case DHCPV6_MSG_INFORMATION_REQUEST: + case DHCPV6_MSG_RELAY_FORW: + /* send to server */ + break; + case DHCPV6_MSG_RELAY_REPL: + /* send to client */ + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT; + error0 = 0; + pkts_to_client++; + goto do_enqueue; + default: + /* drop the packet */ + pkts_wrong_msg_type++; + error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + goto do_trace; + + } + + /* Send to DHCPV6 server via the configured FIB */ + rx_sw_if_index = sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + rx_fib_idx = im->fib_index_by_sw_if_index [rx_sw_if_index]; + server = dhcp_get_server(dpm, rx_fib_idx, FIB_PROTOCOL_IP6); + + if (PREDICT_FALSE (NULL == server)) + { + error0 = DHCPV6_PROXY_ERROR_NO_SERVER; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_server++; + goto do_trace; + } + + server_fib_idx = server->server_fib_index; + vnet_buffer(b0)->sw_if_index[VLIB_TX] = server_fib_idx; + + + /* relay-option header pointer */ + vlib_buffer_advance(b0, -(sizeof(*fwd_opt))); + fwd_opt = vlib_buffer_get_current(b0); + /* relay message header pointer */ + vlib_buffer_advance(b0, -(sizeof(*r1))); + r1 = vlib_buffer_get_current(b0); + + vlib_buffer_advance(b0, -(sizeof(*u1))); + u1 = vlib_buffer_get_current(b0); + + vlib_buffer_advance(b0, -(sizeof(*ip1))); + ip1 = vlib_buffer_get_current(b0); + + /* fill in all that rubbish... */ + len = clib_net_to_host_u16(u0->length) - sizeof(udp_header_t); + copy_ip6_address(&r1->peer_addr, &ip0->src_address); + + r1->msg_type = DHCPV6_MSG_RELAY_FORW; + fwd_opt->length = clib_host_to_net_u16(len); + fwd_opt->option = clib_host_to_net_u16(DHCPV6_OPTION_RELAY_MSG); + + r1->hop_count++; + r1->hop_count = (h0->u.msg_type != DHCPV6_MSG_RELAY_FORW) ? 0 : r1->hop_count; + + if (PREDICT_FALSE(r1->hop_count >= HOP_COUNT_LIMIT)) + { + error0 = DHCPV6_RELAY_PKT_DROP_MAX_HOPS; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_exceeding_max_hop++; + goto do_trace; + } + + + /* If relay-fwd and src address is site or global unicast address */ + if (h0->u.msg_type == DHCPV6_MSG_RELAY_FORW && + ((ip0->src_address.as_u8[0] & 0xe0) == 0x20 || + (ip0->src_address.as_u8[0] & 0xfe) == 0xfc)) + { + /* Set link address to zero */ + r1->link_addr.as_u64[0] = 0; + r1->link_addr.as_u64[1] = 0; + goto link_address_set; + } + + /* if receiving interface is unnumbered, use receiving interface + * IP address as link address, otherwise use the loopback interface + * IP address as link address. + */ + + swif = vnet_get_sw_interface (vnm, rx_sw_if_index); + if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) + sw_if_index = swif->unnumbered_sw_if_index; + + ia0 = ip6_interface_first_global_or_site_address(&ip6_main, sw_if_index); + if (ia0 == 0) + { + error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_interface_address++; + goto do_trace; + } + + copy_ip6_address(&r1->link_addr, ia0); + + link_address_set: + fl = vlib_buffer_get_free_list (vm, b0->free_list_index); + + if ((b0->current_length+sizeof(*id1)+sizeof(*vss1)+sizeof(*cmac)) + > fl->n_data_bytes) + { + error0 = DHCPV6_PROXY_ERROR_PKT_TOO_BIG; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_too_big++; + goto do_trace; + } + + id1 = (dhcpv6_int_id_t *) (((uword) ip1) + b0->current_length); + b0->current_length += (sizeof (*id1)); + + id1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_INTERFACE_ID); + id1->opt.length = clib_host_to_net_u16(sizeof(rx_sw_if_index)); + id1->int_idx = clib_host_to_net_u32(rx_sw_if_index); + + u1->length =0; + if (h0->u.msg_type != DHCPV6_MSG_RELAY_FORW) + { + cmac = (dhcpv6_client_mac_t *) (((uword) ip1) + b0->current_length); + b0->current_length += (sizeof (*cmac)); + cmac->opt.length =clib_host_to_net_u16(sizeof(*cmac) - + sizeof(cmac->opt)); + cmac->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS); + cmac->link_type = clib_host_to_net_u16(1); // ethernet + clib_memcpy(cmac->data, client_src_mac, 6); + u1->length += sizeof(*cmac); + } + + vss = dhcp_get_vss_info(dpm, rx_fib_idx, FIB_PROTOCOL_IP6); + + if (NULL != vss) { + vss1 = (dhcpv6_vss_t *) (((uword) ip1) + b0->current_length); + b0->current_length += (sizeof (*vss1)); + vss1->opt.length =clib_host_to_net_u16(sizeof(*vss1) - + sizeof(vss1->opt)); + vss1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_VSS); + vss1->data[0] = 1; // type + vss1->data[1] = vss->oui >>16 & 0xff; + vss1->data[2] = vss->oui >>8 & 0xff; + vss1->data[3] = vss->oui & 0xff; + vss1->data[4] = vss->fib_id >> 24 & 0xff; + vss1->data[5] = vss->fib_id >> 16 & 0xff; + vss1->data[6] = vss->fib_id >> 8 & 0xff; + vss1->data[7] = vss->fib_id & 0xff; + u1->length += sizeof(*vss1); + } + + pkts_to_server++; + u1->checksum = 0; + u1->src_port = clib_host_to_net_u16(UDP_DST_PORT_dhcpv6_to_client); + u1->dst_port = clib_host_to_net_u16(UDP_DST_PORT_dhcpv6_to_server); + + u1->length = + clib_host_to_net_u16( clib_net_to_host_u16(fwd_opt->length) + + sizeof(*r1) + sizeof(*fwd_opt) + + sizeof(*u1) + sizeof(*id1) + u1->length); + + memset(ip1, 0, sizeof(*ip1)); + ip1->ip_version_traffic_class_and_flow_label = 0x60; + ip1->payload_length = u1->length; + ip1->protocol = PROTO_UDP; + ip1->hop_limit = HOP_COUNT_LIMIT; + src = (server->dhcp_server.ip6.as_u64[0] || + server->dhcp_server.ip6.as_u64[1]) ? + &server->dhcp_server.ip6 : &all_dhcpv6_server_address; + copy_ip6_address(&ip1->dst_address, src); + + + ia0 = ip6_interface_first_global_or_site_address + (&ip6_main, vnet_buffer(b0)->sw_if_index[VLIB_RX]); + + src = (server->dhcp_src_address.ip6.as_u64[0] || + server->dhcp_src_address.ip6.as_u64[1]) ? + &server->dhcp_src_address.ip6 : ia0; + if (ia0 == 0) + { + error0 = DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS; + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; + pkts_no_src_address++; + goto do_trace; + } + + copy_ip6_address (&ip1->src_address, src); + + + u1->checksum = ip6_tcp_udp_icmp_compute_checksum(vm, b0, ip1, + &bogus_length); + ASSERT(bogus_length == 0); + + next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; + + do_trace: + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + dhcpv6_proxy_trace_t *tr = vlib_add_trace (vm, node, + b0, sizeof (*tr)); + tr->which = 0; /* to server */ + tr->error = error0; + tr->original_sw_if_index = rx_sw_if_index; + tr->sw_if_index = sw_if_index; + if (DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP == next0) + copy_ip6_address((ip6_address_t *)&tr->packet_data[0], &server->dhcp_server.ip6); + } + + do_enqueue: + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, + DHCPV6_PROXY_ERROR_RELAY_TO_CLIENT, + pkts_to_client); + vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, + DHCPV6_PROXY_ERROR_RELAY_TO_SERVER, + pkts_to_server); + vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, + DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS, + pkts_no_interface_address); + vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, + DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE, + pkts_wrong_msg_type); + vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, + DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS, + pkts_no_src_address); + vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, + DHCPV6_PROXY_ERROR_PKT_TOO_BIG, + pkts_too_big); + return from_frame->n_vectors; +} + +VLIB_REGISTER_NODE (dhcpv6_proxy_to_server_node, static) = { + .function = dhcpv6_proxy_to_server_input, + .name = "dhcpv6-proxy-to-server", + /* Takes a vector of packets. */ + .vector_size = sizeof (u32), + + .n_errors = DHCPV6_PROXY_N_ERROR, + .error_strings = dhcpv6_proxy_error_strings, + + .n_next_nodes = DHCPV6_PROXY_TO_SERVER_INPUT_N_NEXT, + .next_nodes = { +#define _(s,n) [DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_##s] = n, + foreach_dhcpv6_proxy_to_server_input_next +#undef _ + }, + + .format_buffer = format_dhcpv6_proxy_header_with_length, + .format_trace = format_dhcpv6_proxy_trace, +#if 0 + .unformat_buffer = unformat_dhcpv6_proxy_header, +#endif +}; + +static uword +dhcpv6_proxy_to_client_input (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + + u32 n_left_from, * from; + ethernet_main_t *em = ethernet_get_main (vm); + dhcp_proxy_main_t * dm = &dhcp_proxy_main; + dhcp_server_t * server; + vnet_main_t * vnm = vnet_get_main(); + int bogus_length; + + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + + while (n_left_from > 0) + { + u32 bi0; + vlib_buffer_t * b0; + udp_header_t * u0, *u1=0; + dhcpv6_relay_hdr_t * h0; + ip6_header_t * ip1 = 0, *ip0; + ip6_address_t _ia0, * ia0 = &_ia0; + ip6_address_t client_address; + ethernet_interface_t *ei0; + ethernet_header_t *mac0; + vnet_hw_interface_t *hi0; + vlib_frame_t *f0; + u32 * to_next0; + u32 sw_if_index = ~0; + u32 original_sw_if_index = ~0; + vnet_sw_interface_t *si0; + u32 error0 = (u32)~0; + vnet_sw_interface_t *swif; + dhcpv6_option_t *r0 = 0, *o; + u16 len = 0; + u8 interface_opt_flag = 0; + u8 relay_msg_opt_flag = 0; + ip6_main_t * im = &ip6_main; + u32 server_fib_idx, client_fib_idx; + + bi0 = from[0]; + from += 1; + n_left_from -= 1; + + b0 = vlib_get_buffer (vm, bi0); + h0 = vlib_buffer_get_current (b0); + + if (DHCPV6_MSG_RELAY_REPL != h0->msg_type) + { + error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE; + + drop_packet: + vlib_node_increment_counter (vm, dhcpv6_proxy_to_client_node.index, + error0, 1); + + f0 = vlib_get_frame_to_node (vm, dm->error_drop_node_index); + to_next0 = vlib_frame_vector_args (f0); + to_next0[0] = bi0; + f0->n_vectors = 1; + vlib_put_frame_to_node (vm, dm->error_drop_node_index, f0); + goto do_trace; + } + /* hop count seems not need to be checked */ + if (HOP_COUNT_LIMIT < h0->hop_count) + { + error0 = DHCPV6_RELAY_PKT_DROP_MAX_HOPS; + goto drop_packet; + } + u0 = (void *)h0 -(sizeof(*u0)); + ip0 = (void *)u0 -(sizeof(*ip0)); + + vlib_buffer_advance (b0, sizeof(*h0)); + o = vlib_buffer_get_current (b0); + + /* Parse through TLVs looking for option 18 (DHCPV6_OPTION_INTERFACE_ID) + _and_ option 9 (DHCPV6_OPTION_RELAY_MSG) option which must be there. + Currently assuming no other options need to be processed + The interface-ID is the FIB number we need + to track down the client-facing interface */ + + while ((u8 *) o < (b0->data + b0->current_data + b0->current_length)) + { + if (DHCPV6_OPTION_INTERFACE_ID == clib_net_to_host_u16(o->option)) + { + interface_opt_flag = 1; + if (clib_net_to_host_u16(o->length) == sizeof(sw_if_index)) + sw_if_index = clib_net_to_host_u32(((dhcpv6_int_id_t*)o)->int_idx); + if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index)) + { + error0 = DHCPV6_PROXY_ERROR_WRONG_INTERFACE_ID_OPTION; + goto drop_packet; + } + } + if (DHCPV6_OPTION_RELAY_MSG == clib_net_to_host_u16(o->option)) + { + relay_msg_opt_flag = 1; + r0 = vlib_buffer_get_current (b0); + } + if ((relay_msg_opt_flag == 1) && (interface_opt_flag == 1)) + break; + vlib_buffer_advance (b0, sizeof(*o) + clib_net_to_host_u16(o->length)); + o = (dhcpv6_option_t *) (((uword) o) + clib_net_to_host_u16(o->length) + sizeof(*o)); + } + + if ((relay_msg_opt_flag == 0) || (r0 == 0)) + { + error0 = DHCPV6_PROXY_ERROR_NO_RELAY_MESSAGE_OPTION; + goto drop_packet; + } + + if ((u32)~0 == sw_if_index) + { + error0 = DHCPV6_PROXY_ERROR_NO_CIRCUIT_ID_OPTION; + goto drop_packet; + } + + //Advance buffer to start of encapsulated DHCPv6 message + vlib_buffer_advance (b0, sizeof(*r0)); + + client_fib_idx = im->fib_index_by_sw_if_index[sw_if_index]; + server = dhcp_get_server(dm, client_fib_idx, FIB_PROTOCOL_IP6); + + if (NULL == server) + { + error0 = DHCPV6_PROXY_ERROR_NO_SERVER; + goto drop_packet; + } + + server_fib_idx = im->fib_index_by_sw_if_index + [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; + + if (server_fib_idx != server->server_fib_index || + ip0->src_address.as_u64[0] != server->dhcp_server.ip6.as_u64[0] || + ip0->src_address.as_u64[1] != server->dhcp_server.ip6.as_u64[1]) + { + //drop packet if not from server with configured address or FIB + error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; + goto drop_packet; + } + + vnet_buffer (b0)->sw_if_index[VLIB_TX] = original_sw_if_index + = sw_if_index; + + swif = vnet_get_sw_interface (vnm, original_sw_if_index); + if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) + sw_if_index = swif->unnumbered_sw_if_index; + + + /* + * udp_local hands us the DHCPV6 header, need udp hdr, + * ip hdr to relay to client + */ + vlib_buffer_advance (b0, -(sizeof(*u1))); + u1 = vlib_buffer_get_current (b0); + + vlib_buffer_advance (b0, -(sizeof(*ip1))); + ip1 = vlib_buffer_get_current (b0); + + copy_ip6_address(&client_address, &h0->peer_addr); + + ia0 = ip6_interface_first_address (&ip6_main, sw_if_index); + if (ia0 == 0) + { + error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS; + goto drop_packet; + } + + len = clib_net_to_host_u16(r0->length); + memset(ip1, 0, sizeof(*ip1)); + copy_ip6_address(&ip1->dst_address, &client_address); + u1->checksum = 0; + u1->src_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcpv6_to_server); + u1->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcpv6_to_client); + u1->length = clib_host_to_net_u16 (len + sizeof(udp_header_t)); + + ip1->ip_version_traffic_class_and_flow_label = + ip0->ip_version_traffic_class_and_flow_label & + 0x00000fff; + ip1->payload_length = u1->length; + ip1->protocol = PROTO_UDP; + ip1->hop_limit = HOP_COUNT_LIMIT; + copy_ip6_address(&ip1->src_address, ia0); + + u1->checksum = ip6_tcp_udp_icmp_compute_checksum(vm, b0, ip1, + &bogus_length); + ASSERT(bogus_length == 0); + + vlib_buffer_advance (b0, -(sizeof(ethernet_header_t))); + si0 = vnet_get_sw_interface (vnm, original_sw_if_index); + if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) + vlib_buffer_advance (b0, -4 /* space for VLAN tag */); + + mac0 = vlib_buffer_get_current (b0); + + hi0 = vnet_get_sup_hw_interface (vnm, original_sw_if_index); + ei0 = pool_elt_at_index (em->interfaces, hi0->hw_instance); + clib_memcpy (mac0->src_address, ei0->address, sizeof (ei0->address)); + memset (&mac0->dst_address, 0xff, sizeof (mac0->dst_address)); + mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ? + clib_net_to_host_u16(0x8100) : clib_net_to_host_u16 (0x86dd); + + if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) + { + u32 * vlan_tag = (u32 *)(mac0+1); + u32 tmp; + tmp = (si0->sub.id << 16) | 0x0800; + *vlan_tag = clib_host_to_net_u32 (tmp); + } + + /* $$$ consider adding a dynamic next to the graph node, for performance */ + f0 = vlib_get_frame_to_node (vm, hi0->output_node_index); + to_next0 = vlib_frame_vector_args (f0); + to_next0[0] = bi0; + f0->n_vectors = 1; + vlib_put_frame_to_node (vm, hi0->output_node_index, f0); + + do_trace: + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + dhcpv6_proxy_trace_t *tr = vlib_add_trace (vm, node, + b0, sizeof (*tr)); + tr->which = 1; /* to client */ + if (ia0) + copy_ip6_address((ip6_address_t*)tr->packet_data, ia0); + tr->error = error0; + tr->original_sw_if_index = original_sw_if_index; + tr->sw_if_index = sw_if_index; + } + } + return from_frame->n_vectors; + +} + +VLIB_REGISTER_NODE (dhcpv6_proxy_to_client_node, static) = { + .function = dhcpv6_proxy_to_client_input, + .name = "dhcpv6-proxy-to-client", + /* Takes a vector of packets. */ + .vector_size = sizeof (u32), + + .n_errors = DHCPV6_PROXY_N_ERROR, + .error_strings = dhcpv6_proxy_error_strings, + .format_buffer = format_dhcpv6_proxy_header_with_length, + .format_trace = format_dhcpv6_proxy_trace, +#if 0 + .unformat_buffer = unformat_dhcpv6_proxy_header, +#endif +}; + +static clib_error_t * +dhcp6_proxy_init (vlib_main_t * vm) +{ + dhcp_proxy_main_t * dm = &dhcp_proxy_main; + vlib_node_t * error_drop_node; + + error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); + dm->error_drop_node_index = error_drop_node->index; + + /* RFC says this is the dhcpv6 server address */ + all_dhcpv6_server_address.as_u64[0] = clib_host_to_net_u64 (0xFF05000000000000); + all_dhcpv6_server_address.as_u64[1] = clib_host_to_net_u64 (0x00010003); + + /* RFC says this is the server and agent address */ + all_dhcpv6_server_relay_agent_address.as_u64[0] = clib_host_to_net_u64 (0xFF02000000000000); + all_dhcpv6_server_relay_agent_address.as_u64[1] = clib_host_to_net_u64 (0x00010002); + + udp_register_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client, + dhcpv6_proxy_to_client_node.index, 0 /* is_ip6 */); + + udp_register_dst_port (vm, UDP_DST_PORT_dhcpv6_to_server, + dhcpv6_proxy_to_server_node.index, 0 /* is_ip6 */); + + return 0; +} + +VLIB_INIT_FUNCTION (dhcp6_proxy_init); + +int +dhcp6_proxy_set_server (ip46_address_t *addr, + ip46_address_t *src_addr, + u32 rx_table_id, + u32 server_table_id, + int is_del) +{ + u32 rx_fib_index = 0; + int rc = 0; + + const mfib_prefix_t all_dhcp_servers = { + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_grp_addr = { + .ip6 = all_dhcpv6_server_relay_agent_address, + } + }; + + if (ip46_address_is_zero(addr)) + return VNET_API_ERROR_INVALID_DST_ADDRESS; + + if (ip46_address_is_zero(src_addr)) + return VNET_API_ERROR_INVALID_SRC_ADDRESS; + + rx_fib_index = mfib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, + rx_table_id); + + if (is_del) + { + rc = dhcp_proxy_server_del (FIB_PROTOCOL_IP6, rx_fib_index); + + if (0 == rc) + { + mfib_table_entry_delete(rx_fib_index, + &all_dhcp_servers, + MFIB_SOURCE_DHCP); + mfib_table_unlock(rx_fib_index, FIB_PROTOCOL_IP6); + } + } + else + { + const fib_route_path_t path_for_us = { + .frp_proto = FIB_PROTOCOL_IP6, + .frp_addr = zero_addr, + .frp_sw_if_index = 0xffffffff, + .frp_fib_index = ~0, + .frp_weight = 0, + .frp_flags = FIB_ROUTE_PATH_LOCAL, + }; + if (dhcp_proxy_server_add (FIB_PROTOCOL_IP6, addr, src_addr, + rx_fib_index, server_table_id)) + { + mfib_table_entry_path_update(rx_fib_index, + &all_dhcp_servers, + MFIB_SOURCE_DHCP, + &path_for_us, + MFIB_ITF_FLAG_FORWARD); + /* + * Each interface that is enabled in this table, needs to be added + * as an accepting interface, but this is not easily doable in VPP. + * So we cheat. Add a flag to the entry that indicates accept form + * any interface. + * We will still only accept on v6 enabled interfaces, since the + * input feature ensures this. + */ + mfib_table_entry_update(rx_fib_index, + &all_dhcp_servers, + MFIB_SOURCE_DHCP, + MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF); + mfib_table_lock(rx_fib_index, FIB_PROTOCOL_IP6); + } + } + + mfib_table_unlock(rx_fib_index, FIB_PROTOCOL_IP6); + + return (rc); +} + +static clib_error_t * +dhcpv6_proxy_set_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + ip46_address_t addr, src_addr; + int set_server = 0, set_src_address = 0; + u32 rx_table_id = 0, server_table_id = 0; + int is_del = 0; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "server %U", + unformat_ip6_address, &addr.ip6)) + set_server = 1; + else if (unformat(input, "src-address %U", + unformat_ip6_address, &src_addr.ip6)) + set_src_address =1; + else if (unformat (input, "server-fib-id %d", &server_table_id)) + ; + else if (unformat (input, "rx-fib-id %d", &rx_table_id)) + ; + else if (unformat (input, "delete") || + unformat (input, "del")) + is_del = 1; + else + break; + } + + if (is_del || (set_server && set_src_address)) + { + int rv; + + rv = dhcp6_proxy_set_server (&addr, &src_addr, rx_table_id, + server_table_id, is_del); + + //TODO: Complete the errors + switch (rv) + { + case 0: + return 0; + + case VNET_API_ERROR_INVALID_DST_ADDRESS: + return clib_error_return (0, "Invalid server address"); + + case VNET_API_ERROR_INVALID_SRC_ADDRESS: + return clib_error_return (0, "Invalid src address"); + + case VNET_API_ERROR_NO_SUCH_ENTRY: + return clib_error_return + (0, "Fib id %d: no per-fib DHCP server configured", rx_table_id); + + default: + return clib_error_return (0, "BUG: rv %d", rv); + } + } + else + return clib_error_return (0, "parse error`%U'", + format_unformat_error, input); +} + +VLIB_CLI_COMMAND (dhcpv6_proxy_set_command, static) = { + .path = "set dhcpv6 proxy", + .short_help = "set dhcpv6 proxy [del] server src-address " + "[server-fib-id ] [rx-fib-id ] ", + .function = dhcpv6_proxy_set_command_fn, +}; + +static u8 * +format_dhcp6_proxy_server (u8 * s, va_list * args) +{ + dhcp_server_t * server = va_arg (*args, dhcp_server_t *); + ip6_fib_t * rx_fib, * server_fib; + + if (NULL == server) + { + s = format (s, "%=40s%=40s%=14s%=14s", "Server Address", "Source Address", + "Server FIB", "RX FIB"); + return s; + } + + server_fib = ip6_fib_get(server->server_fib_index); + rx_fib = ip6_fib_get(server->rx_fib_index); + + + s = format (s, "%=40U%=40U%=14u%=14u", + format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY, + format_ip46_address, &server->dhcp_src_address, IP46_TYPE_ANY, + server_fib->table_id, rx_fib->table_id); + return s; +} + +static int +dhcp6_proxy_show_walk (dhcp_server_t *server, + void *ctx) +{ + vlib_main_t * vm = ctx; + + vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, server); + + return (1); +} + +static clib_error_t * +dhcpv6_proxy_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, NULL /* header line */); + + dhcp_proxy_walk(FIB_PROTOCOL_IP6, dhcp6_proxy_show_walk, vm); + + return (NULL); +} + +VLIB_CLI_COMMAND (dhcpv6_proxy_show_command, static) = { + .path = "show dhcpv6 proxy", + .short_help = "Display dhcpv6 proxy info", + .function = dhcpv6_proxy_show_command_fn, +}; + +static clib_error_t * +dhcpv6_vss_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + int is_del = 0, got_new_vss=0; + u32 oui=0; + u32 fib_id=0, tbl_id=~0; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "oui %d", &oui)) + got_new_vss = 1; + else if (unformat (input, "vpn-id %d", &fib_id)) + got_new_vss = 1; + else if (unformat (input, "table %d", &tbl_id)) + got_new_vss = 1; + else if (unformat(input, "delete") || unformat(input, "del")) + is_del = 1; + else + break; + } + + if (tbl_id ==~0) + return clib_error_return (0, "no table ID specified."); + + if (is_del || got_new_vss) + { + int rv; + + rv = dhcp_proxy_set_vss(FIB_PROTOCOL_IP6, tbl_id, oui, fib_id, is_del); + switch (rv) + { + case 0: + return 0; + + case VNET_API_ERROR_NO_SUCH_FIB: + return clib_error_return (0, "vss info (oui:%d, vpn-id:%d) not found in table %d.", + oui, fib_id, tbl_id); + + case VNET_API_ERROR_NO_SUCH_ENTRY: + return clib_error_return (0, "vss for table %d not found in pool.", + tbl_id); + + default: + return clib_error_return (0, "BUG: rv %d", rv); + } + } + else + return clib_error_return (0, "parse error`%U'", + format_unformat_error, input); + +} + +VLIB_CLI_COMMAND (dhcpv6_proxy_vss_command, static) = { + .path = "set dhcpv6 vss", + .short_help = "set dhcpv6 vss table oui vpn-idx ", + .function = dhcpv6_vss_command_fn, +}; + +static clib_error_t * +dhcpv6_vss_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) + +{ + dhcp_vss_walk(FIB_PROTOCOL_IP6, dhcp_vss_show_walk, vm); + + return (NULL); +} + +VLIB_CLI_COMMAND (dhcpv6_proxy_vss_show_command, static) = { + .path = "show dhcpv6 vss", + .short_help = "show dhcpv6 VSS", + .function = dhcpv6_vss_show_command_fn, +}; + +static clib_error_t * +dhcpv6_link_address_show_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) + +{ + vnet_main_t *vnm = vnet_get_main(); + u32 sw_if_index0=0, sw_if_index; + vnet_sw_interface_t *swif; + ip6_address_t *ia0; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) + { + + if (unformat(input, "%U", + unformat_vnet_sw_interface, vnm, &sw_if_index0)) + { + swif = vnet_get_sw_interface (vnm, sw_if_index0); + sw_if_index = (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) ? + swif->unnumbered_sw_if_index : sw_if_index0; + ia0 = ip6_interface_first_address(&ip6_main, sw_if_index); + if (ia0) + { + vlib_cli_output (vm, "%=20s%=48s", "interface", "link-address"); + + vlib_cli_output (vm, "%=20U%=48U", + format_vnet_sw_if_index_name, vnm, sw_if_index0, + format_ip6_address, ia0); + } else + vlib_cli_output (vm, "%=34s%=20U", "No IPv6 address configured on", + format_vnet_sw_if_index_name, vnm, sw_if_index); + } else + break; + } + + return 0; +} + +VLIB_CLI_COMMAND (dhcpv6_proxy_address_show_command, static) = { + .path = "show dhcpv6 link-address interface", + .short_help = "show dhcpv6 link-address interface ", + .function = dhcpv6_link_address_show_command_fn, +}; diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index ce9039b7..bdf02cae 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -22,9 +22,8 @@ #include #include -#include +#include #include -#include #include @@ -51,52 +50,19 @@ _(DHCP_PROXY_DETAILS,dhcp_proxy_details) \ _(DHCP_PROXY_SET_VSS,dhcp_proxy_set_vss) \ _(DHCP_CLIENT_CONFIG, dhcp_client_config) -static void -dhcpv4_proxy_config (vl_api_dhcp_proxy_config_t * mp) -{ - vl_api_dhcp_proxy_config_reply_t *rmp; - int rv; - - rv = dhcp_proxy_set_server ((ip4_address_t *) (&mp->dhcp_server), - (ip4_address_t *) (&mp->dhcp_src_address), - (u32) ntohl (mp->rx_vrf_id), - (u32) ntohl (mp->server_vrf_id), - (int) (mp->is_add == 0)); - - REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); -} - - -static void -dhcpv6_proxy_config (vl_api_dhcp_proxy_config_t * mp) -{ - vl_api_dhcp_proxy_config_reply_t *rmp; - int rv = -1; - - rv = dhcpv6_proxy_set_server ((ip6_address_t *) (&mp->dhcp_server), - (ip6_address_t *) (&mp->dhcp_src_address), - (u32) ntohl (mp->rx_vrf_id), - (u32) ntohl (mp->server_vrf_id), - (int) (mp->is_add == 0)); - - REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_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; int rv; - if (!mp->is_ipv6) - rv = dhcp_proxy_set_option82_vss (ntohl (mp->tbl_id), - ntohl (mp->oui), - ntohl (mp->fib_id), - (int) mp->is_add == 0); - else - rv = dhcpv6_proxy_set_vss (ntohl (mp->tbl_id), - ntohl (mp->oui), - ntohl (mp->fib_id), (int) mp->is_add == 0); + + rv = dhcp_proxy_set_vss ((mp->is_ipv6 ? + FIB_PROTOCOL_IP6 : + FIB_PROTOCOL_IP4), + ntohl (mp->tbl_id), + ntohl (mp->oui), + ntohl (mp->fib_id), (int) mp->is_add == 0); REPLY_MACRO (VL_API_DHCP_PROXY_SET_VSS_REPLY); } @@ -105,10 +71,38 @@ vl_api_dhcp_proxy_set_vss_t_handler (vl_api_dhcp_proxy_set_vss_t * mp) static void vl_api_dhcp_proxy_config_t_handler (vl_api_dhcp_proxy_config_t * mp) { - if (mp->is_ipv6 == 0) - dhcpv4_proxy_config (mp); + vl_api_dhcp_proxy_set_vss_reply_t *rmp; + ip46_address_t src, server; + int rv = -1; + + if (mp->is_ipv6) + { + clib_memcpy (&src.ip6, mp->dhcp_src_address, sizeof (src.ip6)); + clib_memcpy (&server.ip6, mp->dhcp_server, sizeof (server.ip6)); + + rv = dhcp6_proxy_set_server (&server, + &src, + (u32) ntohl (mp->rx_vrf_id), + (u32) ntohl (mp->server_vrf_id), + (int) (mp->is_add == 0)); + } else - dhcpv6_proxy_config (mp); + { + ip46_address_reset (&src); + ip46_address_reset (&server); + + clib_memcpy (&src.ip4, mp->dhcp_src_address, sizeof (src.ip4)); + clib_memcpy (&server.ip4, mp->dhcp_server, sizeof (server.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)); + } + + + REPLY_MACRO (VL_API_DHCP_PROXY_CONFIG_REPLY); } static void @@ -120,14 +114,13 @@ vl_api_dhcp_proxy_dump_t_handler (vl_api_dhcp_proxy_dump_t * mp) if (q == 0) return; - if (mp->is_ip6 == 0) - dhcp_proxy_dump (q, mp->context); - else - dhcpv6_proxy_dump (q, mp->context); + dhcp_proxy_dump ((mp->is_ip6 == 0 ? + FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4), q, mp->context); } void -dhcp_send_details (void *opaque, +dhcp_send_details (fib_protocol_t proto, + void *opaque, u32 context, const ip46_address_t * server, const ip46_address_t * src, @@ -149,7 +142,7 @@ dhcp_send_details (void *opaque, mp->vss_oui = htonl (vss_oui); mp->vss_fib_id = htonl (vss_fib_id); - mp->is_ipv6 = !ip46_address_is_ip4 (server); + mp->is_ipv6 = (proto == FIB_PROTOCOL_IP6); if (mp->is_ipv6) { diff --git a/src/vnet/dhcp/dhcp_proxy.c b/src/vnet/dhcp/dhcp_proxy.c new file mode 100644 index 00000000..da2deea6 --- /dev/null +++ b/src/vnet/dhcp/dhcp_proxy.c @@ -0,0 +1,275 @@ +/* + * proxy_node.c: common dhcp v4 and v6 proxy node processing + * + * Copyright (c) 2013 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 +#include + +/** + * @brief Shard 4/6 instance of DHCP main + */ +dhcp_proxy_main_t dhcp_proxy_main; + +void +dhcp_proxy_walk (fib_protocol_t proto, + dhcp_proxy_walk_fn_t fn, + void *ctx) +{ + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + dhcp_server_t * server; + u32 server_index, i; + + vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index[proto]) + { + server_index = dpm->dhcp_server_index_by_rx_fib_index[proto][i]; + if (~0 == server_index) + continue; + + server = pool_elt_at_index (dpm->dhcp_servers[proto], server_index); + + if (!fn(server, ctx)) + break; + } +} + +void +dhcp_vss_walk (fib_protocol_t proto, + dhcp_vss_walk_fn_t fn, + void *ctx) +{ + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + dhcp_vss_t * vss; + u32 vss_index, i; + fib_table_t *fib; + + + vec_foreach_index (i, dpm->vss_index_by_rx_fib_index[proto]) + { + vss_index = dpm->vss_index_by_rx_fib_index[proto][i]; + if (~0 == vss_index) + continue; + + vss = pool_elt_at_index (dpm->vss[proto], vss_index); + + fib = fib_table_get(i, proto); + + if (!fn(vss, fib->ft_table_id, ctx)) + break; + } +} + +int +dhcp_proxy_server_del (fib_protocol_t proto, + u32 rx_fib_index) +{ + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + dhcp_server_t * server = 0; + int rc = 0; + + server = dhcp_get_server(dpm, rx_fib_index, proto); + + if (NULL == server) + { + rc = VNET_API_ERROR_NO_SUCH_ENTRY; + } + else + { + /* Use the default server again. */ + dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = ~0; + + fib_table_unlock (server->server_fib_index, proto); + + pool_put (dpm->dhcp_servers[proto], server); + } + + return (rc); +} + +int +dhcp_proxy_server_add (fib_protocol_t proto, + ip46_address_t *addr, + ip46_address_t *src_address, + u32 rx_fib_index, + u32 server_table_id) +{ + dhcp_proxy_main_t * dpm = &dhcp_proxy_main; + dhcp_server_t * server = 0; + int new = 0; + + server = dhcp_get_server(dpm, rx_fib_index, proto); + + if (NULL == server) + { + vec_validate_init_empty(dpm->dhcp_server_index_by_rx_fib_index[proto], + rx_fib_index, + ~0); + + pool_get (dpm->dhcp_servers[proto], server); + memset (server, 0, sizeof (*server)); + new = 1; + + dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = + server - dpm->dhcp_servers[proto]; + + server->rx_fib_index = rx_fib_index; + server->server_fib_index = + fib_table_find_or_create_and_lock(proto, server_table_id); + } + else + { + /* modify, may need to swap server FIBs */ + u32 tmp_index; + + tmp_index = fib_table_find(proto, server_table_id); + + if (tmp_index != server->server_fib_index) + { + tmp_index = server->server_fib_index; + + /* certainly swapping if the fib doesn't exist */ + server->server_fib_index = + fib_table_find_or_create_and_lock(proto, server_table_id); + fib_table_unlock (tmp_index, proto); + } + } + + server->dhcp_server = *addr; + server->dhcp_src_address = *src_address; + + return (new); +} + +typedef struct dhcp4_proxy_dump_walk_ctx_t_ +{ + fib_protocol_t proto; + void *opaque; + u32 context; +} dhcp_proxy_dump_walk_cxt_t; + +static int +dhcp_proxy_dump_walk (dhcp_server_t *server, + void *arg) +{ + dhcp_proxy_dump_walk_cxt_t *ctx = arg; + fib_table_t *s_fib, *r_fib; + dhcp_vss_t *v; + + v = dhcp_get_vss_info(&dhcp_proxy_main, + server->rx_fib_index, + ctx->proto); + + s_fib = fib_table_get(server->server_fib_index, ctx->proto); + r_fib = fib_table_get(server->rx_fib_index, ctx->proto); + + dhcp_send_details(ctx->proto, + ctx->opaque, + ctx->context, + &server->dhcp_server, + &server->dhcp_src_address, + s_fib->ft_table_id, + r_fib->ft_table_id, + (v ? v->fib_id : 0), + (v ? v->oui : 0)); + + return (1); +} + +void +dhcp_proxy_dump (fib_protocol_t proto, + void *opaque, + u32 context) +{ + dhcp_proxy_dump_walk_cxt_t ctx = { + .proto = proto, + .opaque = opaque, + .context = context, + }; + dhcp_proxy_walk(proto, dhcp_proxy_dump_walk, &ctx); +} + +int +dhcp_vss_show_walk (dhcp_vss_t *vss, + u32 rx_table_id, + void *ctx) +{ + vlib_main_t * vm = ctx; + + vlib_cli_output (vm, "%=6d%=6d%=12d", + rx_table_id, + vss->oui, + vss->fib_id); + + return (1); +} + +int dhcp_proxy_set_vss (fib_protocol_t proto, + u32 tbl_id, + u32 oui, + u32 fib_id, + int is_del) +{ + dhcp_proxy_main_t *dm = &dhcp_proxy_main; + dhcp_vss_t *v = NULL; + u32 rx_fib_index; + int rc = 0; + + rx_fib_index = fib_table_find_or_create_and_lock(proto, tbl_id); + v = dhcp_get_vss_info(dm, rx_fib_index, proto); + + if (NULL != v) + { + if (is_del) + { + /* release the lock held on the table when the VSS + * info was created */ + fib_table_unlock (rx_fib_index, proto); + + pool_put (dm->vss[proto], v); + dm->vss_index_by_rx_fib_index[proto][rx_fib_index] = ~0; + } + else + { + /* this is a modify */ + v->fib_id = fib_id; + v->oui = oui; + } + } + else + { + if (is_del) + rc = VNET_API_ERROR_NO_SUCH_ENTRY; + else + { + /* create a new entry */ + vec_validate_init_empty(dm->vss_index_by_rx_fib_index[proto], + rx_fib_index, ~0); + + /* hold a lock on the table whilst the VSS info exist */ + fib_table_lock (rx_fib_index, proto); + + pool_get (dm->vss[proto], v); + v->fib_id = fib_id; + v->oui = oui; + dm->vss_index_by_rx_fib_index[proto][rx_fib_index] = + v - dm->vss[proto]; + } + } + + /* Release the lock taken during the create_or_lock at the start */ + fib_table_unlock (rx_fib_index, proto); + + return (rc); +} diff --git a/src/vnet/dhcp/dhcp_proxy.h b/src/vnet/dhcp/dhcp_proxy.h new file mode 100644 index 00000000..c0d79c41 --- /dev/null +++ b/src/vnet/dhcp/dhcp_proxy.h @@ -0,0 +1,248 @@ +/* + * dhcp_proxy.h: DHCP v4 & v6 proxy common functions/types + * + * Copyright (c) 2013 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. + */ + +#ifndef included_dhcp_proxy_h +#define included_dhcp_proxy_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum { +#define dhcp_proxy_error(n,s) DHCP_PROXY_ERROR_##n, +#include +#undef dhcp_proxy_error + DHCP_PROXY_N_ERROR, +} dhcp_proxy_error_t; + +typedef enum { +#define dhcpv6_proxy_error(n,s) DHCPV6_PROXY_ERROR_##n, +#include +#undef dhcpv6_proxy_error + DHCPV6_PROXY_N_ERROR, +} dhcpv6_proxy_error_t; + + +/** + * @brief The Virtual Sub-net Selection information for a given RX FIB + */ +typedef struct dhcp_vss_t_ { + /** + * @brief ?? RFC doesn't say + */ + u32 oui; + /** + * @brief VPN-ID + */ + u32 fib_id; +} dhcp_vss_t; + +/** + * @brief A DHCP proxy server represenation + */ +typedef struct dhcp_server_t_ { + /** + * @brief The address of the DHCP server to which to relay the client's + * messages + */ + ip46_address_t dhcp_server; + + /** + * @brief The source address to use in relayed messaes + */ + ip46_address_t dhcp_src_address; + + /** + * @brief The FIB index (not the external Table-ID) in which the server + * is reachable. + */ + u32 server_fib_index; + + /** + * @brief The FIB index (not the external Table-ID) in which the client + * is resides. + */ + u32 rx_fib_index; +} dhcp_server_t; + +#define DHCP_N_PROTOS (FIB_PROTOCOL_IP6 + 1) + +/** + * @brief Collection of global DHCP proxy data + */ +typedef struct { + /* Pool of DHCP servers */ + dhcp_server_t *dhcp_servers[DHCP_N_PROTOS]; + + /* Pool of selected DHCP server. Zero is the default server */ + u32 * dhcp_server_index_by_rx_fib_index[DHCP_N_PROTOS]; + + /* to drop pkts in server-to-client direction */ + u32 error_drop_node_index; + + dhcp_vss_t *vss[DHCP_N_PROTOS]; + + /* hash lookup specific vrf_id -> option 82 vss suboption */ + u32 *vss_index_by_rx_fib_index[DHCP_N_PROTOS]; + +} dhcp_proxy_main_t; + +extern dhcp_proxy_main_t dhcp_proxy_main; + +/** + * @brief Send the details of a proxy session to the API client during a dump + */ +void dhcp_send_details (fib_protocol_t proto, + void *opaque, + u32 context, + const ip46_address_t *server, + const ip46_address_t *src, + u32 server_fib_id, + u32 rx_fib_id, + u32 vss_fib_id, + u32 vss_oui); + +/** + * @brief Show (on CLI) a VSS config during a show walk + */ +int dhcp_vss_show_walk (dhcp_vss_t *vss, + u32 rx_table_id, + void *ctx); + +/** + * @brief Configure/set a new VSS info + */ +int dhcp_proxy_set_vss(fib_protocol_t proto, + u32 vrf_id, + u32 oui, + u32 fib_id, + int is_del); + +/** + * @brief Dump the proxy configs to the API + */ +void dhcp_proxy_dump(fib_protocol_t proto, + void *opaque, + u32 context); + +/** + * @brief Add a new DHCP proxy server configuration. + * @return 1 is the config is new, + * 0 otherwise (implying a modify of an existing) + */ +int dhcp_proxy_server_add(fib_protocol_t proto, + ip46_address_t *addr, + ip46_address_t *src_address, + u32 rx_fib_iindex, + u32 server_table_id); + +/** + * @brief Delete a DHCP proxy config + * @return 0 is deleted, otherwise an error code + */ +int dhcp_proxy_server_del(fib_protocol_t proto, + u32 rx_fib_index); + +/** + * @brief Callback function invoked for each DHCP proxy entry + * return 0 to break the walk, non-zero otherwise. + */ +typedef int (*dhcp_proxy_walk_fn_t)(dhcp_server_t *server, + void *ctx); + +/** + * @brief Walk/Visit each DHCP proxy server + */ +void dhcp_proxy_walk(fib_protocol_t proto, + dhcp_proxy_walk_fn_t fn, + void *ctx); + +/** + * @brief Callback function invoked for each DHCP VSS entry + * return 0 to break the walk, non-zero otherwise. + */ +typedef int (*dhcp_vss_walk_fn_t)(dhcp_vss_t *server, + u32 rx_table_id, + void *ctx); + +/** + * @brief Walk/Visit each DHCP proxy VSS + */ +void dhcp_vss_walk(fib_protocol_t proto, + dhcp_vss_walk_fn_t fn, + void *ctx); + +/** + * @brief Get the VSS data for the FIB index + */ +static inline dhcp_vss_t * +dhcp_get_vss_info (dhcp_proxy_main_t *dm, + u32 rx_fib_index, + fib_protocol_t proto) +{ + dhcp_vss_t *v = NULL; + + if (vec_len(dm->vss_index_by_rx_fib_index[proto]) > rx_fib_index && + dm->vss_index_by_rx_fib_index[proto][rx_fib_index] != ~0) + { + v = pool_elt_at_index ( + dm->vss[proto], + dm->vss_index_by_rx_fib_index[proto][rx_fib_index]); + } + + return (v); +} + +/** + * @brief Get the DHCP proxy server data for the FIB index + */ +static inline dhcp_server_t * +dhcp_get_server (dhcp_proxy_main_t *dm, + u32 rx_fib_index, + fib_protocol_t proto) +{ + dhcp_server_t *s = NULL; + + if (vec_len(dm->dhcp_server_index_by_rx_fib_index[proto]) > rx_fib_index && + dm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] != ~0) + { + s = pool_elt_at_index ( + dm->dhcp_servers[proto], + dm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index]); + } + + return (s); +} + +int dhcp6_proxy_set_server (ip46_address_t *addr, + ip46_address_t *src_addr, + u32 rx_table_id, + u32 server_table_id, + int is_del); +int dhcp4_proxy_set_server (ip46_address_t *addr, + ip46_address_t *src_addr, + u32 rx_table_id, + u32 server_table_id, + int is_del); + +#endif /* included_dhcp_proxy_h */ diff --git a/src/vnet/dhcp/packet.h b/src/vnet/dhcp/packet.h deleted file mode 100644 index 267a8eaf..00000000 --- a/src/vnet/dhcp/packet.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef included_vnet_dhcp_packet_h -#define included_vnet_dhcp_packet_h - -/* - * DHCP packet format - * - * Copyright (c) 2013 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 - -typedef struct { - u8 opcode; /* 1 = request, 2 = reply */ - u8 hardware_type; /* 1 = ethernet */ - u8 hardware_address_length; - u8 hops; - u32 transaction_identifier; - u16 seconds; - u16 flags; -#define DHCP_FLAG_BROADCAST (1<<15) - ip4_address_t client_ip_address; - ip4_address_t your_ip_address; /* use this one */ - ip4_address_t server_ip_address; - ip4_address_t gateway_ip_address; /* use option 3, not this one */ - u8 client_hardware_address[16]; - u8 server_name[64]; - u8 boot_filename[128]; - ip4_address_t magic_cookie; - u8 options[0]; -} dhcp_header_t; - -typedef struct { - u8 option; - u8 length; - union { - u8 data[0]; - u32 data_as_u32[0]; - }; -} __attribute__((packed)) dhcp_option_t; - -typedef enum { - DHCP_PACKET_DISCOVER=1, - DHCP_PACKET_OFFER, - DHCP_PACKET_REQUEST, - DHCP_PACKET_ACK=5, -} dhcp_packet_type_t; - -/* charming antique: 99.130.83.99 is the dhcp magic cookie */ -#define DHCP_MAGIC (clib_host_to_net_u32(0x63825363)) - -#endif /* included_vnet_dhcp_packet_h */ diff --git a/src/vnet/dhcp/proxy.h b/src/vnet/dhcp/proxy.h deleted file mode 100644 index 4b115c74..00000000 --- a/src/vnet/dhcp/proxy.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * proxy.h: dhcp proxy - * - * Copyright (c) 2013 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. - */ - -#ifndef included_dhcp_proxy_h -#define included_dhcp_proxy_h - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef enum { -#define dhcp_proxy_error(n,s) DHCP_PROXY_ERROR_##n, -#include -#undef dhcp_proxy_error - DHCP_PROXY_N_ERROR, -} dhcp_proxy_error_t; - -typedef struct { - u32 oui; - u32 fib_id; -} vss_id; - -typedef union { - u8 as_u8[8]; - vss_id vpn_id; -} vss_info; - -typedef struct { - ip4_address_t dhcp_server; - ip4_address_t dhcp_src_address; - u32 server_fib_index; -} dhcp_server_t; - -typedef struct { - /* Pool of DHCP servers */ - dhcp_server_t * dhcp_servers; - - /* Pool of selected DHCP server. Zero is the default server */ - u32 * dhcp_server_index_by_rx_fib_index; - - /* to drop pkts in server-to-client direction */ - u32 error_drop_node_index; - - vss_info *vss; - - /* hash lookup specific vrf_id -> option 82 vss suboption */ - u32 *vss_index_by_rx_fib_index; - - /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} dhcp_proxy_main_t; - -extern dhcp_proxy_main_t dhcp_proxy_main; - -void dhcp_send_details (void *opaque, - u32 context, - const ip46_address_t *server, - const ip46_address_t *src, - u32 server_fib_id, - u32 rx_fib_id, - u32 vss_fib_id, - u32 vss_oui); - -int dhcp_proxy_set_server (ip4_address_t *addr, - ip4_address_t *src_address, - u32 fib_id, - u32 server_fib_id, - int is_del); - -int dhcp_proxy_set_option82_vss(u32 vrf_id, - u32 oui, - u32 fib_id, - int is_del); - -void dhcp_proxy_dump(void *opaque, - u32 context); - -#endif /* included_dhcp_proxy_h */ diff --git a/src/vnet/dhcp/proxy_error.def b/src/vnet/dhcp/proxy_error.def deleted file mode 100644 index 6d790d73..00000000 --- a/src/vnet/dhcp/proxy_error.def +++ /dev/null @@ -1,31 +0,0 @@ -/* - * dhcp_proxy_error.def: dhcp proxy errors - * - * Copyright (c) 2013 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. - */ - -dhcp_proxy_error (NONE, "no error") -dhcp_proxy_error (NO_SERVER, "no dhcp server configured") -dhcp_proxy_error (RELAY_TO_SERVER, "DHCP packets relayed to the server") -dhcp_proxy_error (RELAY_TO_CLIENT, "DHCP packets relayed to clients") -dhcp_proxy_error (OPTION_82_ERROR, "DHCP failed to insert option 82") -dhcp_proxy_error (NO_OPTION_82, "DHCP option 82 missing") -dhcp_proxy_error (BAD_OPTION_82_ITF, "Bad DHCP option 82 interface value") -dhcp_proxy_error (BAD_OPTION_82_ADDR, "Bad DHCP option 82 address value") -dhcp_proxy_error (BAD_FIB_ID, "DHCP option 82 fib-id to fib-index map failure") -dhcp_proxy_error (NO_INTERFACE_ADDRESS, "DHCP no interface address") -dhcp_proxy_error (OPTION_82_VSS_NOT_PROCESSED, "DHCP VSS not processed by DHCP server") -dhcp_proxy_error (BAD_YIADDR, "DHCP packets with bad your_ip_address fields") -dhcp_proxy_error (BAD_SVR_FIB_OR_ADDRESS, "DHCP packets not from DHCP server or server FIB.") -dhcp_proxy_error (PKT_TOO_BIG, "DHCP packets which are too big.") diff --git a/src/vnet/dhcp/proxy_node.c b/src/vnet/dhcp/proxy_node.c deleted file mode 100644 index ab6819fe..00000000 --- a/src/vnet/dhcp/proxy_node.c +++ /dev/null @@ -1,1192 +0,0 @@ -/* - * proxy_node.c: dhcp proxy node processing - * - * Copyright (c) 2013 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 -#include -#include -#include -#include - -static char * dhcp_proxy_error_strings[] = { -#define dhcp_proxy_error(n,s) s, -#include "proxy_error.def" -#undef dhcp_proxy_error -}; - -#define foreach_dhcp_proxy_to_server_input_next \ - _ (DROP, "error-drop") \ - _ (LOOKUP, "ip4-lookup") \ - _ (SEND_TO_CLIENT, "dhcp-proxy-to-client") - -typedef enum { -#define _(s,n) DHCP_PROXY_TO_SERVER_INPUT_NEXT_##s, - foreach_dhcp_proxy_to_server_input_next -#undef _ - DHCP_PROXY_TO_SERVER_INPUT_N_NEXT, -} dhcp_proxy_to_server_input_next_t; - -typedef struct { - /* 0 => to server, 1 => to client */ - int which; - ip4_address_t trace_ip4_address; - u32 error; - u32 sw_if_index; - u32 original_sw_if_index; -} dhcp_proxy_trace_t; - -#define VPP_DHCP_OPTION82_SUB1_SIZE 6 -#define VPP_DHCP_OPTION82_SUB5_SIZE 6 -#define VPP_DHCP_OPTION82_VSS_SIZE 12 -#define VPP_DHCP_OPTION82_SIZE (VPP_DHCP_OPTION82_SUB1_SIZE + \ - VPP_DHCP_OPTION82_SUB5_SIZE + \ - VPP_DHCP_OPTION82_VSS_SIZE +3) - -vlib_node_registration_t dhcp_proxy_to_server_node; -vlib_node_registration_t dhcp_proxy_to_client_node; - -dhcp_proxy_main_t dhcp_proxy_main; - -u8 * format_dhcp_proxy_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - dhcp_proxy_trace_t * t = va_arg (*args, dhcp_proxy_trace_t *); - - if (t->which == 0) - s = format (s, "DHCP proxy: sent to server %U\n", - format_ip4_address, &t->trace_ip4_address, t->error); - else - s = format (s, "DHCP proxy: broadcast to client from %U\n", - format_ip4_address, &t->trace_ip4_address); - - if (t->error != (u32)~0) - s = format (s, " error: %s\n", dhcp_proxy_error_strings[t->error]); - - s = format (s, " original_sw_if_index: %d, sw_if_index: %d\n", - t->original_sw_if_index, t->sw_if_index); - - return s; -} - -u8 * format_dhcp_proxy_header_with_length (u8 * s, va_list * args) -{ - dhcp_header_t * h = va_arg (*args, dhcp_header_t *); - u32 max_header_bytes = va_arg (*args, u32); - u32 header_bytes; - - header_bytes = sizeof (h[0]); - if (max_header_bytes != 0 && header_bytes > max_header_bytes) - return format (s, "dhcp header truncated"); - - s = format (s, "DHCP Proxy"); - - return s; -} - -static inline vss_info * -dhcp_get_vss_info (dhcp_proxy_main_t *dm, - u32 rx_fib_index) -{ - vss_info *v; - - if (vec_len(dm->vss_index_by_rx_fib_index) <= rx_fib_index || - dm->vss_index_by_rx_fib_index[rx_fib_index] == ~0) - { - v = NULL; - } - else - { - v = pool_elt_at_index (dm->vss, - dm->vss_index_by_rx_fib_index[rx_fib_index]); - } - - return (v); -} - -static inline dhcp_server_t * -dhcp_get_server (dhcp_proxy_main_t *dm, - u32 rx_fib_index) -{ - dhcp_server_t *s = NULL; - - if (vec_len(dm->dhcp_server_index_by_rx_fib_index) > rx_fib_index && - dm->dhcp_server_index_by_rx_fib_index[rx_fib_index] != ~0) - { - s = pool_elt_at_index (dm->dhcp_servers, - dm->dhcp_server_index_by_rx_fib_index[rx_fib_index]); - } - - return (s); -} - -static uword -dhcp_proxy_to_server_input (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - u32 n_left_from, next_index, * from, * to_next; - dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - from = vlib_frame_vector_args (from_frame); - n_left_from = from_frame->n_vectors; - u32 pkts_to_server=0, pkts_to_client=0, pkts_no_server=0; - u32 pkts_no_interface_address=0; - u32 pkts_too_big=0; - ip4_main_t * im = &ip4_main; - - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - udp_header_t * u0; - dhcp_header_t * h0; - ip4_header_t * ip0; - u32 next0; - u32 old0, new0; - ip_csum_t sum0; - u32 error0 = (u32) ~0; - u32 sw_if_index = 0; - u32 original_sw_if_index = 0; - u8 *end = NULL; - u32 fib_index; - dhcp_server_t * server; - u32 rx_sw_if_index; - dhcp_option_t *o; - u32 len = 0; - vlib_buffer_free_list_t *fl; - - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - h0 = vlib_buffer_get_current (b0); - - /* - * udp_local hands us the DHCP header, need udp hdr, - * ip hdr to relay to server - */ - vlib_buffer_advance (b0, -(sizeof(*u0))); - u0 = vlib_buffer_get_current (b0); - - /* This blows. Return traffic has src_port = 67, dst_port = 67 */ - if (u0->src_port == clib_net_to_host_u16(UDP_DST_PORT_dhcp_to_server)) - { - vlib_buffer_advance (b0, sizeof(*u0)); - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT; - error0 = 0; - pkts_to_client++; - goto do_enqueue; - } - - rx_sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - - fib_index = im->fib_index_by_sw_if_index [rx_sw_if_index]; - server = dhcp_get_server(dpm, fib_index); - - if (PREDICT_FALSE (NULL == server)) - { - error0 = DHCP_PROXY_ERROR_NO_SERVER; - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_server++; - goto do_trace; - } - - vlib_buffer_advance (b0, -(sizeof(*ip0))); - ip0 = vlib_buffer_get_current (b0); - - /* disable UDP checksum */ - u0->checksum = 0; - sum0 = ip0->checksum; - old0 = ip0->dst_address.as_u32; - new0 = server->dhcp_server.as_u32; - ip0->dst_address.as_u32 = server->dhcp_server.as_u32; - sum0 = ip_csum_update (sum0, old0, new0, - ip4_header_t /* structure */, - dst_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - sum0 = ip0->checksum; - old0 = ip0->src_address.as_u32; - new0 = server->dhcp_src_address.as_u32; - ip0->src_address.as_u32 = new0; - sum0 = ip_csum_update (sum0, old0, new0, - ip4_header_t /* structure */, - src_address /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - /* Send to DHCP server via the configured FIB */ - vnet_buffer(b0)->sw_if_index[VLIB_TX] = - server->server_fib_index; - - h0->gateway_ip_address.as_u32 = server->dhcp_src_address.as_u32; - pkts_to_server++; - - o = (dhcp_option_t *) h0->options; - - fib_index = im->fib_index_by_sw_if_index - [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; - - end = b0->data + b0->current_data + b0->current_length; - /* TLVs are not performance-friendly... */ - while (o->option != 0xFF /* end of options */ && (u8 *)o < end) - o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); - - fl = vlib_buffer_get_free_list (vm, b0->free_list_index); - // start write at (option*)o, some packets have padding - if (((u8 *)o - (u8 *)b0->data + VPP_DHCP_OPTION82_SIZE) > fl->n_data_bytes) - { - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_too_big++; - goto do_trace; - } - - if ((o->option == 0xFF) && ((u8 *)o <= end)) - { - vnet_main_t *vnm = vnet_get_main(); - u16 old_l0, new_l0; - ip4_address_t _ia0, * ia0 = &_ia0; - vss_info *vss; - vnet_sw_interface_t *swif; - sw_if_index = 0; - original_sw_if_index = 0; - - original_sw_if_index = sw_if_index = - vnet_buffer(b0)->sw_if_index[VLIB_RX]; - swif = vnet_get_sw_interface (vnm, sw_if_index); - if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) - sw_if_index = swif->unnumbered_sw_if_index; - - /* - * Get the first ip4 address on the [client-side] - * RX interface, if not unnumbered. otherwise use - * the loopback interface's ip address. - */ - ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); - - if (ia0 == 0) - { - error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS; - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_interface_address++; - goto do_trace; - } - - /* Add option 82 */ - o->option = 82; /* option 82 */ - o->length = 12; /* 12 octets to follow */ - o->data[0] = 1; /* suboption 1, circuit ID (=FIB id) */ - o->data[1] = 4; /* length of suboption */ - o->data[2] = (original_sw_if_index >> 24) & 0xFF; - o->data[3] = (original_sw_if_index >> 16) & 0xFF; - o->data[4] = (original_sw_if_index >> 8) & 0xFF; - o->data[5] = (original_sw_if_index >> 0) & 0xFF; - o->data[6] = 5; /* suboption 5 (client RX intfc address) */ - o->data[7] = 4; /* length 4 */ - o->data[8] = ia0->as_u8[0]; - o->data[9] = ia0->as_u8[1]; - o->data[10] = ia0->as_u8[2]; - o->data[11] = ia0->as_u8[3]; - o->data[12] = 0xFF; - - vss = dhcp_get_vss_info (dpm, fib_index); - if (NULL != vss) - { - u32 opt82_fib_id=0, opt82_oui=0; - - opt82_oui = vss->vpn_id.oui; - opt82_fib_id = vss->vpn_id.fib_id; - - o->data[12] = 151; /* vss suboption */ - if (255 == opt82_fib_id) { - o->data[13] = 1; /* length */ - o->data[14] = 255; /* vss option type */ - o->data[15] = 152; /* vss control suboption */ - o->data[16] = 0; /* length */ - /* and a new "end-of-options" option (0xff) */ - o->data[17] = 0xFF; - o->length += 5; - } else { - o->data[13] = 8; /* length */ - o->data[14] = 1; /* vss option type */ - o->data[15] = (opt82_oui >> 16) & 0xff; - o->data[16] = (opt82_oui >> 8) & 0xff; - o->data[17] = (opt82_oui ) & 0xff; - o->data[18] = (opt82_fib_id >> 24) & 0xff; - o->data[19] = (opt82_fib_id >> 16) & 0xff; - o->data[20] = (opt82_fib_id >> 8) & 0xff; - o->data[21] = (opt82_fib_id) & 0xff; - o->data[22] = 152; /* vss control suboption */ - o->data[23] = 0; /* length */ - - /* and a new "end-of-options" option (0xff) */ - o->data[24] = 0xFF; - o->length += 12; - } - } - - len = o->length + 3; - b0->current_length += len; - /* Fix IP header length and checksum */ - old_l0 = ip0->length; - new_l0 = clib_net_to_host_u16 (old_l0); - new_l0 += len; - new_l0 = clib_host_to_net_u16 (new_l0); - ip0->length = new_l0; - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, - length /* changed member */); - ip0->checksum = ip_csum_fold (sum0); - - /* Fix UDP length */ - new_l0 = clib_net_to_host_u16 (u0->length); - new_l0 += len; - u0->length = clib_host_to_net_u16 (new_l0); - } else { - vlib_node_increment_counter - (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_OPTION_82_ERROR, 1); - } - - next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; - - do_trace: - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) - { - dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->which = 0; /* to server */ - tr->error = error0; - tr->original_sw_if_index = original_sw_if_index; - tr->sw_if_index = sw_if_index; - if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP) - tr->trace_ip4_address.as_u32 = server->dhcp_server.as_u32; - } - - do_enqueue: - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_RELAY_TO_CLIENT, - pkts_to_client); - vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_RELAY_TO_SERVER, - pkts_to_server); - vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_NO_SERVER, - pkts_no_server); - vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS, - pkts_no_interface_address); - vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index, - DHCP_PROXY_ERROR_PKT_TOO_BIG, - pkts_too_big); - return from_frame->n_vectors; -} - -VLIB_REGISTER_NODE (dhcp_proxy_to_server_node) = { - .function = dhcp_proxy_to_server_input, - .name = "dhcp-proxy-to-server", - /* Takes a vector of packets. */ - .vector_size = sizeof (u32), - - .n_errors = DHCP_PROXY_N_ERROR, - .error_strings = dhcp_proxy_error_strings, - - .n_next_nodes = DHCP_PROXY_TO_SERVER_INPUT_N_NEXT, - .next_nodes = { -#define _(s,n) [DHCP_PROXY_TO_SERVER_INPUT_NEXT_##s] = n, - foreach_dhcp_proxy_to_server_input_next -#undef _ - }, - - .format_buffer = format_dhcp_proxy_header_with_length, - .format_trace = format_dhcp_proxy_trace, -#if 0 - .unformat_buffer = unformat_dhcp_proxy_header, -#endif -}; - -static uword -dhcp_proxy_to_client_input (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - u32 n_left_from, * from; - ethernet_main_t *em = ethernet_get_main (vm); - dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - vnet_main_t * vnm = vnet_get_main(); - ip4_main_t * im = &ip4_main; - - from = vlib_frame_vector_args (from_frame); - n_left_from = from_frame->n_vectors; - - while (n_left_from > 0) - { - u32 bi0; - vlib_buffer_t * b0; - udp_header_t * u0; - dhcp_header_t * h0; - ip4_header_t * ip0 = 0; - ip4_address_t * ia0 = 0; - u32 old0, new0; - ip_csum_t sum0; - ethernet_interface_t *ei0; - ethernet_header_t *mac0; - vnet_hw_interface_t *hi0; - vlib_frame_t *f0; - u32 * to_next0; - u32 sw_if_index = ~0; - vnet_sw_interface_t *si0; - u32 error0 = (u32)~0; - vnet_sw_interface_t *swif; - u32 fib_index; - dhcp_server_t * server; - u32 original_sw_if_index = (u32) ~0; - ip4_address_t relay_addr = { - .as_u32 = 0, - }; - - bi0 = from[0]; - from += 1; - n_left_from -= 1; - - b0 = vlib_get_buffer (vm, bi0); - h0 = vlib_buffer_get_current (b0); - - /* - * udp_local hands us the DHCP header, need udp hdr, - * ip hdr to relay to client - */ - vlib_buffer_advance (b0, -(sizeof(*u0))); - u0 = vlib_buffer_get_current (b0); - - vlib_buffer_advance (b0, -(sizeof(*ip0))); - ip0 = vlib_buffer_get_current (b0); - - /* Consumed by dhcp client code? */ - if (dhcp_client_for_us (bi0, b0, ip0, u0, h0)) - continue; - - if (1 /* dpm->insert_option_82 */) - { - dhcp_option_t *o = (dhcp_option_t *) h0->options; - dhcp_option_t *sub; - - /* Parse through TLVs looking for option 82. - The circuit-ID is the FIB number we need - to track down the client-facing interface */ - - while (o->option != 0xFF /* end of options */ && - (u8 *) o < (b0->data + b0->current_data + b0->current_length)) - { - if (o->option == 82) - { - u32 vss_exist = 0; - u32 vss_ctrl = 0; - sub = (dhcp_option_t *) &o->data[0]; - while (sub->option != 0xFF /* end of options */ && - (u8 *) sub < (u8 *)(o + o->length)) { - /* If this is one of ours, it will have - total length 12, circuit-id suboption type, - and the sw_if_index */ - if (sub->option == 1 && sub->length == 4) - { - sw_if_index = ((sub->data[0] << 24) | - (sub->data[1] << 16) | - (sub->data[2] << 8) | - (sub->data[3])); - } - else if (sub->option == 5 && sub->length == 4) - { - relay_addr.as_u8[0] = sub->data[0]; - relay_addr.as_u8[1] = sub->data[1]; - relay_addr.as_u8[2] = sub->data[2]; - relay_addr.as_u8[3] = sub->data[3]; - } - else if (sub->option == 151 && - sub->length == 7 && - sub->data[0] == 1) - vss_exist = 1; - else if (sub->option == 152 && sub->length == 0) - vss_ctrl = 1; - sub = (dhcp_option_t *) - (((uword) sub) + (sub->length + 2)); - } - if (vss_ctrl && vss_exist) - vlib_node_increment_counter - (vm, dhcp_proxy_to_client_node.index, - DHCP_PROXY_ERROR_OPTION_82_VSS_NOT_PROCESSED, 1); - - } - o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); - } - } - - if (sw_if_index == (u32)~0) - { - error0 = DHCP_PROXY_ERROR_NO_OPTION_82; - - drop_packet: - vlib_node_increment_counter (vm, dhcp_proxy_to_client_node.index, - error0, 1); - f0 = vlib_get_frame_to_node (vm, dpm->error_drop_node_index); - to_next0 = vlib_frame_vector_args (f0); - to_next0[0] = bi0; - f0->n_vectors = 1; - vlib_put_frame_to_node (vm, dpm->error_drop_node_index, f0); - goto do_trace; - } - - if (relay_addr.as_u32 == 0) - { - error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ADDR; - goto drop_packet; - } - - if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index)) - { - error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ITF; - goto drop_packet; - } - - fib_index = im->fib_index_by_sw_if_index [sw_if_index]; - server = dhcp_get_server(dpm, fib_index); - - if (PREDICT_FALSE (NULL == server)) - { - error0 = DHCP_PROXY_ERROR_NO_SERVER; - goto drop_packet; - } - - if (ip0->src_address.as_u32 != server->dhcp_server.as_u32) - { - error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; - goto drop_packet; - } - - vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index; - - swif = vnet_get_sw_interface (vnm, sw_if_index); - original_sw_if_index = sw_if_index; - if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) - sw_if_index = swif->unnumbered_sw_if_index; - - ia0 = ip4_interface_first_address (&ip4_main, sw_if_index, 0); - if (ia0 == 0) - { - error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS; - goto drop_packet; - } - - if (relay_addr.as_u32 != ia0->as_u32) - { - error0 = DHCP_PROXY_ERROR_BAD_YIADDR; - goto drop_packet; - } - - u0->checksum = 0; - u0->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcp_to_client); - sum0 = ip0->checksum; - old0 = ip0->dst_address.as_u32; - new0 = 0xFFFFFFFF; - ip0->dst_address.as_u32 = new0; - sum0 = ip_csum_update (sum0, old0, new0, - ip4_header_t /* structure */, - dst_address /* offset of changed member */); - ip0->checksum = ip_csum_fold (sum0); - - sum0 = ip0->checksum; - old0 = ip0->src_address.as_u32; - new0 = ia0->as_u32; - ip0->src_address.as_u32 = new0; - sum0 = ip_csum_update (sum0, old0, new0, - ip4_header_t /* structure */, - src_address /* offset of changed member */); - ip0->checksum = ip_csum_fold (sum0); - - vlib_buffer_advance (b0, -(sizeof(ethernet_header_t))); - si0 = vnet_get_sw_interface (vnm, original_sw_if_index); - if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) - vlib_buffer_advance (b0, -4 /* space for VLAN tag */); - - mac0 = vlib_buffer_get_current (b0); - - hi0 = vnet_get_sup_hw_interface (vnm, original_sw_if_index); - ei0 = pool_elt_at_index (em->interfaces, hi0->hw_instance); - clib_memcpy (mac0->src_address, ei0->address, sizeof (ei0->address)); - memset (mac0->dst_address, 0xff, sizeof (mac0->dst_address)); - mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ? - clib_net_to_host_u16(0x8100) : clib_net_to_host_u16 (0x0800); - - if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) - { - u32 * vlan_tag = (u32 *)(mac0+1); - u32 tmp; - tmp = (si0->sub.id << 16) | 0x0800; - *vlan_tag = clib_host_to_net_u32 (tmp); - } - - /* $$$ This needs to be rewritten, for sure */ - f0 = vlib_get_frame_to_node (vm, hi0->output_node_index); - to_next0 = vlib_frame_vector_args (f0); - to_next0[0] = bi0; - f0->n_vectors = 1; - vlib_put_frame_to_node (vm, hi0->output_node_index, f0); - - do_trace: - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) - { - dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->which = 1; /* to client */ - tr->trace_ip4_address.as_u32 = ia0 ? ia0->as_u32 : 0; - tr->error = error0; - tr->original_sw_if_index = original_sw_if_index; - tr->sw_if_index = sw_if_index; - } - } - return from_frame->n_vectors; -} - -VLIB_REGISTER_NODE (dhcp_proxy_to_client_node) = { - .function = dhcp_proxy_to_client_input, - .name = "dhcp-proxy-to-client", - /* Takes a vector of packets. */ - .vector_size = sizeof (u32), - - .n_errors = DHCP_PROXY_N_ERROR, - .error_strings = dhcp_proxy_error_strings, - .format_buffer = format_dhcp_proxy_header_with_length, - .format_trace = format_dhcp_proxy_trace, -#if 0 - .unformat_buffer = unformat_dhcp_proxy_header, -#endif -}; - -clib_error_t * dhcp_proxy_init (vlib_main_t * vm) -{ - dhcp_proxy_main_t * dm = &dhcp_proxy_main; - vlib_node_t * error_drop_node; - dhcp_server_t * server; - - dm->vlib_main = vm; - dm->vnet_main = vnet_get_main(); - error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); - dm->error_drop_node_index = error_drop_node->index; - - dm->vss_index_by_rx_fib_index = NULL; - - udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_client, - dhcp_proxy_to_client_node.index, 1 /* is_ip4 */); - - udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_server, - dhcp_proxy_to_server_node.index, 1 /* is_ip4 */); - - /* Create the default server, don't mark it valid */ - pool_get (dm->dhcp_servers, server); - memset (server, 0, sizeof (*server)); - - return 0; -} - -VLIB_INIT_FUNCTION (dhcp_proxy_init); - -int dhcp_proxy_set_server (ip4_address_t *addr, - ip4_address_t *src_address, - u32 rx_fib_id, - u32 server_fib_id, - int is_del) -{ - dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - dhcp_server_t * server = 0; - u32 server_index = 0; - u32 rx_fib_index = 0; - - const fib_prefix_t all_1s = - { - .fp_len = 32, - .fp_addr.ip4.as_u32 = 0xffffffff, - .fp_proto = FIB_PROTOCOL_IP4, - }; - - if (addr->as_u32 == 0) - return VNET_API_ERROR_INVALID_DST_ADDRESS; - - if (src_address->as_u32 == 0) - return VNET_API_ERROR_INVALID_SRC_ADDRESS; - - rx_fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, - rx_fib_id); - - if (is_del) - { - if (rx_fib_index >= vec_len(dpm->dhcp_server_index_by_rx_fib_index)) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - server_index = dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index]; - - if (server_index == ~0) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - /* Use the default server again. */ - dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = ~0; - server = pool_elt_at_index (dpm->dhcp_servers, server_index); - - fib_table_entry_special_remove(rx_fib_index, - &all_1s, - FIB_SOURCE_DHCP); - fib_table_unlock (rx_fib_index, - FIB_PROTOCOL_IP4); - fib_table_unlock (server->server_fib_index, - FIB_PROTOCOL_IP4); - - memset (server, 0, sizeof (*server)); - pool_put (dpm->dhcp_servers, server); - return 0; - } - else - { - vec_validate_init_empty(dpm->dhcp_server_index_by_rx_fib_index, - rx_fib_index, - ~0); - - pool_get (dpm->dhcp_servers, server); - - server->dhcp_server.as_u32 = addr->as_u32; - server->dhcp_src_address.as_u32 = src_address->as_u32; - - fib_table_entry_special_add(rx_fib_index, - &all_1s, - FIB_SOURCE_DHCP, - FIB_ENTRY_FLAG_LOCAL, - ADJ_INDEX_INVALID); - fib_table_lock (rx_fib_index, - FIB_PROTOCOL_IP4); - - server->server_fib_index = - fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, - server_fib_id); - - vec_validate_init_empty (dpm->dhcp_server_index_by_rx_fib_index, - rx_fib_index, - ~0); - dpm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = - server - dpm->dhcp_servers; - } - - fib_table_unlock (rx_fib_index, - FIB_PROTOCOL_IP4); - - return 0; -} - -static clib_error_t * -dhcp_proxy_set_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - ip4_address_t server_addr, src_addr; - u32 server_fib_id = 0, rx_fib_id = 0; - int is_del = 0; - int set_src = 0, set_server = 0; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "server %U", - unformat_ip4_address, &server_addr)) - set_server = 1; - else if (unformat (input, "server-fib-id %d", &server_fib_id)) - ; - else if (unformat (input, "rx-fib-id %d", &rx_fib_id)) - ; - else if (unformat(input, "src-address %U", - unformat_ip4_address, &src_addr)) - set_src = 1; - else if (unformat (input, "delete") || - unformat (input, "del")) - is_del = 1; - else - break; - } - - if (is_del || (set_server && set_src)) - { - int rv; - - rv = dhcp_proxy_set_server (&server_addr, &src_addr, rx_fib_id, - server_fib_id, is_del); - switch (rv) - { - case 0: - return 0; - - case VNET_API_ERROR_INVALID_DST_ADDRESS: - return clib_error_return (0, "Invalid server address"); - - case VNET_API_ERROR_INVALID_SRC_ADDRESS: - return clib_error_return (0, "Invalid src address"); - - case VNET_API_ERROR_NO_SUCH_INNER_FIB: - return clib_error_return (0, "No such rx fib id %d", rx_fib_id); - - case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "No such server fib id %d", - server_fib_id); - - case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return - (0, "Fib id %d: no per-fib DHCP server configured", rx_fib_id); - - default: - return clib_error_return (0, "BUG: rv %d", rv); - } - } - else - return clib_error_return (0, "parse error`%U'", - format_unformat_error, input); -} - -VLIB_CLI_COMMAND (dhcp_proxy_set_command, static) = { - .path = "set dhcp proxy", - .short_help = "set dhcp proxy [del] server src-address [server-fib-id ] [rx-fib-id ]", - .function = dhcp_proxy_set_command_fn, -}; - -u8 * format_dhcp_proxy_server (u8 * s, va_list * args) -{ - dhcp_proxy_main_t * dm = va_arg (*args, dhcp_proxy_main_t *); - dhcp_server_t * server = va_arg (*args, dhcp_server_t *); - u32 rx_fib_index = va_arg (*args, u32); - ip4_fib_t * rx_fib, * server_fib; - u32 server_fib_id = ~0, rx_fib_id = ~0; - - if (dm == 0) - { - s = format (s, "%=16s%=16s%=14s%=14s", "Server", "Src Address", - "Server FIB", "RX FIB"); - return s; - } - - server_fib = ip4_fib_get(server->server_fib_index); - - if (server_fib) - server_fib_id = server_fib->table_id; - - rx_fib = ip4_fib_get(rx_fib_index); - - if (rx_fib) - rx_fib_id = rx_fib->table_id; - - s = format (s, "%=16U%=16U%=14u%=14u", - format_ip4_address, &server->dhcp_server, - format_ip4_address, &server->dhcp_src_address, - server_fib_id, rx_fib_id); - return s; -} - -static clib_error_t * -dhcp_proxy_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - dhcp_server_t * server; - u32 server_index, i; - - vlib_cli_output (vm, "%U", format_dhcp_proxy_server, 0 /* header line */, - 0, 0); - - vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index) - { - server_index = dpm->dhcp_server_index_by_rx_fib_index[i]; - if (~0 == server_index) - continue; - - server = pool_elt_at_index (dpm->dhcp_servers, server_index); - - vlib_cli_output (vm, "%U", format_dhcp_proxy_server, dpm, - server, i); - } - - return 0; -} - -VLIB_CLI_COMMAND (dhcp_proxy_show_command, static) = { - .path = "show dhcp proxy", - .short_help = "Display dhcp proxy server info", - .function = dhcp_proxy_show_command_fn, -}; - -void -dhcp_proxy_dump (void *opaque, - u32 context) -{ - dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - ip4_fib_t *s_fib, *r_fib; - dhcp_server_t * server; - u32 server_index, i; - vss_info *v; - - vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index) - { - server_index = dpm->dhcp_server_index_by_rx_fib_index[i]; - if (~0 == server_index) - continue; - - server = pool_elt_at_index (dpm->dhcp_servers, server_index); - v = dhcp_get_vss_info(dpm, i); - - ip46_address_t src_addr = { - .ip4 = server->dhcp_src_address, - }; - ip46_address_t server_addr = { - .ip4 = server->dhcp_server, - }; - - s_fib = ip4_fib_get(server->server_fib_index); - r_fib = ip4_fib_get(i); - - dhcp_send_details(opaque, - context, - &server_addr, - &src_addr, - s_fib->table_id, - r_fib->table_id, - (v ? v->vpn_id.fib_id : 0), - (v ? v->vpn_id.oui : 0)); - } -} - -int dhcp_proxy_set_option82_vss(u32 tbl_id, - u32 oui, - u32 fib_id, - int is_del) -{ - dhcp_proxy_main_t *dm = &dhcp_proxy_main; - vss_info *v = NULL; - u32 rx_fib_index; - int rc = 0; - - rx_fib_index = ip4_fib_table_find_or_create_and_lock(tbl_id); - v = dhcp_get_vss_info(dm, rx_fib_index); - - if (NULL != v) - { - if (is_del) - { - /* release the lock held on the table when the VSS - * info was created */ - fib_table_unlock (rx_fib_index, - FIB_PROTOCOL_IP4); - - pool_put (dm->vss, v); - dm->vss_index_by_rx_fib_index[rx_fib_index] = ~0; - } - else - { - /* this is a modify */ - v->vpn_id.fib_id = fib_id; - v->vpn_id.oui = oui; - } - } - else - { - if (is_del) - rc = VNET_API_ERROR_NO_SUCH_ENTRY; - else - { - /* create a new entry */ - vec_validate_init_empty(dm->vss_index_by_rx_fib_index, - rx_fib_index, ~0); - - /* hold a lock on the table whilst the VSS info exist */ - fib_table_lock (rx_fib_index, - FIB_PROTOCOL_IP4); - - pool_get (dm->vss, v); - v->vpn_id.fib_id = fib_id; - v->vpn_id.oui = oui; - dm->vss_index_by_rx_fib_index[rx_fib_index] = v - dm->vss; - } - } - - /* Release the lock taken during the create_or_lock at the start */ - fib_table_unlock (rx_fib_index, - FIB_PROTOCOL_IP4); - - return (rc); -} - -static clib_error_t * -dhcp_option_82_vss_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - int is_del = 0, got_new_vpn_id=0; - u32 oui=0, fib_id=0, tbl_id=~0; - - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - - if (unformat(input, "delete") || unformat(input, "del")) - is_del = 1; - else if (unformat (input, "oui %d", &oui)) - got_new_vpn_id = 1; - else if (unformat (input, "vpn-id %d", &fib_id)) - got_new_vpn_id = 1; - else if (unformat (input, "table %d", &tbl_id)) - got_new_vpn_id = 1; - else - break; - } - if (tbl_id == ~0) - return clib_error_return (0, "no table ID specified."); - - if (is_del || got_new_vpn_id) - { - int rv; - rv = dhcp_proxy_set_option82_vss(tbl_id, oui, fib_id, is_del); - switch (rv) - { - case 0: - return 0; - - case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "option 82 vss(oui:%d, vpn-id:%d) not found in table %d", - oui, fib_id, tbl_id); - - case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "option 82 vss for table %d not found in in pool.", - tbl_id); - default: - return clib_error_return (0, "BUG: rv %d", rv); - } - } - else - return clib_error_return (0, "parse error`%U'", - format_unformat_error, input); -} - -VLIB_CLI_COMMAND (dhcp_proxy_vss_command,static) = { - .path = "set dhcp option-82 vss", - .short_help = "set dhcp option-82 vss [del] table
oui vpn-id ", - .function = dhcp_option_82_vss_fn, -}; - - -static clib_error_t * -dhcp_vss_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) - -{ - dhcp_proxy_main_t * dm = &dhcp_proxy_main; - ip4_fib_t *fib; - u32 *fib_index; - vss_info *v; - - vlib_cli_output (vm, "%=9s%=11s%=12s","Table", "OUI", "VPN-ID"); - pool_foreach (fib_index, dm->vss_index_by_rx_fib_index, - ({ - fib = ip4_fib_get (*fib_index); - v = pool_elt_at_index (dm->vss, *fib_index); - - vlib_cli_output (vm, "%=6d%=6d%=12d", - fib->table_id, - v->vpn_id.oui, - v->vpn_id.fib_id); - })); - - return 0; -} - -VLIB_CLI_COMMAND (dhcp_proxy_vss_show_command, static) = { - .path = "show dhcp vss", - .short_help = "show dhcp VSS", - .function = dhcp_vss_show_command_fn, -}; - -static clib_error_t * -dhcp_option_82_address_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) - -{ - dhcp_proxy_main_t *dm = &dhcp_proxy_main; - vnet_main_t *vnm = vnet_get_main(); - u32 sw_if_index0=0, sw_if_index; - ip4_address_t *ia0; - vnet_sw_interface_t *swif; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - - if (unformat(input, "%U", - unformat_vnet_sw_interface, dm->vnet_main, &sw_if_index0)) - { - swif = vnet_get_sw_interface (vnm, sw_if_index0); - sw_if_index = (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) ? - swif->unnumbered_sw_if_index : sw_if_index0; - ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); - if (ia0) - { - vlib_cli_output (vm, "%=20s%=20s", "interface", - "source IP address"); - - vlib_cli_output (vm, "%=20U%=20U", - format_vnet_sw_if_index_name, - dm->vnet_main, sw_if_index0, - format_ip4_address, ia0); - } - else - vlib_cli_output (vm, "%=34s %=20U", - "No IPv4 address configured on", - format_vnet_sw_if_index_name, - dm->vnet_main, sw_if_index); - } - else - break; - } - - return 0; -} - -VLIB_CLI_COMMAND (dhcp_proxy_address_show_command,static) = { - .path = "show dhcp option-82-address interface", - .short_help = "show dhcp option-82-address interface ", - .function = dhcp_option_82_address_show_command_fn, -}; diff --git a/src/vnet/dhcpv6/packet.h b/src/vnet/dhcpv6/packet.h deleted file mode 100644 index 8634b5d8..00000000 --- a/src/vnet/dhcpv6/packet.h +++ /dev/null @@ -1,183 +0,0 @@ -#ifndef included_vnet_dhcp_packet_h -#define included_vnet_dhcp_packet_h - -/* - * DHCP packet format - * - * Copyright (c) 2013 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 - -// #define DHCP_VRF_NAME_MAX_LEN L3VM_MAX_NAME_STR_LEN -// #define DHCPV6_MAX_VRF_NAME_LEN L3VM_MAX_NAME_STR_LEN -#define DHCP_MAX_RELAY_ADDR 16 -#define PROTO_UDP 17 -#define DHCPV6_CLIENT_PORT 546 -#define DHCPV6_SERVER_PORT 547 -#define HOP_COUNT_LIMIT 32 -#define DHCPV6_CISCO_ENT_NUM 9 - -/* - * DHCPv6 message types - */ -typedef enum dhcpv6_msg_type_{ - DHCPV6_MSG_SOLICIT = 1, - DHCPV6_MSG_ADVERTISE = 2, - DHCPV6_MSG_REQUEST = 3, - DHCPV6_MSG_CONFIRM = 4, - DHCPV6_MSG_RENEW = 5, - DHCPV6_MSG_REBIND = 6, - DHCPV6_MSG_REPLY = 7, - DHCPV6_MSG_RELEASE = 8, - DHCPV6_MSG_DECLINE = 9, - DHCPV6_MSG_RECONFIGURE = 10, - DHCPV6_MSG_INFORMATION_REQUEST = 11, - DHCPV6_MSG_RELAY_FORW = 12, - DHCPV6_MSG_RELAY_REPL = 13, -} dhcpv6_msg_type_t; - -/* - * DHCPv6 options types - */ -enum { - DHCPV6_OPTION_CLIENTID = 1, - DHCPV6_OPTION_SERVERID = 2, - DHCPV6_OPTION_IA_NA = 3, - DHCPV6_OPTION_IA_TA = 4, - DHCPV6_OPTION_IAADDR = 5, - DHCPV6_OPTION_ORO = 6, - DHCPV6_OPTION_PREFERENCE = 7, - DHCPV6_OPTION_ELAPSED_TIME = 8, - DHCPV6_OPTION_RELAY_MSG = 9, - DHCPV6_OPTION_AUTH = 11, - DHCPV6_OPTION_UNICAST = 12, - DHCPV6_OPTION_STATUS_CODE = 13, - DHCPV6_OPTION_RAPID_COMMIT = 14, - DHCPV6_OPTION_USER_CLASS = 15, - DHCPV6_OPTION_VENDOR_CLASS = 16, - DHCPV6_OPTION_VENDOR_OPTS = 17, - DHCPV6_OPTION_INTERFACE_ID = 18, // relay agent fills this - DHCPV6_OPTION_RECONF_MSG = 19, - DHCPV6_OPTION_RECONF_ACCEPT = 20, - DHCPV6_OPTION_REMOTEID = 37, // relay agent fills this - DHCPV6_OPTION_VSS = 68, // relay agent fills this - DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS = 79, - DHCPV6_OPTION_MAX -}; - -/* -* DHCPv6 status codes - */ -enum { - DHCPV6_STATUS_SUCCESS = 0, - DHCPV6_STATUS_UNSPEC_FAIL = 1, - DHCPV6_STATUS_NOADDRS_AVAIL = 2, - DHCPV6_STATUS_NO_BINDING = 3, - DHCPV6_STATUS_NOT_ONLINK = 4, - DHCPV6_STATUS_USE_MULTICAST = 5, -}; - -/* - * DHCPv6 DUID types - */ -enum { - DHCPV6_DUID_LLT = 1, /* DUID Based on Link-layer Address Plus Time */ - DHCPV6_DUID_EN = 2, /* DUID Based on Enterprise Number */ - DHCPV6_DUID_LL = 3, /* DUID Based on Link-layer Address */ -}; - -//Structure for DHCPv6 payload from client -typedef struct dhcpv6_hdr_ { - union { - u8 msg_type; //DHCP msg type - u32 xid; // transaction id - }u; - u8 data[0]; -} dhcpv6_header_t; - - - -typedef CLIB_PACKED (struct dhcpv6_relay_ctx_ { - dhcpv6_header_t *pkt; - u32 pkt_len; - u32 dhcpv6_len; //DHCPv6 payload load -// if_ordinal iod; - u32 if_index; - u32 ctx_id; - char ctx_name[32+1]; - u8 dhcp_msg_type; -}) dhcpv6_relay_ctx_t; - -//Structure for DHCPv6 RELAY-FORWARD and DHCPv6 RELAY-REPLY pkts -typedef CLIB_PACKED (struct dhcpv6_relay_hdr_ { - u8 msg_type; - u8 hop_count; - ip6_address_t link_addr; - ip6_address_t peer_addr; - u8 data[0]; -}) dhcpv6_relay_hdr_t; - -typedef enum dhcp_stats_action_type_ { - DHCP_STATS_ACTION_FORWARDED=1, - DHCP_STATS_ACTION_RECEIVED, - DHCP_STATS_ACTION_DROPPED -} dhcp_stats_action_type_t; -//Generic counters for a packet -typedef struct dhcp_stats_counters_ { - u64 rx_pkts; //counter for received pkts - u64 tx_pkts; //counter for forwarded pkts - u64 drops; //counter for dropped pkts -} dhcp_stats_counters_t; - - -typedef enum dhcpv6_stats_drop_reason_ { - DHCPV6_RELAY_PKT_DROP_RELAYDISABLE = 1, - DHCPV6_RELAY_PKT_DROP_MAX_HOPS, - DHCPV6_RELAY_PKT_DROP_VALIDATION_FAIL, - DHCPV6_RELAY_PKT_DROP_UNKNOWN_OP_INTF, - DHCPV6_RELAY_PKT_DROP_BAD_CONTEXT, - DHCPV6_RELAY_PKT_DROP_OPT_INSERT_FAIL, - DHCPV6_RELAY_PKT_DROP_REPLY_FROM_CLIENT, -} dhcpv6_stats_drop_reason_t; - -typedef CLIB_PACKED (struct { - u16 option; - u16 length; - u8 data[0]; -}) dhcpv6_option_t; - -typedef CLIB_PACKED (struct { - dhcpv6_option_t opt; - u32 int_idx; -}) dhcpv6_int_id_t; - -typedef CLIB_PACKED (struct { - dhcpv6_option_t opt; - u8 data[8]; // data[0]:type, data[1..7]: VPN ID -}) dhcpv6_vss_t; - -typedef CLIB_PACKED (struct { - dhcpv6_option_t opt; - u32 ent_num; - u32 rmt_id; -}) dhcpv6_rmt_id_t; - -typedef CLIB_PACKED (struct { - dhcpv6_option_t opt; - u16 link_type; - u8 data[6]; // data[0]:data[5]: MAC address -}) dhcpv6_client_mac_t; - - -#endif /* included_vnet_dhcp_packet_h */ diff --git a/src/vnet/dhcpv6/proxy.h b/src/vnet/dhcpv6/proxy.h deleted file mode 100644 index 77ced361..00000000 --- a/src/vnet/dhcpv6/proxy.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * proxy.h: dhcp proxy - * - * Copyright (c) 2013 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. - */ - -#ifndef included_dhcpv6_proxy_h -#define included_dhcpv6_proxy_h - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef enum { -#define dhcpv6_proxy_error(n,s) DHCPV6_PROXY_ERROR_##n, -#include -#undef dhcpv6_proxy_error - DHCPV6_PROXY_N_ERROR, -} dhcpv6_proxy_error_t; - -typedef struct { - u32 oui; - u32 fib_id; -} dhcpv6_vss_id; - -typedef union { - u8 as_u8[8]; - dhcpv6_vss_id vpn_id; -} dhcpv6_vss_info; - -typedef struct { - ip6_address_t dhcp6_server; - ip6_address_t dhcp6_src_address; - u32 server_fib6_index; -} dhcpv6_server_t; - -typedef struct { - /* Pool of DHCP servers */ - dhcpv6_server_t * dhcp6_servers; - - /* Pool of selected DHCP server. Zero is the default server */ - u32 * dhcp6_server_index_by_rx_fib_index; - - /* all DHCP servers address */ - ip6_address_t all_dhcpv6_server_address; - ip6_address_t all_dhcpv6_server_relay_agent_address; - - /* to drop pkts in server-to-client direction */ - u32 error_drop_node_index; - - dhcpv6_vss_info *vss; - - /* hash lookup specific vrf_id -> VSS vector index*/ - u32 *vss_index_by_rx_fib_index; - - /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; -} dhcpv6_proxy_main_t; - -dhcpv6_proxy_main_t dhcpv6_proxy_main; - -int dhcpv6_proxy_set_vss(u32 tbl_id, - u32 oui, - u32 fib_id, - int is_del); - -int dhcpv6_proxy_set_server(ip6_address_t *addr, - ip6_address_t *src_address, - u32 rx_fib_id, - u32 server_fib_id, - int is_del); - -void dhcpv6_proxy_dump(void *opaque, - u32 context); - -#endif /* included_dhcpv6_proxy_h */ diff --git a/src/vnet/dhcpv6/proxy_error.def b/src/vnet/dhcpv6/proxy_error.def deleted file mode 100644 index 55fa7317..00000000 --- a/src/vnet/dhcpv6/proxy_error.def +++ /dev/null @@ -1,29 +0,0 @@ -/* - * dhcp_proxy_error.def: dhcp proxy errors - * - * Copyright (c) 2013 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. - */ - -dhcpv6_proxy_error (NONE, "no error") -dhcpv6_proxy_error (NO_SERVER, "no dhcpv6 server configured") -dhcpv6_proxy_error (RELAY_TO_SERVER, "DHCPV6 packets relayed to the server") -dhcpv6_proxy_error (RELAY_TO_CLIENT, "DHCPV6 packets relayed to clients") -dhcpv6_proxy_error (NO_INTERFACE_ADDRESS, "DHCPV6 no interface address") -dhcpv6_proxy_error (WRONG_MESSAGE_TYPE, "DHCPV6 wrong message type.") -dhcpv6_proxy_error (NO_SRC_ADDRESS, "DHCPV6 no srouce IPv6 address configured.") -dhcpv6_proxy_error (NO_CIRCUIT_ID_OPTION, "DHCPv6 reply packets without circuit ID option") -dhcpv6_proxy_error (NO_RELAY_MESSAGE_OPTION, "DHCPv6 reply packets without relay message option") -dhcpv6_proxy_error (BAD_SVR_FIB_OR_ADDRESS, "DHCPv6 packets not from DHCPv6 server or server FIB.") -dhcpv6_proxy_error (PKT_TOO_BIG, "DHCPv6 packets which are too big.") -dhcpv6_proxy_error (WRONG_INTERFACE_ID_OPTION, "DHCPv6 reply to invalid interface.") diff --git a/src/vnet/dhcpv6/proxy_node.c b/src/vnet/dhcpv6/proxy_node.c deleted file mode 100644 index f40798e6..00000000 --- a/src/vnet/dhcpv6/proxy_node.c +++ /dev/null @@ -1,1280 +0,0 @@ -/* - * proxy_node.c: dhcpv6 proxy node processing - * - * Copyright (c) 2013 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 -#include -#include -#include -#include -#include -#include - -static char * dhcpv6_proxy_error_strings[] = { -#define dhcpv6_proxy_error(n,s) s, -#include "proxy_error.def" -#undef dhcpv6_proxy_error -}; - -#define foreach_dhcpv6_proxy_to_server_input_next \ - _ (DROP, "error-drop") \ - _ (LOOKUP, "ip6-lookup") \ - _ (SEND_TO_CLIENT, "dhcpv6-proxy-to-client") - - -typedef enum { -#define _(s,n) DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_##s, - foreach_dhcpv6_proxy_to_server_input_next -#undef _ - DHCPV6_PROXY_TO_SERVER_INPUT_N_NEXT, -} dhcpv6_proxy_to_server_input_next_t; - -typedef struct { - /* 0 => to server, 1 => to client */ - int which; - u8 packet_data[64]; - u32 error; - u32 sw_if_index; - u32 original_sw_if_index; -} dhcpv6_proxy_trace_t; - -vlib_node_registration_t dhcpv6_proxy_to_server_node; -vlib_node_registration_t dhcpv6_proxy_to_client_node; - - -u8 * format_dhcpv6_proxy_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - dhcpv6_proxy_trace_t * t = va_arg (*args, dhcpv6_proxy_trace_t *); - - if (t->which == 0) - s = format (s, "DHCPV6 proxy: sent to server %U", - format_ip6_address, &t->packet_data, sizeof (ip6_address_t)); - else - s = format (s, "DHCPV6 proxy: sent to client from %U", - format_ip6_address, &t->packet_data, sizeof (ip6_address_t)); - if (t->error != (u32)~0) - s = format (s, " error: %s\n", dhcpv6_proxy_error_strings[t->error]); - - s = format (s, " original_sw_if_index: %d, sw_if_index: %d\n", - t->original_sw_if_index, t->sw_if_index); - - return s; -} - -u8 * format_dhcpv6_proxy_header_with_length (u8 * s, va_list * args) -{ - dhcpv6_header_t * h = va_arg (*args, dhcpv6_header_t *); - u32 max_header_bytes = va_arg (*args, u32); - u32 header_bytes; - - header_bytes = sizeof (h[0]); - if (max_header_bytes != 0 && header_bytes > max_header_bytes) - return format (s, "dhcpv6 header truncated"); - - s = format (s, "DHCPV6 Proxy"); - - return s; -} -/* get first interface address */ -static ip6_address_t * -ip6_interface_first_global_or_site_address (ip6_main_t * im, u32 sw_if_index) -{ - ip_lookup_main_t * lm = &im->lookup_main; - ip_interface_address_t * ia = 0; - ip6_address_t * result = 0; - - foreach_ip_interface_address (lm, ia, sw_if_index, - 1 /* honor unnumbered */, - ({ - ip6_address_t * a = ip_interface_address_get_address (lm, ia); - if ((a->as_u8[0] & 0xe0) == 0x20 || - (a->as_u8[0] & 0xfe) == 0xfc) { - result = a; - break; - } - })); - return result; -} - -static inline void copy_ip6_address (ip6_address_t *dst, ip6_address_t *src) -{ - - dst->as_u64[0] = src->as_u64[0]; - dst->as_u64[1] = src->as_u64[1]; -} - -static inline dhcpv6_vss_info * -dhcpv6_get_vss_info (dhcpv6_proxy_main_t *dm, - u32 rx_fib_index) -{ - dhcpv6_vss_info *v; - - if (vec_len(dm->vss_index_by_rx_fib_index) <= rx_fib_index || - dm->vss_index_by_rx_fib_index[rx_fib_index] == ~0) - { - v = NULL; - } - else - { - v = pool_elt_at_index (dm->vss, - dm->vss_index_by_rx_fib_index[rx_fib_index]); - } - - return (v); -} - -static inline dhcpv6_server_t * -dhcpv6_get_server (dhcpv6_proxy_main_t *dm, - u32 rx_fib_index) -{ - dhcpv6_server_t *s = NULL; - - if (vec_len(dm->dhcp6_server_index_by_rx_fib_index) > rx_fib_index && - dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] != ~0) - { - s = pool_elt_at_index (dm->dhcp6_servers, - dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index]); - } - - return (s); -} - -static uword -dhcpv6_proxy_to_server_input (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - u32 n_left_from, next_index, * from, * to_next; - dhcpv6_proxy_main_t * dpm = &dhcpv6_proxy_main; - from = vlib_frame_vector_args (from_frame); - n_left_from = from_frame->n_vectors; - u32 pkts_to_server=0, pkts_to_client=0, pkts_no_server=0; - u32 pkts_no_interface_address=0, pkts_no_exceeding_max_hop=0; - u32 pkts_no_src_address=0; - u32 pkts_wrong_msg_type=0; - u32 pkts_too_big=0; - ip6_main_t * im = &ip6_main; - ip6_address_t * src; - int bogus_length; - dhcpv6_server_t * server; - u32 rx_fib_idx = 0, server_fib_idx = 0; - - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - vnet_main_t *vnm = vnet_get_main(); - u32 sw_if_index = 0; - u32 rx_sw_if_index = 0; - vnet_sw_interface_t *swif; - u32 bi0; - vlib_buffer_t * b0; - udp_header_t * u0, *u1; - dhcpv6_header_t * h0; // client msg hdr - ip6_header_t * ip0, *ip1; - ip6_address_t _ia0, *ia0=&_ia0; - u32 next0; - u32 error0 = (u32) ~0; - dhcpv6_option_t *fwd_opt; - dhcpv6_relay_hdr_t *r1; - u16 len; - dhcpv6_int_id_t *id1; - dhcpv6_vss_t *vss1; - dhcpv6_client_mac_t *cmac; // client mac - ethernet_header_t * e_h0; - u8 client_src_mac[6]; - vlib_buffer_free_list_t *fl; - dhcpv6_vss_info *vss; - - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - h0 = vlib_buffer_get_current (b0); - - /* - * udp_local hands us the DHCPV6 header. - */ - u0 = (void *)h0 -(sizeof(*u0)); - ip0 = (void *)u0 -(sizeof(*ip0)); - e_h0 = (void *)ip0 - ethernet_buffer_header_size(b0); - - clib_memcpy(client_src_mac, e_h0->src_address, 6); - - switch (h0->u.msg_type) { - case DHCPV6_MSG_SOLICIT: - case DHCPV6_MSG_REQUEST: - case DHCPV6_MSG_CONFIRM: - case DHCPV6_MSG_RENEW: - case DHCPV6_MSG_REBIND: - case DHCPV6_MSG_RELEASE: - case DHCPV6_MSG_DECLINE: - case DHCPV6_MSG_INFORMATION_REQUEST: - case DHCPV6_MSG_RELAY_FORW: - /* send to server */ - break; - case DHCPV6_MSG_RELAY_REPL: - /* send to client */ - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT; - error0 = 0; - pkts_to_client++; - goto do_enqueue; - default: - /* drop the packet */ - pkts_wrong_msg_type++; - error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - goto do_trace; - - } - - /* Send to DHCPV6 server via the configured FIB */ - rx_sw_if_index = sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; - rx_fib_idx = im->fib_index_by_sw_if_index [rx_sw_if_index]; - server = dhcpv6_get_server(dpm, rx_fib_idx); - - if (PREDICT_FALSE (NULL == server)) - { - error0 = DHCPV6_PROXY_ERROR_NO_SERVER; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_server++; - goto do_trace; - } - - server_fib_idx = server->server_fib6_index; - vnet_buffer(b0)->sw_if_index[VLIB_TX] = server_fib_idx; - - - /* relay-option header pointer */ - vlib_buffer_advance(b0, -(sizeof(*fwd_opt))); - fwd_opt = vlib_buffer_get_current(b0); - /* relay message header pointer */ - vlib_buffer_advance(b0, -(sizeof(*r1))); - r1 = vlib_buffer_get_current(b0); - - vlib_buffer_advance(b0, -(sizeof(*u1))); - u1 = vlib_buffer_get_current(b0); - - vlib_buffer_advance(b0, -(sizeof(*ip1))); - ip1 = vlib_buffer_get_current(b0); - - /* fill in all that rubbish... */ - len = clib_net_to_host_u16(u0->length) - sizeof(udp_header_t); - copy_ip6_address(&r1->peer_addr, &ip0->src_address); - - r1->msg_type = DHCPV6_MSG_RELAY_FORW; - fwd_opt->length = clib_host_to_net_u16(len); - fwd_opt->option = clib_host_to_net_u16(DHCPV6_OPTION_RELAY_MSG); - - r1->hop_count++; - r1->hop_count = (h0->u.msg_type != DHCPV6_MSG_RELAY_FORW) ? 0 : r1->hop_count; - - if (PREDICT_FALSE(r1->hop_count >= HOP_COUNT_LIMIT)) - { - error0 = DHCPV6_RELAY_PKT_DROP_MAX_HOPS; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_exceeding_max_hop++; - goto do_trace; - } - - - /* If relay-fwd and src address is site or global unicast address */ - if (h0->u.msg_type == DHCPV6_MSG_RELAY_FORW && - ((ip0->src_address.as_u8[0] & 0xe0) == 0x20 || - (ip0->src_address.as_u8[0] & 0xfe) == 0xfc)) - { - /* Set link address to zero */ - r1->link_addr.as_u64[0] = 0; - r1->link_addr.as_u64[1] = 0; - goto link_address_set; - } - - /* if receiving interface is unnumbered, use receiving interface - * IP address as link address, otherwise use the loopback interface - * IP address as link address. - */ - - swif = vnet_get_sw_interface (vnm, rx_sw_if_index); - if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) - sw_if_index = swif->unnumbered_sw_if_index; - - ia0 = ip6_interface_first_global_or_site_address(&ip6_main, sw_if_index); - if (ia0 == 0) - { - error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_interface_address++; - goto do_trace; - } - - copy_ip6_address(&r1->link_addr, ia0); - - link_address_set: - fl = vlib_buffer_get_free_list (vm, b0->free_list_index); - - if ((b0->current_length+sizeof(*id1)+sizeof(*vss1)+sizeof(*cmac)) - > fl->n_data_bytes) - { - error0 = DHCPV6_PROXY_ERROR_PKT_TOO_BIG; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_too_big++; - goto do_trace; - } - - id1 = (dhcpv6_int_id_t *) (((uword) ip1) + b0->current_length); - b0->current_length += (sizeof (*id1)); - - id1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_INTERFACE_ID); - id1->opt.length = clib_host_to_net_u16(sizeof(rx_sw_if_index)); - id1->int_idx = clib_host_to_net_u32(rx_sw_if_index); - - u1->length =0; - if (h0->u.msg_type != DHCPV6_MSG_RELAY_FORW) - { - cmac = (dhcpv6_client_mac_t *) (((uword) ip1) + b0->current_length); - b0->current_length += (sizeof (*cmac)); - cmac->opt.length =clib_host_to_net_u16(sizeof(*cmac) - - sizeof(cmac->opt)); - cmac->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS); - cmac->link_type = clib_host_to_net_u16(1); // ethernet - clib_memcpy(cmac->data, client_src_mac, 6); - u1->length += sizeof(*cmac); - } - - //TODO: Revisit if hash makes sense here - vss = dhcpv6_get_vss_info(dpm, rx_fib_idx); - - if (NULL != vss) { - vss1 = (dhcpv6_vss_t *) (((uword) ip1) + b0->current_length); - b0->current_length += (sizeof (*vss1)); - vss1->opt.length =clib_host_to_net_u16(sizeof(*vss1) - - sizeof(vss1->opt)); - vss1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_VSS); - vss1->data[0] = 1; // type - vss1->data[1] = vss->vpn_id.oui >>16 & 0xff; - vss1->data[2] = vss->vpn_id.oui >>8 & 0xff; - vss1->data[3] = vss->vpn_id.oui & 0xff; - vss1->data[4] = vss->vpn_id.fib_id >> 24 & 0xff; - vss1->data[5] = vss->vpn_id.fib_id >> 16 & 0xff; - vss1->data[6] = vss->vpn_id.fib_id >> 8 & 0xff; - vss1->data[7] = vss->vpn_id.fib_id & 0xff; - u1->length += sizeof(*vss1); - } - - pkts_to_server++; - u1->checksum = 0; - u1->src_port = clib_host_to_net_u16(UDP_DST_PORT_dhcpv6_to_client); - u1->dst_port = clib_host_to_net_u16(UDP_DST_PORT_dhcpv6_to_server); - - u1->length = - clib_host_to_net_u16( clib_net_to_host_u16(fwd_opt->length) + - sizeof(*r1) + sizeof(*fwd_opt) + - sizeof(*u1) + sizeof(*id1) + u1->length); - - memset(ip1, 0, sizeof(*ip1)); - ip1->ip_version_traffic_class_and_flow_label = 0x60; - ip1->payload_length = u1->length; - ip1->protocol = PROTO_UDP; - ip1->hop_limit = HOP_COUNT_LIMIT; - src = (server->dhcp6_server.as_u64[0] || server->dhcp6_server.as_u64[1]) ? - &server->dhcp6_server : &dpm->all_dhcpv6_server_address; - copy_ip6_address(&ip1->dst_address, src); - - - ia0 = ip6_interface_first_global_or_site_address - (&ip6_main, vnet_buffer(b0)->sw_if_index[VLIB_RX]); - - src = (server->dhcp6_src_address.as_u64[0] || server->dhcp6_src_address.as_u64[1]) ? - &server->dhcp6_src_address : ia0; - if (ia0 == 0) - { - error0 = DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS; - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; - pkts_no_src_address++; - goto do_trace; - } - - copy_ip6_address (&ip1->src_address, src); - - - u1->checksum = ip6_tcp_udp_icmp_compute_checksum(vm, b0, ip1, - &bogus_length); - ASSERT(bogus_length == 0); - - next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; - - do_trace: - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) - { - dhcpv6_proxy_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->which = 0; /* to server */ - tr->error = error0; - tr->original_sw_if_index = rx_sw_if_index; - tr->sw_if_index = sw_if_index; - if (DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP == next0) - copy_ip6_address((ip6_address_t *)&tr->packet_data[0], &server->dhcp6_server); - } - - do_enqueue: - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, - DHCPV6_PROXY_ERROR_RELAY_TO_CLIENT, - pkts_to_client); - vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, - DHCPV6_PROXY_ERROR_RELAY_TO_SERVER, - pkts_to_server); - vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, - DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS, - pkts_no_interface_address); - vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, - DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE, - pkts_wrong_msg_type); - vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, - DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS, - pkts_no_src_address); - vlib_node_increment_counter (vm, dhcpv6_proxy_to_server_node.index, - DHCPV6_PROXY_ERROR_PKT_TOO_BIG, - pkts_too_big); - return from_frame->n_vectors; -} - -VLIB_REGISTER_NODE (dhcpv6_proxy_to_server_node) = { - .function = dhcpv6_proxy_to_server_input, - .name = "dhcpv6-proxy-to-server", - /* Takes a vector of packets. */ - .vector_size = sizeof (u32), - - .n_errors = DHCPV6_PROXY_N_ERROR, - .error_strings = dhcpv6_proxy_error_strings, - - .n_next_nodes = DHCPV6_PROXY_TO_SERVER_INPUT_N_NEXT, - .next_nodes = { -#define _(s,n) [DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_##s] = n, - foreach_dhcpv6_proxy_to_server_input_next -#undef _ - }, - - .format_buffer = format_dhcpv6_proxy_header_with_length, - .format_trace = format_dhcpv6_proxy_trace, -#if 0 - .unformat_buffer = unformat_dhcpv6_proxy_header, -#endif -}; - -static uword -dhcpv6_proxy_to_client_input (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - - u32 n_left_from, * from; - ethernet_main_t *em = ethernet_get_main (vm); - dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; - dhcpv6_server_t * server; - vnet_main_t * vnm = vnet_get_main(); - int bogus_length; - - from = vlib_frame_vector_args (from_frame); - n_left_from = from_frame->n_vectors; - - while (n_left_from > 0) - { - u32 bi0; - vlib_buffer_t * b0; - udp_header_t * u0, *u1=0; - dhcpv6_relay_hdr_t * h0; - ip6_header_t * ip1 = 0, *ip0; - ip6_address_t _ia0, * ia0 = &_ia0; - ip6_address_t client_address; - ethernet_interface_t *ei0; - ethernet_header_t *mac0; - vnet_hw_interface_t *hi0; - vlib_frame_t *f0; - u32 * to_next0; - u32 sw_if_index = ~0; - u32 original_sw_if_index = ~0; - vnet_sw_interface_t *si0; - u32 error0 = (u32)~0; - vnet_sw_interface_t *swif; - dhcpv6_option_t *r0 = 0, *o; - u16 len = 0; - u8 interface_opt_flag = 0; - u8 relay_msg_opt_flag = 0; - ip6_main_t * im = &ip6_main; - u32 server_fib_idx, client_fib_idx; - - bi0 = from[0]; - from += 1; - n_left_from -= 1; - - b0 = vlib_get_buffer (vm, bi0); - h0 = vlib_buffer_get_current (b0); - - if (DHCPV6_MSG_RELAY_REPL != h0->msg_type) - { - error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE; - - drop_packet: - vlib_node_increment_counter (vm, dhcpv6_proxy_to_client_node.index, - error0, 1); - - f0 = vlib_get_frame_to_node (vm, dm->error_drop_node_index); - to_next0 = vlib_frame_vector_args (f0); - to_next0[0] = bi0; - f0->n_vectors = 1; - vlib_put_frame_to_node (vm, dm->error_drop_node_index, f0); - goto do_trace; - } - /* hop count seems not need to be checked */ - if (HOP_COUNT_LIMIT < h0->hop_count) - { - error0 = DHCPV6_RELAY_PKT_DROP_MAX_HOPS; - goto drop_packet; - } - u0 = (void *)h0 -(sizeof(*u0)); - ip0 = (void *)u0 -(sizeof(*ip0)); - - vlib_buffer_advance (b0, sizeof(*h0)); - o = vlib_buffer_get_current (b0); - - /* Parse through TLVs looking for option 18 (DHCPV6_OPTION_INTERFACE_ID) - _and_ option 9 (DHCPV6_OPTION_RELAY_MSG) option which must be there. - Currently assuming no other options need to be processed - The interface-ID is the FIB number we need - to track down the client-facing interface */ - - while ((u8 *) o < (b0->data + b0->current_data + b0->current_length)) - { - if (DHCPV6_OPTION_INTERFACE_ID == clib_net_to_host_u16(o->option)) - { - interface_opt_flag = 1; - if (clib_net_to_host_u16(o->length) == sizeof(sw_if_index)) - sw_if_index = clib_net_to_host_u32(((dhcpv6_int_id_t*)o)->int_idx); - if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index)) - { - error0 = DHCPV6_PROXY_ERROR_WRONG_INTERFACE_ID_OPTION; - goto drop_packet; - } - } - if (DHCPV6_OPTION_RELAY_MSG == clib_net_to_host_u16(o->option)) - { - relay_msg_opt_flag = 1; - r0 = vlib_buffer_get_current (b0); - } - if ((relay_msg_opt_flag == 1) && (interface_opt_flag == 1)) - break; - vlib_buffer_advance (b0, sizeof(*o) + clib_net_to_host_u16(o->length)); - o = (dhcpv6_option_t *) (((uword) o) + clib_net_to_host_u16(o->length) + sizeof(*o)); - } - - if ((relay_msg_opt_flag == 0) || (r0 == 0)) - { - error0 = DHCPV6_PROXY_ERROR_NO_RELAY_MESSAGE_OPTION; - goto drop_packet; - } - - if ((u32)~0 == sw_if_index) - { - error0 = DHCPV6_PROXY_ERROR_NO_CIRCUIT_ID_OPTION; - goto drop_packet; - } - - //Advance buffer to start of encapsulated DHCPv6 message - vlib_buffer_advance (b0, sizeof(*r0)); - - client_fib_idx = im->fib_index_by_sw_if_index[sw_if_index]; - server = dhcpv6_get_server(dm, client_fib_idx); - - if (NULL == server) - { - error0 = DHCPV6_PROXY_ERROR_NO_SERVER; - goto drop_packet; - } - - server_fib_idx = im->fib_index_by_sw_if_index - [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; - - if (server_fib_idx != server->server_fib6_index || - ip0->src_address.as_u64[0] != server->dhcp6_server.as_u64[0] || - ip0->src_address.as_u64[1] != server->dhcp6_server.as_u64[1]) - { - //drop packet if not from server with configured address or FIB - error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; - goto drop_packet; - } - - vnet_buffer (b0)->sw_if_index[VLIB_TX] = original_sw_if_index - = sw_if_index; - - swif = vnet_get_sw_interface (vnm, original_sw_if_index); - if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) - sw_if_index = swif->unnumbered_sw_if_index; - - - /* - * udp_local hands us the DHCPV6 header, need udp hdr, - * ip hdr to relay to client - */ - vlib_buffer_advance (b0, -(sizeof(*u1))); - u1 = vlib_buffer_get_current (b0); - - vlib_buffer_advance (b0, -(sizeof(*ip1))); - ip1 = vlib_buffer_get_current (b0); - - copy_ip6_address(&client_address, &h0->peer_addr); - - ia0 = ip6_interface_first_address (&ip6_main, sw_if_index); - if (ia0 == 0) - { - error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS; - goto drop_packet; - } - - len = clib_net_to_host_u16(r0->length); - memset(ip1, 0, sizeof(*ip1)); - copy_ip6_address(&ip1->dst_address, &client_address); - u1->checksum = 0; - u1->src_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcpv6_to_server); - u1->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcpv6_to_client); - u1->length = clib_host_to_net_u16 (len + sizeof(udp_header_t)); - - ip1->ip_version_traffic_class_and_flow_label = - ip0->ip_version_traffic_class_and_flow_label & - 0x00000fff; - ip1->payload_length = u1->length; - ip1->protocol = PROTO_UDP; - ip1->hop_limit = HOP_COUNT_LIMIT; - copy_ip6_address(&ip1->src_address, ia0); - - u1->checksum = ip6_tcp_udp_icmp_compute_checksum(vm, b0, ip1, - &bogus_length); - ASSERT(bogus_length == 0); - - vlib_buffer_advance (b0, -(sizeof(ethernet_header_t))); - si0 = vnet_get_sw_interface (vnm, original_sw_if_index); - if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) - vlib_buffer_advance (b0, -4 /* space for VLAN tag */); - - mac0 = vlib_buffer_get_current (b0); - - hi0 = vnet_get_sup_hw_interface (vnm, original_sw_if_index); - ei0 = pool_elt_at_index (em->interfaces, hi0->hw_instance); - clib_memcpy (mac0->src_address, ei0->address, sizeof (ei0->address)); - memset (&mac0->dst_address, 0xff, sizeof (mac0->dst_address)); - mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ? - clib_net_to_host_u16(0x8100) : clib_net_to_host_u16 (0x86dd); - - if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) - { - u32 * vlan_tag = (u32 *)(mac0+1); - u32 tmp; - tmp = (si0->sub.id << 16) | 0x0800; - *vlan_tag = clib_host_to_net_u32 (tmp); - } - - /* $$$ consider adding a dynamic next to the graph node, for performance */ - f0 = vlib_get_frame_to_node (vm, hi0->output_node_index); - to_next0 = vlib_frame_vector_args (f0); - to_next0[0] = bi0; - f0->n_vectors = 1; - vlib_put_frame_to_node (vm, hi0->output_node_index, f0); - - do_trace: - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) - { - dhcpv6_proxy_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->which = 1; /* to client */ - if (ia0) - copy_ip6_address((ip6_address_t*)tr->packet_data, ia0); - tr->error = error0; - tr->original_sw_if_index = original_sw_if_index; - tr->sw_if_index = sw_if_index; - } - } - return from_frame->n_vectors; - -} - -VLIB_REGISTER_NODE (dhcpv6_proxy_to_client_node) = { - .function = dhcpv6_proxy_to_client_input, - .name = "dhcpv6-proxy-to-client", - /* Takes a vector of packets. */ - .vector_size = sizeof (u32), - - .n_errors = DHCPV6_PROXY_N_ERROR, - .error_strings = dhcpv6_proxy_error_strings, - .format_buffer = format_dhcpv6_proxy_header_with_length, - .format_trace = format_dhcpv6_proxy_trace, -#if 0 - .unformat_buffer = unformat_dhcpv6_proxy_header, -#endif -}; - -clib_error_t * dhcpv6_proxy_init (vlib_main_t * vm) -{ - dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; - vlib_node_t * error_drop_node; - dhcpv6_server_t * server; - - dm->vlib_main = vm; - dm->vnet_main = vnet_get_main(); - error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); - dm->error_drop_node_index = error_drop_node->index; - - dm->vss_index_by_rx_fib_index = NULL; - - /* RFC says this is the dhcpv6 server address */ - dm->all_dhcpv6_server_address.as_u64[0] = clib_host_to_net_u64 (0xFF05000000000000); - dm->all_dhcpv6_server_address.as_u64[1] = clib_host_to_net_u64 (0x00010003); - - /* RFC says this is the server and agent address */ - dm->all_dhcpv6_server_relay_agent_address.as_u64[0] = clib_host_to_net_u64 (0xFF02000000000000); - dm->all_dhcpv6_server_relay_agent_address.as_u64[1] = clib_host_to_net_u64 (0x00010002); - - udp_register_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client, - dhcpv6_proxy_to_client_node.index, 0 /* is_ip6 */); - - udp_register_dst_port (vm, UDP_DST_PORT_dhcpv6_to_server, - dhcpv6_proxy_to_server_node.index, 0 /* is_ip6 */); - - /* Create the default server, don't mark it valid */ - pool_get (dm->dhcp6_servers, server); - memset (server, 0, sizeof (*server)); - - return 0; -} - -VLIB_INIT_FUNCTION (dhcpv6_proxy_init); - -int dhcpv6_proxy_set_server (ip6_address_t *addr, - ip6_address_t *src_address, - u32 rx_fib_id, - u32 server_fib_id, - int is_del) -{ - dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; - dhcpv6_server_t * server = 0; - u32 rx_fib_index = 0; - int rc = 0; - - rx_fib_index = ip6_mfib_table_find_or_create_and_lock(rx_fib_id); - - const mfib_prefix_t all_dhcp_servers = { - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - .fp_grp_addr = { - .ip6 = dm->all_dhcpv6_server_relay_agent_address, - } - }; - - if (is_del) - { - server = dhcpv6_get_server(dm, rx_fib_index); - - if (NULL == server) - { - rc = VNET_API_ERROR_NO_SUCH_ENTRY; - goto out; - } - - /* - * release the locks held on the server fib and rx mfib - */ - mfib_table_entry_delete(rx_fib_index, - &all_dhcp_servers, - MFIB_SOURCE_DHCP); - mfib_table_unlock(rx_fib_index, FIB_PROTOCOL_IP6); - fib_table_unlock(server->server_fib6_index, FIB_PROTOCOL_IP6); - - dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] = ~0; - - memset (server, 0, sizeof (*server)); - pool_put (dm->dhcp6_servers, server); - } - else - { - if (addr->as_u64[0] == 0 && - addr->as_u64[1] == 0 ) - { - rc = VNET_API_ERROR_INVALID_DST_ADDRESS; - goto out; - } - if (src_address->as_u64[0] == 0 && - src_address->as_u64[1] == 0) - { - rc = VNET_API_ERROR_INVALID_SRC_ADDRESS; - goto out; - } - - server = dhcpv6_get_server(dm, rx_fib_index); - - if (NULL != server) - { - /* modify of an existing entry */ - ip6_fib_t *fib; - - fib = ip6_fib_get(server->server_fib6_index); - - if (fib->table_id != server_fib_id) - { - /* swap tables */ - fib_table_unlock(server->server_fib6_index, FIB_PROTOCOL_IP6); - server->server_fib6_index = - ip6_fib_table_find_or_create_and_lock(server_fib_id); - } - } - else - { - /* Allocate a new server */ - pool_get (dm->dhcp6_servers, server); - - vec_validate_init_empty (dm->dhcp6_server_index_by_rx_fib_index, - rx_fib_index, ~0); - dm->dhcp6_server_index_by_rx_fib_index[rx_fib_index] = - server - dm->dhcp6_servers; - - server->server_fib6_index = - ip6_fib_table_find_or_create_and_lock(server_fib_id); - mfib_table_lock(rx_fib_index, FIB_PROTOCOL_IP6); - - const mfib_prefix_t all_dhcp_servers = { - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - .fp_grp_addr = { - .ip6 = dm->all_dhcpv6_server_relay_agent_address, - } - }; - const fib_route_path_t path_for_us = { - .frp_proto = FIB_PROTOCOL_IP6, - .frp_addr = zero_addr, - .frp_sw_if_index = 0xffffffff, - .frp_fib_index = ~0, - .frp_weight = 0, - .frp_flags = FIB_ROUTE_PATH_LOCAL, - }; - mfib_table_entry_path_update(rx_fib_index, - &all_dhcp_servers, - MFIB_SOURCE_DHCP, - &path_for_us, - MFIB_ITF_FLAG_FORWARD); - /* - * Each interface that is enabled in this table, needs to be added - * as an accepting interface, but this is not easily doable in VPP. - * So we cheat. Add a flag to the entry that indicates accept form - * any interface. - * We will still only accept on v6 enabled interfaces, since the - * input feature ensures this. - */ - mfib_table_entry_update(rx_fib_index, - &all_dhcp_servers, - MFIB_SOURCE_DHCP, - MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF); - } - copy_ip6_address(&server->dhcp6_server, addr); - copy_ip6_address(&server->dhcp6_src_address, src_address); - } - -out: - mfib_table_unlock(rx_fib_index, FIB_PROTOCOL_IP6); - - return (rc); -} - -static clib_error_t * -dhcpv6_proxy_set_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - ip6_address_t addr, src_addr; - int set_server = 0, set_src_address = 0; - u32 rx_fib_id = 0, server_fib_id = 0; - int is_del = 0; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "server %U", - unformat_ip6_address, &addr)) - set_server = 1; - else if (unformat(input, "src-address %U", - unformat_ip6_address, &src_addr)) - set_src_address =1; - else if (unformat (input, "server-fib-id %d", &server_fib_id)) - ; - else if (unformat (input, "rx-fib-id %d", &rx_fib_id)) - ; - else if (unformat (input, "delete") || - unformat (input, "del")) - is_del = 1; - else - break; - } - - if (is_del || (set_server && set_src_address)) - { - int rv; - - rv = dhcpv6_proxy_set_server (&addr, &src_addr, rx_fib_id, - server_fib_id, is_del); - - //TODO: Complete the errors - switch (rv) - { - case 0: - return 0; - - case -1: - return clib_error_return (0, "FIB id %d does not exist", server_fib_id); - - default: - return clib_error_return (0, "BUG: rv %d", rv); - } - } - else - return clib_error_return (0, "parse error`%U'", - format_unformat_error, input); -} - -VLIB_CLI_COMMAND (dhcpv6_proxy_set_command, static) = { - .path = "set dhcpv6 proxy", - .short_help = "set dhcpv6 proxy [del] server src-address " - "[server-fib-id ] [rx-fib-id ] ", - .function = dhcpv6_proxy_set_command_fn, -}; - -u8 * format_dhcpv6_proxy_server (u8 * s, va_list * args) -{ - dhcpv6_proxy_main_t * dm = va_arg (*args, dhcpv6_proxy_main_t *); - dhcpv6_server_t * server = va_arg (*args, dhcpv6_server_t *); - u32 rx_fib_index = va_arg (*args, u32); - ip6_fib_t * rx_fib, * server_fib; - u32 server_fib_id = (u32)~0, rx_fib_id = ~0; - - if (dm == 0) - { - s = format (s, "%=40s%=40s%=14s%=14s", "Server Address", "Source Address", - "Server FIB", "RX FIB"); - return s; - } - - server_fib = ip6_fib_get(server->server_fib6_index); - if (server_fib) - server_fib_id= server_fib->table_id; - - rx_fib= ip6_fib_get(rx_fib_index); - - if (rx_fib) - rx_fib_id = rx_fib->table_id; - - s = format (s, "%=40U%=40U%=14u%=14u", - format_ip6_address, &server->dhcp6_server, - format_ip6_address, &server->dhcp6_src_address, - server_fib_id, rx_fib_id); - return s; -} - -static clib_error_t * -dhcpv6_proxy_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - dhcpv6_proxy_main_t * dpm = &dhcpv6_proxy_main; - int i; - u32 server_index; - dhcpv6_server_t * server; - - vlib_cli_output (vm, "%U", format_dhcpv6_proxy_server, 0 /* header line */, - 0, 0); - vec_foreach_index (i, dpm->dhcp6_server_index_by_rx_fib_index) - { - server_index = dpm->dhcp6_server_index_by_rx_fib_index[i]; - if (~0 == server_index) - continue; - - server = pool_elt_at_index (dpm->dhcp6_servers, server_index); - - vlib_cli_output (vm, "%U", format_dhcpv6_proxy_server, dpm, - server, i); - } - - return 0; -} - -VLIB_CLI_COMMAND (dhcpv6_proxy_show_command, static) = { - .path = "show dhcpv6 proxy", - .short_help = "Display dhcpv6 proxy info", - .function = dhcpv6_proxy_show_command_fn, -}; - -void -dhcpv6_proxy_dump (void *opaque, - u32 context) -{ - dhcpv6_proxy_main_t * dpm = &dhcpv6_proxy_main; - ip6_fib_t *s_fib, *r_fib; - dhcpv6_server_t * server; - u32 server_index, i; - dhcpv6_vss_info *v; - - vec_foreach_index (i, dpm->dhcp6_server_index_by_rx_fib_index) - { - server_index = dpm->dhcp6_server_index_by_rx_fib_index[i]; - if (~0 == server_index) - continue; - - server = pool_elt_at_index (dpm->dhcp6_servers, server_index); - v = dhcpv6_get_vss_info(dpm, i); - - ip46_address_t src_addr = { - .ip6 = server->dhcp6_src_address, - }; - ip46_address_t server_addr = { - .ip6 = server->dhcp6_server, - }; - - s_fib = ip6_fib_get(server->server_fib6_index); - r_fib = ip6_fib_get(i); - - dhcp_send_details(opaque, - context, - &server_addr, - &src_addr, - s_fib->table_id, - r_fib->table_id, - (v ? v->vpn_id.fib_id : 0), - (v ? v->vpn_id.oui : 0)); - } -} - -int dhcpv6_proxy_set_vss(u32 tbl_id, - u32 oui, - u32 fib_id, - int is_del) -{ - dhcpv6_proxy_main_t *dm = &dhcpv6_proxy_main; - dhcpv6_vss_info *v = NULL; - u32 rx_fib_index; - int rc = 0; - - rx_fib_index = ip6_fib_table_find_or_create_and_lock(tbl_id); - v = dhcpv6_get_vss_info(dm, rx_fib_index); - - if (NULL != v) - { - if (is_del) - { - /* release the lock held on the table when the VSS - * info was created */ - fib_table_unlock (rx_fib_index, - FIB_PROTOCOL_IP6); - - pool_put (dm->vss, v); - dm->vss_index_by_rx_fib_index[rx_fib_index] = ~0; - } - else - { - /* this is a modify */ - v->vpn_id.fib_id = fib_id; - v->vpn_id.oui = oui; - } - } - else - { - if (is_del) - rc = VNET_API_ERROR_NO_SUCH_ENTRY; - else - { - /* create a new entry */ - vec_validate_init_empty(dm->vss_index_by_rx_fib_index, - rx_fib_index, ~0); - - /* hold a lock on the table whilst the VSS info exist */ - fib_table_lock (rx_fib_index, - FIB_PROTOCOL_IP6); - - pool_get (dm->vss, v); - v->vpn_id.fib_id = fib_id; - v->vpn_id.oui = oui; - dm->vss_index_by_rx_fib_index[rx_fib_index] = v - dm->vss; - } - } - - /* Release the lock taken during the create_or_lock at the start */ - fib_table_unlock (rx_fib_index, - FIB_PROTOCOL_IP6); - - return (rc); -} - - -static clib_error_t * -dhcpv6_vss_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - int is_del = 0, got_new_vss=0; - u32 oui=0; - u32 fib_id=0, tbl_id=~0; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "oui %d", &oui)) - got_new_vss = 1; - else if (unformat (input, "vpn-id %d", &fib_id)) - got_new_vss = 1; - else if (unformat (input, "table %d", &tbl_id)) - got_new_vss = 1; - else if (unformat(input, "delete") || unformat(input, "del")) - is_del = 1; - else - break; - } - - if (tbl_id ==~0) - return clib_error_return (0, "no table ID specified."); - - if (is_del || got_new_vss) - { - int rv; - - rv = dhcpv6_proxy_set_vss(tbl_id, oui, fib_id, is_del); - switch (rv) - { - case 0: - return 0; - - case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "vss info (oui:%d, vpn-id:%d) not found in table %d.", - oui, fib_id, tbl_id); - - case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "vss for table %d not found in pool.", - tbl_id); - - default: - return clib_error_return (0, "BUG: rv %d", rv); - } - } - else - return clib_error_return (0, "parse error`%U'", - format_unformat_error, input); - -} - -VLIB_CLI_COMMAND (dhcpv6_proxy_vss_command, static) = { - .path = "set dhcpv6 vss", - .short_help = "set dhcpv6 vss table oui vpn-idx ", - .function = dhcpv6_vss_command_fn, -}; - -static clib_error_t * -dhcpv6_vss_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) - -{ - dhcpv6_proxy_main_t * dm = &dhcpv6_proxy_main; - dhcpv6_vss_info *v; - ip6_fib_t *fib; - u32 *fib_index; - - vlib_cli_output (vm, "%=6s%=6s%=12s","Table", "OUI", "VPN ID"); - pool_foreach (fib_index, dm->vss_index_by_rx_fib_index, - ({ - fib = ip6_fib_get (*fib_index); - v = pool_elt_at_index (dm->vss, *fib_index); - - vlib_cli_output (vm, "%=6d%=6d%=12d", - fib->table_id, - v->vpn_id.oui, - v->vpn_id.fib_id); - })); - - return 0; -} - -VLIB_CLI_COMMAND (dhcpv6_proxy_vss_show_command, static) = { - .path = "show dhcpv6 vss", - .short_help = "show dhcpv6 VSS", - .function = dhcpv6_vss_show_command_fn, -}; - -static clib_error_t * -dhcpv6_link_address_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) - -{ - dhcpv6_proxy_main_t *dm = &dhcpv6_proxy_main; - vnet_main_t *vnm = vnet_get_main(); - u32 sw_if_index0=0, sw_if_index; - ip6_address_t *ia0; - vnet_sw_interface_t *swif; - - while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) - { - - if (unformat(input, "%U", - unformat_vnet_sw_interface, dm->vnet_main, &sw_if_index0)) - { - swif = vnet_get_sw_interface (vnm, sw_if_index0); - sw_if_index = (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) ? - swif->unnumbered_sw_if_index : sw_if_index0; - ia0 = ip6_interface_first_address(&ip6_main, sw_if_index); - if (ia0) - { - vlib_cli_output (vm, "%=20s%=48s", "interface", "link-address"); - - vlib_cli_output (vm, "%=20U%=48U", - format_vnet_sw_if_index_name, dm->vnet_main, sw_if_index0, - format_ip6_address, ia0); - } else - vlib_cli_output (vm, "%=34s%=20U", "No IPv6 address configured on", - format_vnet_sw_if_index_name, dm->vnet_main, sw_if_index); - } else - break; - } - - return 0; -} - -VLIB_CLI_COMMAND (dhcpv6_proxy_address_show_command, static) = { - .path = "show dhcpv6 link-address interface", - .short_help = "show dhcpv6 link-address interface ", - .function = dhcpv6_link_address_show_command_fn, -}; diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index 70b4e4c9..4cc6aa73 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -21,8 +21,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/test/test_dhcp.py b/test/test_dhcp.py index fbfb8a0c..6299975b 100644 --- a/test/test_dhcp.py +++ b/test/test_dhcp.py @@ -293,7 +293,7 @@ class TestDHCP(VppTestCase): # # Inject a response from the server # dropped, because there is no IP addrees on the - # clinet interfce to fill in the option. + # 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) / -- cgit 1.2.3-korg From a1a093d4e46e38503332a97ad216f80053a15f2b Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Thu, 2 Mar 2017 13:13:23 -0500 Subject: Clean up binary api message handler registration issues Removed a fair number of "BUG" message handlers, due to conflicts with actual message handlers in api_format.c. Vpp itself had no business receiving certain messages, up to the point where we started building in relevant code from vpp_api_test. Eliminated all but one duplicate registration complaint. That one needs attention from the vxlan team since the duplicated handlers have diverged. Change-Id: Iafce5429d2f906270643b4ea5f0130e20beb4d1d Signed-off-by: Dave Barach --- src/vat/api_format.c | 43 ++++++- src/vlib/unix/input.c | 31 ++++- src/vlibapi/api.h | 15 +++ src/vlibapi/api_shared.c | 4 + src/vnet/classify/classify_api.c | 8 -- src/vnet/devices/virtio/vhost_user_api.c | 10 +- src/vnet/dhcp/dhcp_api.c | 8 -- src/vnet/interface_api.c | 7 - src/vnet/ip/ip_api.c | 83 ------------ src/vnet/l2/l2_api.c | 22 ---- src/vnet/mpls/mpls_api.c | 28 +--- src/vpp/api/api.c | 211 ------------------------------- src/vpp/api/api_main.c | 1 - src/vpp/stats/stats.c | 7 - 14 files changed, 81 insertions(+), 397 deletions(-) (limited to 'src/vnet/dhcp/dhcp_api.c') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 1321bade..52436917 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -944,6 +944,7 @@ static void vl_api_sw_interface_details_t_handler_json } } +#if VPP_API_TEST_BUILTIN == 0 static void vl_api_sw_interface_set_flags_t_handler (vl_api_sw_interface_set_flags_t * mp) { @@ -954,6 +955,7 @@ static void vl_api_sw_interface_set_flags_t_handler mp->admin_up_down ? "admin-up" : "admin-down", mp->link_up_down ? "link-up" : "link-down"); } +#endif static void vl_api_sw_interface_set_flags_t_handler_json (vl_api_sw_interface_set_flags_t * mp) @@ -4009,7 +4011,6 @@ foreach_standard_reply_retval_handler; #define foreach_vpe_api_reply_msg \ _(CREATE_LOOPBACK_REPLY, create_loopback_reply) \ _(SW_INTERFACE_DETAILS, sw_interface_details) \ -_(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \ _(SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply) \ _(CONTROL_PING_REPLY, control_ping_reply) \ _(CLI_REPLY, cli_reply) \ @@ -4126,11 +4127,6 @@ _(IKEV2_INITIATE_REKEY_CHILD_SA_REPLY, ikev2_initiate_rekey_child_sa_reply) \ _(DELETE_LOOPBACK_REPLY, delete_loopback_reply) \ _(BD_IP_MAC_ADD_DEL_REPLY, bd_ip_mac_add_del_reply) \ _(DHCP_COMPL_EVENT, dhcp_compl_event) \ -_(VNET_INTERFACE_COUNTERS, vnet_interface_counters) \ -_(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \ -_(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \ -_(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters) \ -_(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) \ _(MAP_ADD_DOMAIN_REPLY, map_add_domain_reply) \ _(MAP_DEL_DOMAIN_REPLY, map_del_domain_reply) \ _(MAP_ADD_DEL_RULE_REPLY, map_add_del_rule_reply) \ @@ -4232,6 +4228,14 @@ _(SW_INTERFACE_SET_MTU_REPLY, sw_interface_set_mtu_reply) \ _(IP_NEIGHBOR_DETAILS, ip_neighbor_details) \ _(SW_INTERFACE_GET_TABLE_REPLY, sw_interface_get_table_reply) +#define foreach_standalone_reply_msg \ +_(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \ +_(VNET_INTERFACE_COUNTERS, vnet_interface_counters) \ +_(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \ +_(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \ +_(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters) \ +_(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) + typedef struct { u8 *name; @@ -15425,7 +15429,15 @@ api_af_packet_create (vat_main_t * vam) vec_free (host_if_name); S (mp); - W2 (ret, fprintf (vam->ofp, " new sw_if_index = %d ", vam->sw_if_index)); + + /* *INDENT-OFF* */ + W2 (ret, + ({ + if (ret == 0) + fprintf (vam->ofp ? vam->ofp : stderr, + " new sw_if_index = %d\n", vam->sw_if_index); + })); + /* *INDENT-ON* */ return ret; } @@ -18417,6 +18429,9 @@ _(unset, "usage: unset ") } \ } foreach_vpe_api_reply_msg; +#if VPP_API_TEST_BUILTIN == 0 +foreach_standalone_reply_msg; +#endif #undef _ void @@ -18430,6 +18445,9 @@ vat_api_hookup (vat_main_t * vam) vl_api_##n##_t_print, \ sizeof(vl_api_##n##_t), 1); foreach_vpe_api_reply_msg; +#if VPP_API_TEST_BUILTIN == 0 + foreach_standalone_reply_msg; +#endif #undef _ #if (VPP_API_TEST_BUILTIN==0) @@ -18463,6 +18481,17 @@ vat_api_hookup (vat_main_t * vam) #undef _ } +#if VPP_API_TEST_BUILTIN +static clib_error_t * +vat_api_hookup_shim (vlib_main_t * vm) +{ + vat_api_hookup (&vat_main); + return 0; +} + +VLIB_API_INIT_FUNCTION (vat_api_hookup_shim); +#endif + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vlib/unix/input.c b/src/vlib/unix/input.c index 07096ed2..7b4183a4 100644 --- a/src/vlib/unix/input.c +++ b/src/vlib/unix/input.c @@ -66,6 +66,7 @@ linux_epoll_file_update (unix_file_t * f, unix_file_update_type_t update_type) unix_main_t *um = &unix_main; linux_epoll_main_t *em = &linux_epoll_main; struct epoll_event e; + int op; memset (&e, 0, sizeof (e)); @@ -76,13 +77,29 @@ linux_epoll_file_update (unix_file_t * f, unix_file_update_type_t update_type) e.events |= EPOLLET; e.data.u32 = f - um->file_pool; - if (epoll_ctl (em->epoll_fd, - (update_type == UNIX_FILE_UPDATE_ADD - ? EPOLL_CTL_ADD - : (update_type == UNIX_FILE_UPDATE_MODIFY - ? EPOLL_CTL_MOD - : EPOLL_CTL_DEL)), f->file_descriptor, &e) < 0) - clib_warning ("epoll_ctl"); + op = -1; + + switch (update_type) + { + case UNIX_FILE_UPDATE_ADD: + op = EPOLL_CTL_ADD; + break; + + case UNIX_FILE_UPDATE_MODIFY: + op = EPOLL_CTL_MOD; + break; + + case UNIX_FILE_UPDATE_DELETE: + op = EPOLL_CTL_DEL; + break; + + default: + clib_warning ("unknown update_type %d", update_type); + return; + } + + if (epoll_ctl (em->epoll_fd, op, f->file_descriptor, &e) < 0) + clib_unix_warning ("epoll_ctl"); } static uword diff --git a/src/vlibapi/api.h b/src/vlibapi/api.h index fcb101d7..b40ece15 100644 --- a/src/vlibapi/api.h +++ b/src/vlibapi/api.h @@ -271,6 +271,21 @@ vlib_node_t **vlib_node_unserialize (u8 * vector); #define VLIB_API_INIT_FUNCTION(x) VLIB_DECLARE_INIT_FUNCTION(x,api_init) +/* Call given init function: used for init function dependencies. */ +#define vlib_call_api_init_function(vm, x) \ + ({ \ + extern vlib_init_function_t * _VLIB_INIT_FUNCTION_SYMBOL (x,api_init); \ + vlib_init_function_t * _f = _VLIB_INIT_FUNCTION_SYMBOL (x,api_init); \ + clib_error_t * _error = 0; \ + if (! hash_get (vm->init_functions_called, _f)) \ + { \ + hash_set1 (vm->init_functions_called, _f); \ + _error = _f (vm); \ + } \ + _error; \ + }) + + #endif /* included_api_h */ /* diff --git a/src/vlibapi/api_shared.c b/src/vlibapi/api_shared.c index 1a2740e2..79921afe 100644 --- a/src/vlibapi/api_shared.c +++ b/src/vlibapi/api_shared.c @@ -667,6 +667,10 @@ vl_msg_api_config (vl_msg_api_msg_config_t * c) foreach_msg_api_vector; #undef _ + if (am->msg_names[c->id]) + clib_warning ("BUG: multiple registrations of 'vl_api_%s_t_handler'", + c->name); + am->msg_names[c->id] = c->name; am->msg_handlers[c->id] = c->handler; am->msg_cleanup_handlers[c->id] = c->cleanup; diff --git a/src/vnet/classify/classify_api.c b/src/vnet/classify/classify_api.c index 77a8b434..24c7a2b9 100644 --- a/src/vnet/classify/classify_api.c +++ b/src/vnet/classify/classify_api.c @@ -53,7 +53,6 @@ _(CLASSIFY_TABLE_IDS,classify_table_ids) \ _(CLASSIFY_TABLE_BY_INTERFACE, classify_table_by_interface) \ _(CLASSIFY_TABLE_INFO,classify_table_info) \ _(CLASSIFY_SESSION_DUMP,classify_session_dump) \ -_(CLASSIFY_SESSION_DETAILS,classify_session_details) \ _(POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface) \ _(POLICER_CLASSIFY_DUMP, policer_classify_dump) \ _(FLOW_CLASSIFY_SET_INTERFACE, flow_classify_set_interface) \ @@ -356,13 +355,6 @@ vl_api_classify_table_info_t_handler (vl_api_classify_table_info_t * mp) vl_msg_api_send_shmem (q, (u8 *) & rmp); } -static void -vl_api_classify_session_details_t_handler (vl_api_classify_session_details_t * - mp) -{ - clib_warning ("BUG"); -} - static void send_classify_session_details (unix_shared_memory_queue_t * q, u32 table_id, diff --git a/src/vnet/devices/virtio/vhost_user_api.c b/src/vnet/devices/virtio/vhost_user_api.c index dd517c26..8dbd032b 100644 --- a/src/vnet/devices/virtio/vhost_user_api.c +++ b/src/vnet/devices/virtio/vhost_user_api.c @@ -46,8 +46,7 @@ _(CREATE_VHOST_USER_IF, create_vhost_user_if) \ _(MODIFY_VHOST_USER_IF, modify_vhost_user_if) \ _(DELETE_VHOST_USER_IF, delete_vhost_user_if) \ -_(SW_INTERFACE_VHOST_USER_DUMP, sw_interface_vhost_user_dump) \ -_(SW_INTERFACE_VHOST_USER_DETAILS, sw_interface_vhost_user_details) +_(SW_INTERFACE_VHOST_USER_DUMP, sw_interface_vhost_user_dump) /* * WARNING: replicated pending api refactor completion @@ -148,13 +147,6 @@ vl_api_delete_vhost_user_if_t_handler (vl_api_delete_vhost_user_if_t * mp) } } -static void - vl_api_sw_interface_vhost_user_details_t_handler - (vl_api_sw_interface_vhost_user_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_sw_interface_vhost_user_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index bdf02cae..ce34f6a4 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -46,7 +46,6 @@ #define foreach_vpe_api_msg \ _(DHCP_PROXY_CONFIG,dhcp_proxy_config) \ _(DHCP_PROXY_DUMP,dhcp_proxy_dump) \ -_(DHCP_PROXY_DETAILS,dhcp_proxy_details) \ _(DHCP_PROXY_SET_VSS,dhcp_proxy_set_vss) \ _(DHCP_CLIENT_CONFIG, dhcp_client_config) @@ -158,13 +157,6 @@ dhcp_send_details (fib_protocol_t proto, vl_msg_api_send_shmem (q, (u8 *) & mp); } - -static void -vl_api_dhcp_proxy_details_t_handler (vl_api_dhcp_proxy_details_t * mp) -{ - clib_warning ("BUG"); -} - void dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, u8 is_ipv6, u8 * host_address, u8 * router_address, diff --git a/src/vnet/interface_api.c b/src/vnet/interface_api.c index 63f7cad4..60cd6d40 100644 --- a/src/vnet/interface_api.c +++ b/src/vnet/interface_api.c @@ -50,7 +50,6 @@ _(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \ _(SW_INTERFACE_SET_MTU, sw_interface_set_mtu) \ _(WANT_INTERFACE_EVENTS, want_interface_events) \ _(SW_INTERFACE_DUMP, sw_interface_dump) \ -_(SW_INTERFACE_DETAILS, sw_interface_details) \ _(SW_INTERFACE_ADD_DEL_ADDRESS, sw_interface_add_del_address) \ _(SW_INTERFACE_SET_TABLE, sw_interface_set_table) \ _(SW_INTERFACE_GET_TABLE, sw_interface_get_table) \ @@ -684,12 +683,6 @@ out: REPLY_MACRO (VL_API_SW_INTERFACE_TAG_ADD_DEL_REPLY); } -static void -vl_api_sw_interface_details_t_handler (vl_api_sw_interface_details_t * mp) -{ - clib_warning ("BUG"); -} - /* * vpe_api_hookup * Add vpe's API message handlers to the table. diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c index 49d941c2..ab164a5f 100644 --- a/src/vnet/ip/ip_api.c +++ b/src/vnet/ip/ip_api.c @@ -59,17 +59,12 @@ #define foreach_ip_api_msg \ _(IP_FIB_DUMP, ip_fib_dump) \ -_(IP_FIB_DETAILS, ip_fib_details) \ _(IP6_FIB_DUMP, ip6_fib_dump) \ -_(IP6_FIB_DETAILS, ip6_fib_details) \ _(IP_MFIB_DUMP, ip_mfib_dump) \ -_(IP_MFIB_DETAILS, ip_mfib_details) \ _(IP6_MFIB_DUMP, ip6_mfib_dump) \ -_(IP6_MFIB_DETAILS, ip6_mfib_details) \ _(IP_NEIGHBOR_DUMP, ip_neighbor_dump) \ _(IP_MROUTE_ADD_DEL, ip_mroute_add_del) \ _(MFIB_SIGNAL_DUMP, mfib_signal_dump) \ -_(IP_NEIGHBOR_DETAILS, ip_neighbor_details) \ _(IP_ADDRESS_DUMP, ip_address_dump) \ _(IP_DUMP, ip_dump) \ _(IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del) \ @@ -105,12 +100,6 @@ send_ip_neighbor_details (u8 is_ipv6, vl_msg_api_send_shmem (q, (u8 *) & mp); } -static void -vl_api_ip_neighbor_details_t_handler (vl_api_ip_neighbor_details_t * mp) -{ - clib_warning ("BUG"); -} - static void vl_api_ip_neighbor_dump_t_handler (vl_api_ip_neighbor_dump_t * mp) { @@ -185,24 +174,6 @@ copy_fib_next_hop (fib_route_path_encode_t * api_rpath, void *fp_arg) sizeof (api_rpath->rpath.frp_addr.ip6)); } -static void -vl_api_ip_fib_details_t_handler (vl_api_ip_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip_fib_details_t_endian (vl_api_ip_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip_fib_details_t_print (vl_api_ip_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_ip_fib_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, @@ -316,24 +287,6 @@ vl_api_ip_fib_dump_t_handler (vl_api_ip_fib_dump_t * mp) vec_free (lfeis); } -static void -vl_api_ip6_fib_details_t_handler (vl_api_ip6_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip6_fib_details_t_endian (vl_api_ip6_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip6_fib_details_t_print (vl_api_ip6_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_ip6_fib_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, @@ -469,24 +422,6 @@ vl_api_ip6_fib_dump_t_handler (vl_api_ip6_fib_dump_t * mp) /* *INDENT-ON* */ } -static void -vl_api_ip_mfib_details_t_handler (vl_api_ip_mfib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip_mfib_details_t_endian (vl_api_ip_mfib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip_mfib_details_t_print (vl_api_ip_mfib_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_ip_mfib_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, @@ -591,24 +526,6 @@ vl_api_ip_mfib_dump_t_handler (vl_api_ip_mfib_dump_t * mp) vec_free (api_rpaths); } -static void -vl_api_ip6_mfib_details_t_handler (vl_api_ip6_mfib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip6_mfib_details_t_endian (vl_api_ip6_mfib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip6_mfib_details_t_print (vl_api_ip6_mfib_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_ip6_mfib_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index a3cc49bf..a985852c 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -48,13 +48,10 @@ _(L2_XCONNECT_DUMP, l2_xconnect_dump) \ _(L2_FIB_CLEAR_TABLE, l2_fib_clear_table) \ _(L2_FIB_TABLE_DUMP, l2_fib_table_dump) \ -_(L2_FIB_TABLE_ENTRY, l2_fib_table_entry) \ _(L2FIB_ADD_DEL, l2fib_add_del) \ _(L2_FLAGS, l2_flags) \ _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \ _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ -_(BRIDGE_DOMAIN_DETAILS, bridge_domain_details) \ -_(BRIDGE_DOMAIN_SW_IF_DETAILS, bridge_domain_sw_if_details) \ _(BRIDGE_FLAGS, bridge_flags) \ _(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \ _(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) @@ -140,12 +137,6 @@ send_l2fib_table_entry (vpe_api_main_t * am, vl_msg_api_send_shmem (q, (u8 *) & mp); } -static void -vl_api_l2_fib_table_entry_t_handler (vl_api_l2_fib_table_entry_t * mp) -{ - clib_warning ("BUG"); -} - static void vl_api_l2_fib_table_dump_t_handler (vl_api_l2_fib_table_dump_t * mp) { @@ -329,19 +320,6 @@ vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp) REPLY_MACRO (VL_API_BRIDGE_DOMAIN_ADD_DEL_REPLY); } -static void -vl_api_bridge_domain_details_t_handler (vl_api_bridge_domain_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void - vl_api_bridge_domain_sw_if_details_t_handler - (vl_api_bridge_domain_sw_if_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_bridge_domain_details (unix_shared_memory_queue_t * q, l2_bridge_domain_t * bd_config, diff --git a/src/vnet/mpls/mpls_api.c b/src/vnet/mpls/mpls_api.c index ebbeba69..a36a5046 100644 --- a/src/vnet/mpls/mpls_api.c +++ b/src/vnet/mpls/mpls_api.c @@ -50,9 +50,7 @@ _(MPLS_IP_BIND_UNBIND, mpls_ip_bind_unbind) \ _(MPLS_ROUTE_ADD_DEL, mpls_route_add_del) \ _(MPLS_TUNNEL_ADD_DEL, mpls_tunnel_add_del) \ _(MPLS_TUNNEL_DUMP, mpls_tunnel_dump) \ -_(MPLS_TUNNEL_DETAILS, mpls_tunnel_details) \ -_(MPLS_FIB_DUMP, mpls_fib_dump) \ -_(MPLS_FIB_DETAILS, mpls_fib_details) +_(MPLS_FIB_DUMP, mpls_fib_dump) extern void stats_dslock_with_hint (int hint, int tag); extern void stats_dsunlock (void); @@ -280,12 +278,6 @@ vl_api_mpls_tunnel_add_del_t_handler (vl_api_mpls_tunnel_add_del_t * mp) /* *INDENT-ON* */ } -static void -vl_api_mpls_tunnel_details_t_handler (vl_api_mpls_tunnel_details_t * mp) -{ - clib_warning ("BUG"); -} - typedef struct mpls_tunnel_send_walk_ctx_t_ { unix_shared_memory_queue_t *q; @@ -340,24 +332,6 @@ vl_api_mpls_tunnel_dump_t_handler (vl_api_mpls_tunnel_dump_t * mp) mpls_tunnel_walk (send_mpls_tunnel_entry, &ctx); } -static void -vl_api_mpls_fib_details_t_handler (vl_api_mpls_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_mpls_fib_details_t_endian (vl_api_mpls_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_mpls_fib_details_t_print (vl_api_mpls_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_mpls_fib_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 60fd0199..a8f471e8 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -128,12 +128,8 @@ _(CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table) \ _(CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables) \ _(GET_NODE_INDEX, get_node_index) \ _(ADD_NODE_NEXT, add_node_next) \ -_(VXLAN_ADD_DEL_TUNNEL, vxlan_add_del_tunnel) \ -_(VXLAN_TUNNEL_DUMP, vxlan_tunnel_dump) \ _(L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter) \ _(SHOW_VERSION, show_version) \ -_(VXLAN_GPE_ADD_DEL_TUNNEL, vxlan_gpe_add_del_tunnel) \ -_(VXLAN_GPE_TUNNEL_DUMP, vxlan_gpe_tunnel_dump) \ _(INTERFACE_NAME_RENUMBER, interface_name_renumber) \ _(WANT_IP4_ARP_EVENTS, want_ip4_arp_events) \ _(WANT_IP6_ND_EVENTS, want_ip6_nd_events) \ @@ -1436,62 +1432,6 @@ out: /* *INDENT-ON* */ } -static void vl_api_vxlan_add_del_tunnel_t_handler - (vl_api_vxlan_add_del_tunnel_t * mp) -{ - vl_api_vxlan_add_del_tunnel_reply_t *rmp; - int rv = 0; - vnet_vxlan_add_del_tunnel_args_t _a, *a = &_a; - u32 encap_fib_index; - uword *p; - ip4_main_t *im = &ip4_main; - vnet_main_t *vnm = vnet_get_main (); - u32 sw_if_index = ~0; - - p = hash_get (im->fib_index_by_table_id, ntohl (mp->encap_vrf_id)); - if (!p) - { - rv = VNET_API_ERROR_NO_SUCH_FIB; - goto out; - } - encap_fib_index = p[0]; - memset (a, 0, sizeof (*a)); - - a->is_add = mp->is_add; - a->is_ip6 = mp->is_ipv6; - - /* ip addresses sent in network byte order */ - ip46_from_addr_buf (mp->is_ipv6, mp->dst_address, &a->dst); - ip46_from_addr_buf (mp->is_ipv6, mp->src_address, &a->src); - - /* Check src & dst are different */ - if (ip46_address_cmp (&a->dst, &a->src) == 0) - { - rv = VNET_API_ERROR_SAME_SRC_DST; - goto out; - } - a->mcast_sw_if_index = ntohl (mp->mcast_sw_if_index); - if (ip46_address_is_multicast (&a->dst) && - pool_is_free_index (vnm->interface_main.sw_interfaces, - a->mcast_sw_if_index)) - { - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - goto out; - } - a->encap_fib_index = encap_fib_index; - a->decap_next_index = ntohl (mp->decap_next_index); - a->vni = ntohl (mp->vni); - rv = vnet_vxlan_add_del_tunnel (a, &sw_if_index); - -out: - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_VXLAN_ADD_DEL_TUNNEL_REPLY, - ({ - rmp->sw_if_index = ntohl (sw_if_index); - })); - /* *INDENT-ON* */ -} - static void send_vxlan_tunnel_details (vxlan_tunnel_t * t, unix_shared_memory_queue_t * q, u32 context) { @@ -1525,43 +1465,6 @@ static void send_vxlan_tunnel_details vl_msg_api_send_shmem (q, (u8 *) & rmp); } -static void vl_api_vxlan_tunnel_dump_t_handler - (vl_api_vxlan_tunnel_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - vxlan_main_t *vxm = &vxlan_main; - vxlan_tunnel_t *t; - u32 sw_if_index; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - { - return; - } - - sw_if_index = ntohl (mp->sw_if_index); - - if (~0 == sw_if_index) - { - /* *INDENT-OFF* */ - pool_foreach (t, vxm->tunnels, - ({ - send_vxlan_tunnel_details(t, q, mp->context); - })); - /* *INDENT-ON* */ - } - else - { - if ((sw_if_index >= vec_len (vxm->tunnel_index_by_sw_if_index)) || - (~0 == vxm->tunnel_index_by_sw_if_index[sw_if_index])) - { - return; - } - t = &vxm->tunnels[vxm->tunnel_index_by_sw_if_index[sw_if_index]]; - send_vxlan_tunnel_details (t, q, mp->context); - } -} - static void vl_api_l2_patch_add_del_t_handler (vl_api_l2_patch_add_del_t * mp) { @@ -1585,83 +1488,6 @@ vl_api_l2_patch_add_del_t_handler (vl_api_l2_patch_add_del_t * mp) REPLY_MACRO (VL_API_L2_PATCH_ADD_DEL_REPLY); } -static void - vl_api_vxlan_gpe_add_del_tunnel_t_handler - (vl_api_vxlan_gpe_add_del_tunnel_t * mp) -{ - vl_api_vxlan_gpe_add_del_tunnel_reply_t *rmp; - int rv = 0; - vnet_vxlan_gpe_add_del_tunnel_args_t _a, *a = &_a; - u32 encap_fib_index, decap_fib_index; - u8 protocol; - uword *p; - ip4_main_t *im = &ip4_main; - u32 sw_if_index = ~0; - - - p = hash_get (im->fib_index_by_table_id, ntohl (mp->encap_vrf_id)); - if (!p) - { - rv = VNET_API_ERROR_NO_SUCH_FIB; - goto out; - } - encap_fib_index = p[0]; - - protocol = mp->protocol; - - /* Interpret decap_vrf_id as an opaque if sending to other-than-ip4-input */ - if (protocol == VXLAN_GPE_INPUT_NEXT_IP4_INPUT) - { - p = hash_get (im->fib_index_by_table_id, ntohl (mp->decap_vrf_id)); - if (!p) - { - rv = VNET_API_ERROR_NO_SUCH_INNER_FIB; - goto out; - } - decap_fib_index = p[0]; - } - else - { - decap_fib_index = ntohl (mp->decap_vrf_id); - } - - /* Check src & dst are different */ - if ((mp->is_ipv6 && memcmp (mp->local, mp->remote, 16) == 0) || - (!mp->is_ipv6 && memcmp (mp->local, mp->remote, 4) == 0)) - { - rv = VNET_API_ERROR_SAME_SRC_DST; - goto out; - } - memset (a, 0, sizeof (*a)); - - a->is_add = mp->is_add; - a->is_ip6 = mp->is_ipv6; - /* ip addresses sent in network byte order */ - if (a->is_ip6) - { - clib_memcpy (&(a->local.ip6), mp->local, 16); - clib_memcpy (&(a->remote.ip6), mp->remote, 16); - } - else - { - clib_memcpy (&(a->local.ip4), mp->local, 4); - clib_memcpy (&(a->remote.ip4), mp->remote, 4); - } - a->encap_fib_index = encap_fib_index; - a->decap_fib_index = decap_fib_index; - a->protocol = protocol; - a->vni = ntohl (mp->vni); - rv = vnet_vxlan_gpe_add_del_tunnel (a, &sw_if_index); - -out: - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_VXLAN_GPE_ADD_DEL_TUNNEL_REPLY, - ({ - rmp->sw_if_index = ntohl (sw_if_index); - })); - /* *INDENT-ON* */ -} - static void send_vxlan_gpe_tunnel_details (vxlan_gpe_tunnel_t * t, unix_shared_memory_queue_t * q, u32 context) { @@ -1696,43 +1522,6 @@ static void send_vxlan_gpe_tunnel_details vl_msg_api_send_shmem (q, (u8 *) & rmp); } -static void vl_api_vxlan_gpe_tunnel_dump_t_handler - (vl_api_vxlan_gpe_tunnel_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - vxlan_gpe_main_t *vgm = &vxlan_gpe_main; - vxlan_gpe_tunnel_t *t; - u32 sw_if_index; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - { - return; - } - - sw_if_index = ntohl (mp->sw_if_index); - - if (~0 == sw_if_index) - { - /* *INDENT-OFF* */ - pool_foreach (t, vgm->tunnels, - ({ - send_vxlan_gpe_tunnel_details(t, q, mp->context); - })); - /* *INDENT-ON* */ - } - else - { - if ((sw_if_index >= vec_len (vgm->tunnel_index_by_sw_if_index)) || - (~0 == vgm->tunnel_index_by_sw_if_index[sw_if_index])) - { - return; - } - t = &vgm->tunnels[vgm->tunnel_index_by_sw_if_index[sw_if_index]]; - send_vxlan_gpe_tunnel_details (t, q, mp->context); - } -} - static void vl_api_interface_name_renumber_t_handler (vl_api_interface_name_renumber_t * mp) diff --git a/src/vpp/api/api_main.c b/src/vpp/api/api_main.c index 97b501e0..6ae510b1 100644 --- a/src/vpp/api/api_main.c +++ b/src/vpp/api/api_main.c @@ -48,7 +48,6 @@ api_main_init (vlib_main_t * vm) vam->vlib_main = vm; vam->my_client_index = (u32) ~ 0; init_error_string_table (vam); - vat_api_hookup (vam); rv = vat_plugin_init (vam); if (rv) clib_warning ("vat_plugin_init returned %d", rv); diff --git a/src/vpp/stats/stats.c b/src/vpp/stats/stats.c index 5e9b0d69..c46d441a 100644 --- a/src/vpp/stats/stats.c +++ b/src/vpp/stats/stats.c @@ -46,7 +46,6 @@ stats_main_t stats_main; #define foreach_stats_msg \ _(WANT_STATS, want_stats) \ -_(WANT_STATS_REPLY, want_stats_reply) \ _(VNET_INTERFACE_COUNTERS, vnet_interface_counters) \ _(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \ _(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \ @@ -1226,12 +1225,6 @@ vl_api_vnet_ip6_nbr_counters_t_handler (vl_api_vnet_ip6_nbr_counters_t * mp) } } -static void -vl_api_want_stats_reply_t_handler (vl_api_want_stats_reply_t * mp) -{ - clib_warning ("BUG"); -} - static void vl_api_want_stats_t_handler (vl_api_want_stats_t * mp) { -- cgit 1.2.3-korg From 3466c30261950823828d1dad0d2fb170ee2f9aaf Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 16 Feb 2017 07:45:03 -0800 Subject: DHCP Multiple Servers (VPP-602, VPP-605) Multiple DHCP (4 and/or 6) servers can be added and removed through multiple calls to the 'set dhcp server' API. All 4/6/ discover/solicit messages will then be replicated to all servers in the list. The expectation is that the servers/system is configured in such a way that this is viable. If VSS information is providied for the clinet VRF which also has multiple servers configured, then the same VSS information is sent to each server. Likewise the source address of packets sent to from VPP to each server is the same. Change-Id: I3287cb084c84b3f612b78bc69cfcb5b9c1f8934d Signed-off-by: Neale Ranns --- src/scripts/vnet/dhcp/proxy | 3 +- src/vat/api_format.c | 56 ++++-- src/vnet/dhcp/client.c | 2 +- src/vnet/dhcp/dhcp.api | 12 +- src/vnet/dhcp/dhcp4_packet.h | 5 + src/vnet/dhcp/dhcp4_proxy_node.c | 151 +++++++++++++---- src/vnet/dhcp/dhcp6_proxy_node.c | 158 ++++++++++++----- src/vnet/dhcp/dhcp_api.c | 66 +++++--- src/vnet/dhcp/dhcp_proxy.c | 129 +++++++------- src/vnet/dhcp/dhcp_proxy.h | 85 +++++++--- src/vnet/ip/ip6_packet.h | 2 + src/vnet/pg/input.c | 6 + test/test_dhcp.py | 356 ++++++++++++++++++++++++++++++++++----- 13 files changed, 796 insertions(+), 235 deletions(-) (limited to 'src/vnet/dhcp/dhcp_api.c') diff --git a/src/scripts/vnet/dhcp/proxy b/src/scripts/vnet/dhcp/proxy index c709d87d..42dff2a0 100644 --- a/src/scripts/vnet/dhcp/proxy +++ b/src/scripts/vnet/dhcp/proxy @@ -14,7 +14,8 @@ set int ip addr loop0 2001::1/64 set int ip addr loop0 2001:1::1/64 set dhcp proxy server 10.255.0.1 src-address 10.0.0.1 server-fib-id 0 rx-fib-id 0 -set dhcp proxy server 10.255.0.2 src-address 10.0.1.1 server-fib-id 1 rx-fib-id 1 +set dhcp proxy server 10.255.0.2 src-address 10.0.0.1 server-fib-id 0 rx-fib-id 0 +set dhcp proxy server 10.255.1.2 src-address 10.0.1.1 server-fib-id 1 rx-fib-id 1 set dhcpv6 proxy server 3001::1 src-address 2001::1 server-fib-id 0 rx-fib-id 0 set dhcpv6 proxy server 3002::1 src-address 2001:1::1 server-fib-id 1 rx-fib-id 1 diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 0b60b910..b5943f03 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -7573,23 +7573,35 @@ static void vl_api_dhcp_proxy_details_t_handler (vl_api_dhcp_proxy_details_t * mp) { vat_main_t *vam = &vat_main; + u32 i, count = mp->count; + vl_api_dhcp_server_t *s; if (mp->is_ipv6) print (vam->ofp, - "RX Table-ID %d, Server Table-ID %d, Server Address %U, Source Address %U, VSS FIB-ID %d, VSS OUI %d", + "RX Table-ID %d, Source Address %U, VSS FIB-ID %d, VSS OUI %d", ntohl (mp->rx_vrf_id), - ntohl (mp->server_vrf_id), - format_ip6_address, mp->dhcp_server, format_ip6_address, mp->dhcp_src_address, ntohl (mp->vss_oui), ntohl (mp->vss_fib_id)); else print (vam->ofp, - "RX Table-ID %d, Server Table-ID %d, Server Address %U, Source Address %U, VSS FIB-ID %d, VSS OUI %d", + "RX Table-ID %d, Source Address %U, VSS FIB-ID %d, VSS OUI %d", ntohl (mp->rx_vrf_id), - ntohl (mp->server_vrf_id), - format_ip4_address, mp->dhcp_server, format_ip4_address, mp->dhcp_src_address, ntohl (mp->vss_oui), ntohl (mp->vss_fib_id)); + + for (i = 0; i < count; i++) + { + s = &mp->servers[i]; + + if (mp->is_ipv6) + print (vam->ofp, + " Server Table-ID %d, Server Address %U", + ntohl (s->server_vrf_id), format_ip6_address, s->dhcp_server); + else + print (vam->ofp, + " Server Table-ID %d, Server Address %U", + ntohl (s->server_vrf_id), format_ip4_address, s->dhcp_server); + } } static void vl_api_dhcp_proxy_details_t_handler_json @@ -7597,8 +7609,10 @@ static void vl_api_dhcp_proxy_details_t_handler_json { vat_main_t *vam = &vat_main; vat_json_node_t *node = NULL; + u32 i, count = mp->count; struct in_addr ip4; struct in6_addr ip6; + vl_api_dhcp_server_t *s; if (VAT_JSON_ARRAY != vam->json_tree.type) { @@ -7609,24 +7623,38 @@ static void vl_api_dhcp_proxy_details_t_handler_json vat_json_init_object (node); vat_json_object_add_uint (node, "rx-table-id", ntohl (mp->rx_vrf_id)); - vat_json_object_add_uint (node, "server-table-id", - ntohl (mp->server_vrf_id)); + vat_json_object_add_uint (node, "vss-fib-id", ntohl (mp->vss_fib_id)); + vat_json_object_add_uint (node, "vss-oui", ntohl (mp->vss_oui)); + if (mp->is_ipv6) { - clib_memcpy (&ip6, &mp->dhcp_server, sizeof (ip6)); - vat_json_object_add_ip6 (node, "server_address", ip6); clib_memcpy (&ip6, &mp->dhcp_src_address, sizeof (ip6)); vat_json_object_add_ip6 (node, "src_address", ip6); } else { - clib_memcpy (&ip4, &mp->dhcp_server, sizeof (ip4)); - vat_json_object_add_ip4 (node, "server_address", ip4); clib_memcpy (&ip4, &mp->dhcp_src_address, sizeof (ip4)); vat_json_object_add_ip4 (node, "src_address", ip4); } - vat_json_object_add_uint (node, "vss-fib-id", ntohl (mp->vss_fib_id)); - vat_json_object_add_uint (node, "vss-oui", ntohl (mp->vss_oui)); + + for (i = 0; i < count; i++) + { + s = &mp->servers[i]; + + vat_json_object_add_uint (node, "server-table-id", + ntohl (s->server_vrf_id)); + + if (mp->is_ipv6) + { + clib_memcpy (&ip4, &s->dhcp_server, sizeof (ip4)); + vat_json_object_add_ip4 (node, "src_address", ip4); + } + else + { + clib_memcpy (&ip6, &s->dhcp_server, sizeof (ip6)); + vat_json_object_add_ip6 (node, "server_address", ip6); + } + } } static int diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index d34c5a64..29749a33 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -366,7 +366,7 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c, o = (dhcp_option_t * )dhcp->options; /* Send option 53, the DHCP message type */ - o->option = 53; + o->option = DHCP_PACKET_OPTION_MSG_TYPE; o->length = 1; o->data[0] = type; o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api index 8daadd8c..2db85a79 100644 --- a/src/vnet/dhcp/dhcp.api +++ b/src/vnet/dhcp/dhcp.api @@ -137,19 +137,25 @@ define dhcp_proxy_dump u8 is_ip6; }; +typeonly manual_print manual_endian define dhcp_server +{ + u32 server_vrf_id; + u8 dhcp_server[16]; +}; + /** \brief Tell client about a DHCP completion event @param client_index - opaque cookie to identify the sender */ -define dhcp_proxy_details +manual_endian manual_print define dhcp_proxy_details { u32 context; u32 rx_vrf_id; - u32 server_vrf_id; u32 vss_oui; u32 vss_fib_id; u8 is_ipv6; - u8 dhcp_server[16]; u8 dhcp_src_address[16]; + u8 count; + vl_api_dhcp_server_t servers[count]; }; /* diff --git a/src/vnet/dhcp/dhcp4_packet.h b/src/vnet/dhcp/dhcp4_packet.h index 28c4b156..07829f48 100644 --- a/src/vnet/dhcp/dhcp4_packet.h +++ b/src/vnet/dhcp/dhcp4_packet.h @@ -55,6 +55,11 @@ typedef enum { DHCP_PACKET_ACK=5, } dhcp_packet_type_t; +typedef enum dhcp_packet_option_t_ +{ + DHCP_PACKET_OPTION_MSG_TYPE = 53, +} dhcp_packet_option_t; + /* charming antique: 99.130.83.99 is the dhcp magic cookie */ #define DHCP_MAGIC (clib_host_to_net_u32(0x63825363)) diff --git a/src/vnet/dhcp/dhcp4_proxy_node.c b/src/vnet/dhcp/dhcp4_proxy_node.c index 88a99249..1c84881a 100644 --- a/src/vnet/dhcp/dhcp4_proxy_node.c +++ b/src/vnet/dhcp/dhcp4_proxy_node.c @@ -135,18 +135,17 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, u32 original_sw_if_index = 0; u8 *end = NULL; u32 fib_index; - dhcp_server_t * server; + dhcp_proxy_t *proxy; + dhcp_server_t *server; u32 rx_sw_if_index; dhcp_option_t *o; u32 len = 0; vlib_buffer_free_list_t *fl; + u8 is_discover = 0; bi0 = from[0]; - to_next[0] = bi0; from += 1; - to_next += 1; n_left_from -= 1; - n_left_to_next -= 1; b0 = vlib_get_buffer (vm, bi0); @@ -172,16 +171,17 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, rx_sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; fib_index = im->fib_index_by_sw_if_index [rx_sw_if_index]; - server = dhcp_get_server(dpm, fib_index, FIB_PROTOCOL_IP4); - - if (PREDICT_FALSE (NULL == server)) + proxy = dhcp_get_proxy(dpm, fib_index, FIB_PROTOCOL_IP4); + + if (PREDICT_FALSE (NULL == proxy)) { error0 = DHCP_PROXY_ERROR_NO_SERVER; next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP; pkts_no_server++; goto do_trace; } - + + server = &proxy->dhcp_servers[0]; vlib_buffer_advance (b0, -(sizeof(*ip0))); ip0 = vlib_buffer_get_current (b0); @@ -198,7 +198,7 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, sum0 = ip0->checksum; old0 = ip0->src_address.as_u32; - new0 = server->dhcp_src_address.ip4.as_u32; + new0 = proxy->dhcp_src_address.ip4.as_u32; ip0->src_address.as_u32 = new0; sum0 = ip_csum_update (sum0, old0, new0, ip4_header_t /* structure */, @@ -209,7 +209,7 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, vnet_buffer(b0)->sw_if_index[VLIB_TX] = server->server_fib_index; - h0->gateway_ip_address.as_u32 = server->dhcp_src_address.ip4.as_u32; + h0->gateway_ip_address.as_u32 = proxy->dhcp_src_address.ip4.as_u32; pkts_to_server++; o = (dhcp_option_t *) h0->options; @@ -220,7 +220,16 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, end = b0->data + b0->current_data + b0->current_length; /* TLVs are not performance-friendly... */ while (o->option != 0xFF /* end of options */ && (u8 *)o < end) + { + if (DHCP_PACKET_OPTION_MSG_TYPE == o->option) + { + if (DHCP_PACKET_DISCOVER == o->data[0]) + { + is_discover = 1; + } + } o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + } fl = vlib_buffer_get_free_list (vm, b0->free_list_index); // start write at (option*)o, some packets have padding @@ -340,6 +349,65 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; + /* + * If we have multiple servers configured and this is the + * client's discover message, then send copies to each of + * those servers + */ + if (is_discover && vec_len(proxy->dhcp_servers) > 1) + { + u32 ii; + + for (ii = 1; ii < vec_len(proxy->dhcp_servers); ii++) + { + vlib_buffer_t *c0; + u32 ci0; + + c0 = vlib_buffer_copy(vm, b0); + ci0 = vlib_get_buffer_index(vm, c0); + server = &proxy->dhcp_servers[ii]; + + ip0 = vlib_buffer_get_current (c0); + + sum0 = ip0->checksum; + old0 = ip0->dst_address.as_u32; + new0 = server->dhcp_server.ip4.as_u32; + ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32; + sum0 = ip_csum_update (sum0, old0, new0, + ip4_header_t /* structure */, + dst_address /* changed member */); + ip0->checksum = ip_csum_fold (sum0); + + to_next[0] = ci0; + to_next += 1; + n_left_to_next -= 1; + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + ci0, next0); + + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + dhcp_proxy_trace_t *tr; + + tr = vlib_add_trace (vm, node, c0, sizeof (*tr)); + tr->which = 0; /* to server */ + tr->error = error0; + tr->original_sw_if_index = original_sw_if_index; + tr->sw_if_index = sw_if_index; + if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP) + tr->trace_ip4_address.as_u32 = server->dhcp_server.ip4.as_u32; + } + + if (PREDICT_FALSE(0 == n_left_to_next)) + { + vlib_put_next_frame (vm, node, next_index, + n_left_to_next); + vlib_get_next_frame (vm, node, next_index, + to_next, n_left_to_next); + } + } + } do_trace: if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { @@ -350,10 +418,15 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, tr->original_sw_if_index = original_sw_if_index; tr->sw_if_index = sw_if_index; if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP) - tr->trace_ip4_address.as_u32 = server->dhcp_server.ip4.as_u32; + tr->trace_ip4_address.as_u32 = + proxy->dhcp_servers[0].dhcp_server.ip4.as_u32; } do_enqueue: + to_next[0] = bi0; + to_next += 1; + n_left_to_next -= 1; + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, next0); @@ -437,7 +510,8 @@ dhcp_proxy_to_client_input (vlib_main_t * vm, u32 error0 = (u32)~0; vnet_sw_interface_t *swif; u32 fib_index; - dhcp_server_t * server; + dhcp_proxy_t *proxy; + dhcp_server_t *server; u32 original_sw_if_index = (u32) ~0; ip4_address_t relay_addr = { .as_u32 = 0, @@ -547,20 +621,26 @@ dhcp_proxy_to_client_input (vlib_main_t * vm, } fib_index = im->fib_index_by_sw_if_index [sw_if_index]; - server = dhcp_get_server(dpm, fib_index, FIB_PROTOCOL_IP4); + proxy = dhcp_get_proxy(dpm, fib_index, FIB_PROTOCOL_IP4); - if (PREDICT_FALSE (NULL == server)) + if (PREDICT_FALSE (NULL == proxy)) { error0 = DHCP_PROXY_ERROR_NO_SERVER; goto drop_packet; } - if (ip0->src_address.as_u32 != server->dhcp_server.ip4.as_u32) - { - error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; - goto drop_packet; + vec_foreach(server, proxy->dhcp_servers) + { + if (ip0->src_address.as_u32 == server->dhcp_server.ip4.as_u32) + { + goto server_found; + } } + error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; + goto drop_packet; + + server_found: vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index; swif = vnet_get_sw_interface (vnm, sw_if_index); @@ -709,9 +789,8 @@ dhcp4_proxy_set_server (ip46_address_t *addr, if (is_del) { - rc = dhcp_proxy_server_del (FIB_PROTOCOL_IP4, rx_fib_index); - - if (0 == rc) + if (dhcp_proxy_server_del (FIB_PROTOCOL_IP4, rx_fib_index, + addr, server_table_id)) { fib_table_entry_special_remove(rx_fib_index, &all_1s, @@ -809,29 +888,35 @@ VLIB_CLI_COMMAND (dhcp_proxy_set_command, static) = { static u8 * format_dhcp4_proxy_server (u8 * s, va_list * args) { - dhcp_server_t * server = va_arg (*args, dhcp_server_t *); + dhcp_proxy_t *proxy = va_arg (*args, dhcp_proxy_t *); ip4_fib_t * rx_fib, * server_fib; + dhcp_server_t *server; - if (server == 0) + if (proxy == 0) { - s = format (s, "%=16s%=16s%=14s%=14s", "Server", "Src Address", - "Server FIB", "RX FIB"); + s = format (s, "%=14s%=16s%s", "RX FIB", "Src Address", + "Servers FIB,Address"); return s; } - server_fib = ip4_fib_get(server->server_fib_index); - rx_fib = ip4_fib_get(server->rx_fib_index); + rx_fib = ip4_fib_get(proxy->rx_fib_index); + + s = format (s, "%=14u%=16U", + rx_fib->table_id, + format_ip46_address, &proxy->dhcp_src_address, IP46_TYPE_ANY); - s = format (s, "%=16U%=16U%=14u%=14u", - format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY, - format_ip46_address, &server->dhcp_src_address, IP46_TYPE_ANY, - server_fib->table_id, - rx_fib->table_id); + vec_foreach(server, proxy->dhcp_servers) + { + server_fib = ip4_fib_get(server->server_fib_index); + s = format (s, "%u,%U ", + server_fib->table_id, + format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY); + } return s; } static int -dhcp4_proxy_show_walk (dhcp_server_t *server, +dhcp4_proxy_show_walk (dhcp_proxy_t *server, void *ctx) { vlib_main_t * vm = ctx; diff --git a/src/vnet/dhcp/dhcp6_proxy_node.c b/src/vnet/dhcp/dhcp6_proxy_node.c index 58674209..524cb095 100644 --- a/src/vnet/dhcp/dhcp6_proxy_node.c +++ b/src/vnet/dhcp/dhcp6_proxy_node.c @@ -140,7 +140,8 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, ip6_main_t * im = &ip6_main; ip6_address_t * src; int bogus_length; - dhcp_server_t * server; + dhcp_proxy_t *proxy; + dhcp_server_t *server; u32 rx_fib_idx = 0, server_fib_idx = 0; next_index = node->cached_next_index; @@ -176,13 +177,11 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, u8 client_src_mac[6]; vlib_buffer_free_list_t *fl; dhcp_vss_t *vss; + u8 is_solicit = 0; bi0 = from[0]; - to_next[0] = bi0; from += 1; - to_next += 1; n_left_from -= 1; - n_left_to_next -= 1; b0 = vlib_get_buffer (vm, bi0); @@ -227,9 +226,9 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, /* Send to DHCPV6 server via the configured FIB */ rx_sw_if_index = sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; rx_fib_idx = im->mfib_index_by_sw_if_index [rx_sw_if_index]; - server = dhcp_get_server(dpm, rx_fib_idx, FIB_PROTOCOL_IP6); + proxy = dhcp_get_proxy(dpm, rx_fib_idx, FIB_PROTOCOL_IP6); - if (PREDICT_FALSE (NULL == server)) + if (PREDICT_FALSE (NULL == proxy)) { error0 = DHCPV6_PROXY_ERROR_NO_SERVER; next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP; @@ -237,6 +236,7 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, goto do_trace; } + server = &proxy->dhcp_servers[0]; server_fib_idx = server->server_fib_index; vnet_buffer(b0)->sw_if_index[VLIB_TX] = server_fib_idx; @@ -371,18 +371,19 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, ip1->payload_length = u1->length; ip1->protocol = PROTO_UDP; ip1->hop_limit = HOP_COUNT_LIMIT; - src = (server->dhcp_server.ip6.as_u64[0] || - server->dhcp_server.ip6.as_u64[1]) ? - &server->dhcp_server.ip6 : &all_dhcpv6_server_address; + src = ((server->dhcp_server.ip6.as_u64[0] || + server->dhcp_server.ip6.as_u64[1]) ? + &server->dhcp_server.ip6 : + &all_dhcpv6_server_address); copy_ip6_address(&ip1->dst_address, src); ia0 = ip6_interface_first_global_or_site_address (&ip6_main, vnet_buffer(b0)->sw_if_index[VLIB_RX]); - src = (server->dhcp_src_address.ip6.as_u64[0] || - server->dhcp_src_address.ip6.as_u64[1]) ? - &server->dhcp_src_address.ip6 : ia0; + src = (proxy->dhcp_src_address.ip6.as_u64[0] || + proxy->dhcp_src_address.ip6.as_u64[1]) ? + &proxy->dhcp_src_address.ip6 : ia0; if (ia0 == 0) { error0 = DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS; @@ -400,6 +401,66 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP; + is_solicit = (DHCPV6_MSG_SOLICIT == h0->u.msg_type); + + /* + * If we have multiple servers configured and this is the + * client's discover message, then send copies to each of + * those servers + */ + if (is_solicit && vec_len(proxy->dhcp_servers) > 1) + { + u32 ii; + + for (ii = 1; ii < vec_len(proxy->dhcp_servers); ii++) + { + vlib_buffer_t *c0; + u32 ci0; + + c0 = vlib_buffer_copy(vm, b0); + ci0 = vlib_get_buffer_index(vm, c0); + server = &proxy->dhcp_servers[ii]; + + ip0 = vlib_buffer_get_current (c0); + + src = ((server->dhcp_server.ip6.as_u64[0] || + server->dhcp_server.ip6.as_u64[1]) ? + &server->dhcp_server.ip6 : + &all_dhcpv6_server_address); + copy_ip6_address(&ip1->dst_address, src); + + to_next[0] = ci0; + to_next += 1; + n_left_to_next -= 1; + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + ci0, next0); + + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + dhcpv6_proxy_trace_t *tr; + + tr = vlib_add_trace (vm, node, c0, sizeof (*tr)); + tr->which = 0; /* to server */ + tr->error = error0; + tr->original_sw_if_index = rx_sw_if_index; + tr->sw_if_index = sw_if_index; + if (next0 == DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP) + copy_ip6_address((ip6_address_t *)&tr->packet_data[0], + &server->dhcp_server.ip6); + } + + if (PREDICT_FALSE(0 == n_left_to_next)) + { + vlib_put_next_frame (vm, node, next_index, + n_left_to_next); + vlib_get_next_frame (vm, node, next_index, + to_next, n_left_to_next); + } + } + } + do_trace: if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { @@ -414,6 +475,10 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, } do_enqueue: + to_next[0] = bi0; + to_next += 1; + n_left_to_next -= 1; + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, next0); @@ -475,7 +540,8 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, u32 n_left_from, * from; ethernet_main_t *em = ethernet_get_main (vm); dhcp_proxy_main_t * dm = &dhcp_proxy_main; - dhcp_server_t * server; + dhcp_proxy_t *proxy; + dhcp_server_t *server; vnet_main_t * vnm = vnet_get_main(); int bogus_length; @@ -588,9 +654,9 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, vlib_buffer_advance (b0, sizeof(*r0)); client_fib_idx = im->mfib_index_by_sw_if_index[sw_if_index]; - server = dhcp_get_server(dm, client_fib_idx, FIB_PROTOCOL_IP6); + proxy = dhcp_get_proxy(dm, client_fib_idx, FIB_PROTOCOL_IP6); - if (NULL == server) + if (NULL == proxy) { error0 = DHCPV6_PROXY_ERROR_NO_SERVER; goto drop_packet; @@ -599,15 +665,21 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm, server_fib_idx = im->fib_index_by_sw_if_index [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; - if (server_fib_idx != server->server_fib_index || - ip0->src_address.as_u64[0] != server->dhcp_server.ip6.as_u64[0] || - ip0->src_address.as_u64[1] != server->dhcp_server.ip6.as_u64[1]) - { - //drop packet if not from server with configured address or FIB - error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; - goto drop_packet; - } + vec_foreach(server, proxy->dhcp_servers) + { + if (server_fib_idx == server->server_fib_index && + ip0->src_address.as_u64[0] == server->dhcp_server.ip6.as_u64[0] && + ip0->src_address.as_u64[1] == server->dhcp_server.ip6.as_u64[1]) + { + goto server_found; + } + } + + //drop packet if not from server with configured address or FIB + error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS; + goto drop_packet; + server_found: vnet_buffer (b0)->sw_if_index[VLIB_TX] = original_sw_if_index = sw_if_index; @@ -773,9 +845,8 @@ dhcp6_proxy_set_server (ip46_address_t *addr, if (is_del) { - rc = dhcp_proxy_server_del (FIB_PROTOCOL_IP6, rx_fib_index); - - if (0 == rc) + if (dhcp_proxy_server_del (FIB_PROTOCOL_IP6, rx_fib_index, + addr, server_table_id)) { mfib_table_entry_delete(rx_fib_index, &all_dhcp_servers, @@ -893,43 +964,50 @@ VLIB_CLI_COMMAND (dhcpv6_proxy_set_command, static) = { static u8 * format_dhcp6_proxy_server (u8 * s, va_list * args) { - dhcp_server_t * server = va_arg (*args, dhcp_server_t *); + dhcp_proxy_t * proxy = va_arg (*args, dhcp_proxy_t *); ip6_fib_t *server_fib; + dhcp_server_t *server; ip6_mfib_t *rx_fib; - if (NULL == server) + if (proxy == 0) { - s = format (s, "%=40s%=40s%=14s%=14s", "Server Address", "Source Address", - "Server FIB", "RX FIB"); + s = format (s, "%=14s%=16s%s", "RX FIB", "Src Address", + "Servers FIB,Address"); return s; } - server_fib = ip6_fib_get(server->server_fib_index); - rx_fib = ip6_mfib_get(server->rx_fib_index); + rx_fib = ip6_mfib_get(proxy->rx_fib_index); + + s = format (s, "%=14u%=16U", + rx_fib->table_id, + format_ip46_address, &proxy->dhcp_src_address, IP46_TYPE_ANY); + vec_foreach(server, proxy->dhcp_servers) + { + server_fib = ip6_fib_get(server->server_fib_index); + s = format (s, "%u,%U ", + server_fib->table_id, + format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY); + } - s = format (s, "%=40U%=40U%=14u%=14u", - format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY, - format_ip46_address, &server->dhcp_src_address, IP46_TYPE_ANY, - server_fib->table_id, rx_fib->table_id); return s; } static int -dhcp6_proxy_show_walk (dhcp_server_t *server, +dhcp6_proxy_show_walk (dhcp_proxy_t *proxy, void *ctx) { vlib_main_t * vm = ctx; - vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, server); + vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, proxy); return (1); } static clib_error_t * dhcpv6_proxy_show_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) + unformat_input_t * input, + vlib_cli_command_t * cmd) { vlib_cli_output (vm, "%U", format_dhcp6_proxy_server, NULL /* header line */); diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index ce34f6a4..e9c757e8 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -113,46 +114,73 @@ vl_api_dhcp_proxy_dump_t_handler (vl_api_dhcp_proxy_dump_t * mp) if (q == 0) return; - dhcp_proxy_dump ((mp->is_ip6 == 0 ? + dhcp_proxy_dump ((mp->is_ip6 == 1 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4), q, mp->context); } void dhcp_send_details (fib_protocol_t proto, - void *opaque, - u32 context, - const ip46_address_t * server, - const ip46_address_t * src, - u32 server_fib_id, - u32 rx_fib_id, u32 vss_fib_id, u32 vss_oui) + void *opaque, u32 context, dhcp_proxy_t * proxy) { vl_api_dhcp_proxy_details_t *mp; unix_shared_memory_queue_t *q = opaque; - - mp = vl_msg_api_alloc (sizeof (*mp)); + vl_api_dhcp_server_t *v_server; + dhcp_server_t *server; + fib_table_t *s_fib; + dhcp_vss_t *vss; + u32 count; + size_t n; + + count = vec_len (proxy->dhcp_servers); + n = sizeof (*mp) + (count * sizeof (vl_api_dhcp_server_t)); + mp = vl_msg_api_alloc (n); if (!mp) return; - memset (mp, 0, sizeof (*mp)); + memset (mp, 0, n); mp->_vl_msg_id = ntohs (VL_API_DHCP_PROXY_DETAILS); mp->context = context; - - mp->rx_vrf_id = htonl (rx_fib_id); - mp->server_vrf_id = htonl (server_fib_id); - mp->vss_oui = htonl (vss_oui); - mp->vss_fib_id = htonl (vss_fib_id); + mp->count = count; mp->is_ipv6 = (proto == FIB_PROTOCOL_IP6); + mp->rx_vrf_id = + htonl (dhcp_proxy_rx_table_get_table_id (proto, proxy->rx_fib_index)); + + vss = dhcp_get_vss_info (&dhcp_proxy_main, proxy->rx_fib_index, proto); + + if (NULL != vss) + { + mp->vss_oui = htonl (vss->oui); + mp->vss_fib_id = htonl (vss->fib_id); + } + + vec_foreach_index (count, proxy->dhcp_servers) + { + server = &proxy->dhcp_servers[count]; + v_server = &mp->servers[count]; + + s_fib = fib_table_get (server->server_fib_index, proto); + + v_server->server_vrf_id = htonl (s_fib->ft_table_id); + + if (mp->is_ipv6) + { + memcpy (v_server->dhcp_server, &server->dhcp_server.ip6, 16); + } + else + { + /* put the address in the first bytes */ + memcpy (v_server->dhcp_server, &server->dhcp_server.ip4, 4); + } + } if (mp->is_ipv6) { - memcpy (mp->dhcp_server, server, 16); - memcpy (mp->dhcp_src_address, src, 16); + memcpy (mp->dhcp_src_address, &proxy->dhcp_src_address.ip6, 16); } else { /* put the address in the first bytes */ - memcpy (mp->dhcp_server, &server->ip4, 4); - memcpy (mp->dhcp_src_address, &src->ip4, 4); + memcpy (mp->dhcp_src_address, &proxy->dhcp_src_address.ip4, 4); } vl_msg_api_send_shmem (q, (u8 *) & mp); } diff --git a/src/vnet/dhcp/dhcp_proxy.c b/src/vnet/dhcp/dhcp_proxy.c index 8e31c3db..ba7f354e 100644 --- a/src/vnet/dhcp/dhcp_proxy.c +++ b/src/vnet/dhcp/dhcp_proxy.c @@ -44,7 +44,7 @@ dhcp_proxy_rx_table_unlock (fib_protocol_t proto, mfib_table_unlock(fib_index, proto); } -static u32 + u32 dhcp_proxy_rx_table_get_table_id (fib_protocol_t proto, u32 fib_index) { @@ -72,7 +72,7 @@ dhcp_proxy_walk (fib_protocol_t proto, void *ctx) { dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - dhcp_server_t * server; + dhcp_proxy_t * server; u32 server_index, i; vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index[proto]) @@ -124,31 +124,68 @@ dhcp_vss_walk (fib_protocol_t proto, } } +static u32 +dhcp_proxy_server_find (dhcp_proxy_t *proxy, + fib_protocol_t proto, + ip46_address_t *addr, + u32 server_table_id) +{ + dhcp_server_t *server; + u32 ii, fib_index; + + vec_foreach_index(ii, proxy->dhcp_servers) + { + server = &proxy->dhcp_servers[ii]; + fib_index = fib_table_find(proto, server_table_id); + + if (ip46_address_is_equal(&server->dhcp_server, + addr) && + (server->server_fib_index == fib_index)) + { + return (ii); + } + } + return (~0); +} + int dhcp_proxy_server_del (fib_protocol_t proto, - u32 rx_fib_index) + u32 rx_fib_index, + ip46_address_t *addr, + u32 server_table_id) { dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - dhcp_server_t * server = 0; - int rc = 0; + dhcp_proxy_t *proxy = 0; - server = dhcp_get_server(dpm, rx_fib_index, proto); + proxy = dhcp_get_proxy(dpm, rx_fib_index, proto); - if (NULL == server) - { - rc = VNET_API_ERROR_NO_SUCH_ENTRY; - } - else + if (NULL != proxy) { - /* Use the default server again. */ - dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = ~0; + dhcp_server_t *server; + u32 index; - fib_table_unlock (server->server_fib_index, proto); + index = dhcp_proxy_server_find(proxy, proto, addr, server_table_id); - pool_put (dpm->dhcp_servers[proto], server); + if (~0 != index) + { + server = &proxy->dhcp_servers[index]; + fib_table_unlock (server->server_fib_index, proto); + + vec_del1(proxy->dhcp_servers, index); + + if (0 == vec_len(proxy->dhcp_servers)) + { + /* no servers left, delete the proxy config */ + dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = ~0; + vec_free(proxy->dhcp_servers); + pool_put (dpm->dhcp_servers[proto], proxy); + return (1); + } + } } - return (rc); + /* the proxy still exists */ + return (0); } int @@ -159,48 +196,42 @@ dhcp_proxy_server_add (fib_protocol_t proto, u32 server_table_id) { dhcp_proxy_main_t * dpm = &dhcp_proxy_main; - dhcp_server_t * server = 0; + dhcp_proxy_t * proxy = 0; int new = 0; - server = dhcp_get_server(dpm, rx_fib_index, proto); + proxy = dhcp_get_proxy(dpm, rx_fib_index, proto); - if (NULL == server) + if (NULL == proxy) { vec_validate_init_empty(dpm->dhcp_server_index_by_rx_fib_index[proto], rx_fib_index, ~0); - pool_get (dpm->dhcp_servers[proto], server); - memset (server, 0, sizeof (*server)); + pool_get (dpm->dhcp_servers[proto], proxy); + memset (proxy, 0, sizeof (*proxy)); new = 1; dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = - server - dpm->dhcp_servers[proto]; + proxy - dpm->dhcp_servers[proto]; - server->rx_fib_index = rx_fib_index; - server->server_fib_index = - fib_table_find_or_create_and_lock(proto, server_table_id); + proxy->dhcp_src_address = *src_address; + proxy->rx_fib_index = rx_fib_index; } else { - /* modify, may need to swap server FIBs */ - u32 tmp_index; - - tmp_index = fib_table_find(proto, server_table_id); - - if (tmp_index != server->server_fib_index) + if (~0 != dhcp_proxy_server_find(proxy, proto, addr, server_table_id)) { - tmp_index = server->server_fib_index; - - /* certainly swapping if the fib doesn't exist */ - server->server_fib_index = - fib_table_find_or_create_and_lock(proto, server_table_id); - fib_table_unlock (tmp_index, proto); + return (new); } } - server->dhcp_server = *addr; - server->dhcp_src_address = *src_address; + dhcp_server_t server = { + .dhcp_server = *addr, + .server_fib_index = fib_table_find_or_create_and_lock(proto, + server_table_id), + }; + + vec_add1(proxy->dhcp_servers, server); return (new); } @@ -213,31 +244,15 @@ typedef struct dhcp4_proxy_dump_walk_ctx_t_ } dhcp_proxy_dump_walk_cxt_t; static int -dhcp_proxy_dump_walk (dhcp_server_t *server, +dhcp_proxy_dump_walk (dhcp_proxy_t *proxy, void *arg) { dhcp_proxy_dump_walk_cxt_t *ctx = arg; - fib_table_t *s_fib; - u32 rx_table_id; - dhcp_vss_t *v; - - v = dhcp_get_vss_info(&dhcp_proxy_main, - server->rx_fib_index, - ctx->proto); - - s_fib = fib_table_get(server->server_fib_index, ctx->proto); - rx_table_id = dhcp_proxy_rx_table_get_table_id(server->rx_fib_index, - ctx->proto); dhcp_send_details(ctx->proto, ctx->opaque, ctx->context, - &server->dhcp_server, - &server->dhcp_src_address, - s_fib->ft_table_id, - rx_table_id, - (v ? v->fib_id : 0), - (v ? v->oui : 0)); + proxy); return (1); } diff --git a/src/vnet/dhcp/dhcp_proxy.h b/src/vnet/dhcp/dhcp_proxy.h index 708e92f3..ef2bc0a1 100644 --- a/src/vnet/dhcp/dhcp_proxy.h +++ b/src/vnet/dhcp/dhcp_proxy.h @@ -58,32 +58,58 @@ typedef struct dhcp_vss_t_ { } dhcp_vss_t; /** - * @brief A DHCP proxy server represenation + * @brief A representation of a single DHCP Server within a given VRF config */ -typedef struct dhcp_server_t_ { +typedef struct dhcp_server_t_ +{ /** * @brief The address of the DHCP server to which to relay the client's * messages */ ip46_address_t dhcp_server; - /** - * @brief The source address to use in relayed messaes - */ - ip46_address_t dhcp_src_address; - /** * @brief The FIB index (not the external Table-ID) in which the server * is reachable. */ u32 server_fib_index; +} dhcp_server_t; + +/** + * @brief A DHCP proxy represenation fpr per-client VRF config + */ +typedef struct dhcp_proxy_t_ { + /** + * @brief The set of DHCP servers to which messages are relayed. + * If multiple servers are configured then discover/solict messages + * are relayed to each. A cookie is maintained for the relay, and only + * one message is replayed to the client, based on the presence of the + * cookie. + * The expectation is there are only 1 or 2 servers, hence no fancy DB. + */ + dhcp_server_t *dhcp_servers; + + /** + * @brief Hash table of pending requets key'd on the clients MAC address + */ + uword *dhcp_pending; + + /** + * @brief A lock for the pending request DB. + */ + int lock; + + /** + * @brief The source address to use in relayed messaes + */ + ip46_address_t dhcp_src_address; /** * @brief The FIB index (not the external Table-ID) in which the client * is resides. */ u32 rx_fib_index; -} dhcp_server_t; +} dhcp_proxy_t; #define DHCP_N_PROTOS (FIB_PROTOCOL_IP6 + 1) @@ -92,7 +118,7 @@ typedef struct dhcp_server_t_ { */ typedef struct { /* Pool of DHCP servers */ - dhcp_server_t *dhcp_servers[DHCP_N_PROTOS]; + dhcp_proxy_t *dhcp_servers[DHCP_N_PROTOS]; /* Pool of selected DHCP server. Zero is the default server */ u32 * dhcp_server_index_by_rx_fib_index[DHCP_N_PROTOS]; @@ -114,12 +140,7 @@ extern dhcp_proxy_main_t dhcp_proxy_main; void dhcp_send_details (fib_protocol_t proto, void *opaque, u32 context, - const ip46_address_t *server, - const ip46_address_t *src, - u32 server_fib_id, - u32 rx_fib_id, - u32 vss_fib_id, - u32 vss_oui); + dhcp_proxy_t *proxy); /** * @brief Show (on CLI) a VSS config during a show walk @@ -157,16 +178,22 @@ int dhcp_proxy_server_add(fib_protocol_t proto, /** * @brief Delete a DHCP proxy config - * @return 0 is deleted, otherwise an error code + * @return 1 if the proxy is deleted, 0 otherwise */ int dhcp_proxy_server_del(fib_protocol_t proto, - u32 rx_fib_index); + u32 rx_fib_index, + ip46_address_t *addr, + u32 server_table_id); + +u32 +dhcp_proxy_rx_table_get_table_id (fib_protocol_t proto, + u32 fib_index); /** * @brief Callback function invoked for each DHCP proxy entry * return 0 to break the walk, non-zero otherwise. */ -typedef int (*dhcp_proxy_walk_fn_t)(dhcp_server_t *server, +typedef int (*dhcp_proxy_walk_fn_t)(dhcp_proxy_t *server, void *ctx); /** @@ -191,6 +218,18 @@ void dhcp_vss_walk(fib_protocol_t proto, dhcp_vss_walk_fn_t fn, void *ctx); +/** + * @brief Lock a proxy object to prevent simultaneous access of its + * pending store + */ +void dhcp_proxy_lock (dhcp_proxy_t *server); + +/** + * @brief Lock a proxy object to prevent simultaneous access of its + * pending store + */ +void dhcp_proxy_unlock (dhcp_proxy_t *server); + /** * @brief Get the VSS data for the FIB index */ @@ -215,12 +254,12 @@ dhcp_get_vss_info (dhcp_proxy_main_t *dm, /** * @brief Get the DHCP proxy server data for the FIB index */ -static inline dhcp_server_t * -dhcp_get_server (dhcp_proxy_main_t *dm, - u32 rx_fib_index, - fib_protocol_t proto) +static inline dhcp_proxy_t * +dhcp_get_proxy (dhcp_proxy_main_t *dm, + u32 rx_fib_index, + fib_protocol_t proto) { - dhcp_server_t *s = NULL; + dhcp_proxy_t *s = NULL; if (vec_len(dm->dhcp_server_index_by_rx_fib_index[proto]) > rx_fib_index && dm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] != ~0) diff --git a/src/vnet/ip/ip6_packet.h b/src/vnet/ip/ip6_packet.h index 6eabeef1..9bf19edb 100644 --- a/src/vnet/ip/ip6_packet.h +++ b/src/vnet/ip/ip6_packet.h @@ -79,6 +79,8 @@ typedef CLIB_PACKED (union { #define ip46_address_reset(ip46) ((ip46)->as_u64[0] = (ip46)->as_u64[1] = 0) #define ip46_address_cmp(ip46_1, ip46_2) (memcmp(ip46_1, ip46_2, sizeof(*ip46_1))) #define ip46_address_is_zero(ip46) (((ip46)->as_u64[0] == 0) && ((ip46)->as_u64[1] == 0)) +#define ip46_address_is_equal(a1, a2) (((a1)->as_u64[0] == (a2)->as_u64[0]) \ + && ((a1)->as_u64[1] == (a2)->as_u64[1])) always_inline void ip46_from_addr_buf (u32 is_ipv6, u8 * buf, ip46_address_t * ip) diff --git a/src/vnet/pg/input.c b/src/vnet/pg/input.c index 4a65b024..2649798b 100644 --- a/src/vnet/pg/input.c +++ b/src/vnet/pg/input.c @@ -1373,6 +1373,7 @@ typedef struct u32 stream_index; u32 packet_length; + u32 sw_if_index; /* Use pre data for packet data. */ vlib_buffer_t buffer; @@ -1399,6 +1400,7 @@ format_pg_input_trace (u8 * s, va_list * va) s = format (s, "stream %d", t->stream_index); s = format (s, ", %d bytes", t->packet_length); + s = format (s, ", %d sw_if_index", t->sw_if_index); s = format (s, "\n%U%U", format_white_space, indent, format_vlib_buffer, &t->buffer); @@ -1458,6 +1460,9 @@ pg_input_trace (pg_main_t * pg, t0->packet_length = vlib_buffer_length_in_chain (vm, b0); t1->packet_length = vlib_buffer_length_in_chain (vm, b1); + t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t1->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + clib_memcpy (&t0->buffer, b0, sizeof (b0[0]) - sizeof (b0->pre_data)); clib_memcpy (&t1->buffer, b1, sizeof (b1[0]) - sizeof (b1->pre_data)); @@ -1484,6 +1489,7 @@ pg_input_trace (pg_main_t * pg, t0->stream_index = stream_index; t0->packet_length = vlib_buffer_length_in_chain (vm, b0); + t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; clib_memcpy (&t0->buffer, b0, sizeof (b0[0]) - sizeof (b0->pre_data)); clib_memcpy (t0->buffer.pre_data, b0->data, sizeof (t0->buffer.pre_data)); diff --git a/test/test_dhcp.py b/test/test_dhcp.py index a09c9bdb..89667d3d 100644 --- a/test/test_dhcp.py +++ b/test/test_dhcp.py @@ -2,8 +2,10 @@ import unittest import socket +import struct from framework import VppTestCase, VppTestRunner +from vpp_neighbor import VppNeighbor from scapy.layers.l2 import Ether, getmacbyip from scapy.layers.inet import IP, UDP, ICMP @@ -11,7 +13,7 @@ from scapy.layers.inet6 import IPv6, in6_getnsmac, in6_mactoifaceid from scapy.layers.dhcp import DHCP, BOOTP, DHCPTypes from scapy.layers.dhcp6 import DHCP6, DHCP6_Solicit, DHCP6_RelayForward, \ DHCP6_RelayReply, DHCP6_Advertise, DHCP6OptRelayMsg, DHCP6OptIfaceId, \ - DHCP6OptStatusCode, DHCP6OptVSS, DHCP6OptClientLinkLayerAddr + DHCP6OptStatusCode, DHCP6OptVSS, DHCP6OptClientLinkLayerAddr, DHCP6_Request from socket import AF_INET, AF_INET6 from scapy.utils import inet_pton, inet_ntop from scapy.utils6 import in6_ptop @@ -140,7 +142,7 @@ class TestDHCP(VppTestCase): return data - def verify_dhcp_offer(self, pkt, intf): + def verify_dhcp_offer(self, pkt, intf, fib_id=0, oui=0): ether = pkt[Ether] self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") self.assertEqual(ether.src, intf.local_mac) @@ -162,15 +164,22 @@ class TestDHCP(VppTestCase): is_offer = True self.assertTrue(is_offer) - data = self.validate_relay_options(pkt, intf, intf.local_ip4, 0, 0) + data = self.validate_relay_options(pkt, intf, intf.local_ip4, + fib_id, oui) + + def verify_dhcp_discover(self, pkt, intf, src_intf=None, fib_id=0, oui=0, + dst_mac=None, dst_ip=None): + if not dst_mac: + dst_mac = intf.remote_mac + if not dst_ip: + dst_ip = intf.remote_ip4 - def verify_dhcp_discover(self, pkt, intf, src_intf=None, fib_id=0, oui=0): ether = pkt[Ether] - self.assertEqual(ether.dst, intf.remote_mac) + self.assertEqual(ether.dst, dst_mac) self.assertEqual(ether.src, intf.local_mac) ip = pkt[IP] - self.assertEqual(ip.dst, intf.remote_ip4) + self.assertEqual(ip.dst, dst_ip) self.assertEqual(ip.src, intf.local_ip4) udp = pkt[UDP] @@ -195,13 +204,20 @@ class TestDHCP(VppTestCase): def verify_dhcp6_solicit(self, pkt, intf, peer_ip, peer_mac, fib_id=0, - oui=0): + oui=0, + dst_mac=None, + dst_ip=None): + if not dst_mac: + dst_mac = intf.remote_mac + if not dst_ip: + dst_ip = in6_ptop(intf.remote_ip6) + ether = pkt[Ether] - self.assertEqual(ether.dst, intf.remote_mac) + self.assertEqual(ether.dst, dst_mac) self.assertEqual(ether.src, intf.local_mac) ip = pkt[IPv6] - self.assertEqual(in6_ptop(ip.dst), in6_ptop(intf.remote_ip6)) + self.assertEqual(in6_ptop(ip.dst), dst_ip) self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6)) udp = pkt[UDP] @@ -447,6 +463,128 @@ class TestDHCP(VppTestCase): self.pg_enable_capture(self.pg_interfaces) self.pg_start() + rx = self.pg1.get_capture(1) + rx = rx[0] + self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3, + fib_id=1, oui=4) + + # + # Add a second DHCP server in VRF 1 + # expect clients messages to be relay to both configured servers + # + self.pg1.generate_remote_hosts(2) + server_addr2 = socket.inet_pton(AF_INET, self.pg1.remote_hosts[1].ip4) + + self.vapi.dhcp_proxy_config(server_addr2, + src_addr, + rx_table_id=1, + server_table_id=1, + is_add=1) + + # + # We'll need an ARP entry for the server to send it packets + # + arp_entry = VppNeighbor(self, + self.pg1.sw_if_index, + self.pg1.remote_hosts[1].mac, + self.pg1.remote_hosts[1].ip4) + arp_entry.add_vpp_config() + + # + # Send a discover from the client. expect two relayed messages + # The frist packet is sent to the second server + # We're not enforcing that here, it's just the way it is. + # + self.pg3.add_stream(pkts_disc_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(2) + + option_82 = self.verify_dhcp_discover( + rx[0], self.pg1, + src_intf=self.pg3, + dst_mac=self.pg1.remote_hosts[1].mac, + dst_ip=self.pg1.remote_hosts[1].ip4, + fib_id=1, oui=4) + self.verify_dhcp_discover(rx[1], self.pg1, src_intf=self.pg3, + fib_id=1, oui=4) + + # + # Send both packets back. Client gets both. + # + p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), + ('relay_agent_Information', option_82), + ('end')])) + p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IP(src=self.pg1.remote_hosts[1].ip4, dst=self.pg1.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), + ('relay_agent_Information', option_82), + ('end')])) + pkts = [p1, p2] + + self.pg1.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg3.get_capture(2) + + self.verify_dhcp_offer(rx[0], self.pg3, fib_id=1, oui=4) + self.verify_dhcp_offer(rx[1], self.pg3, fib_id=1, oui=4) + + # + # Ensure offers from non-servers are dropeed + # + p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IP(src="8.8.8.8", dst=self.pg1.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), + ('relay_agent_Information', option_82), + ('end')])) + self.send_and_assert_no_replies(self.pg1, p2, + "DHCP offer from non-server") + + # + # Ensure only the discover is sent to multiple servers + # + p_req_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff", + src=self.pg3.remote_mac) / + IP(src="0.0.0.0", dst="255.255.255.255") / + UDP(sport=DHCP4_CLIENT_PORT, + dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'request'), + ('end')])) + + self.pg3.add_stream(p_req_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + + # + # Remove the second DHCP server + # + self.vapi.dhcp_proxy_config(server_addr2, + src_addr, + rx_table_id=1, + server_table_id=1, + is_add=0) + + # + # Test we can still relay with the first + # + self.pg3.add_stream(pkts_disc_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + rx = self.pg1.get_capture(1) rx = rx[0] self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3, @@ -472,7 +610,7 @@ class TestDHCP(VppTestCase): self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=1, - server_table_id=11, + server_table_id=1, is_add=0) self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, @@ -500,18 +638,16 @@ class TestDHCP(VppTestCase): UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Solicit()) - pkts_solicit_vrf0 = [p_solicit_vrf0] p_solicit_vrf1 = (Ether(dst=dmac, src=self.pg3.remote_mac) / IPv6(src=dhcp_solicit_src_vrf1, dst=dhcp_solicit_dst) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Solicit()) - pkts_solicit_vrf1 = [p_solicit_vrf1] - self.send_and_assert_no_replies(self.pg2, pkts_solicit_vrf0, + self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0, "DHCP with no configuration") - self.send_and_assert_no_replies(self.pg3, pkts_solicit_vrf1, + self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1, "DHCP with no configuration") # @@ -525,9 +661,9 @@ class TestDHCP(VppTestCase): server_table_id=0, is_ipv6=1) - self.send_and_assert_no_replies(self.pg2, pkts_solicit_vrf0, + self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0, "DHCP with no configuration") - self.send_and_assert_no_replies(self.pg3, pkts_solicit_vrf1, + self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1, "DHCP with no configuration") # @@ -538,13 +674,13 @@ class TestDHCP(VppTestCase): # # Now the DHCP requests are relayed to the server # - self.pg2.add_stream(pkts_solicit_vrf0) + self.pg2.add_stream(p_solicit_vrf0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) - rx = rx[0] - self.verify_dhcp6_solicit(rx, self.pg0, + + self.verify_dhcp6_solicit(rx[0], self.pg0, dhcp_solicit_src_vrf0, self.pg2.remote_mac) @@ -557,8 +693,7 @@ class TestDHCP(VppTestCase): IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_Advertise()) - pkts_adv_vrf0 = [p_adv_vrf0] - self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0, + self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP6 not a relay reply") # 2 - no relay message option @@ -567,8 +702,7 @@ class TestDHCP(VppTestCase): UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply() / DHCP6_Advertise()) - pkts_adv_vrf0 = [p_adv_vrf0] - self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0, + self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP not a relay message") # 3 - no circuit ID @@ -578,8 +712,7 @@ class TestDHCP(VppTestCase): DHCP6_RelayReply() / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise()) - pkts_adv_vrf0 = [p_adv_vrf0] - self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0, + self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP6 no circuit ID") # 4 - wrong circuit ID p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / @@ -589,8 +722,7 @@ class TestDHCP(VppTestCase): DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise()) - pkts_adv_vrf0 = [p_adv_vrf0] - self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0, + self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP6 wrong circuit ID") # @@ -611,8 +743,8 @@ class TestDHCP(VppTestCase): self.pg_start() rx = self.pg2.get_capture(1) - rx = rx[0] - self.verify_dhcp6_advert(rx, self.pg2, "::") + + self.verify_dhcp6_advert(rx[0], self.pg2, "::") # # Send the relay response (the advertisement) @@ -632,8 +764,8 @@ class TestDHCP(VppTestCase): self.pg_start() rx = self.pg2.get_capture(1) - rx = rx[0] - self.verify_dhcp6_advert(rx, self.pg2, dhcp_solicit_src_vrf0) + + self.verify_dhcp6_advert(rx[0], self.pg2, dhcp_solicit_src_vrf0) # # Add all the config for VRF 1 @@ -648,13 +780,13 @@ class TestDHCP(VppTestCase): # # VRF 1 solicit # - self.pg3.add_stream(pkts_solicit_vrf1) + self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) - rx = rx[0] - self.verify_dhcp6_solicit(rx, self.pg1, + + self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac) @@ -676,21 +808,21 @@ class TestDHCP(VppTestCase): self.pg_start() rx = self.pg3.get_capture(1) - rx = rx[0] - self.verify_dhcp6_advert(rx, self.pg3, dhcp_solicit_src_vrf1) + + self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1) # # Add VSS config # table=1, fib=id=1, oui=4 self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1) - self.pg3.add_stream(pkts_solicit_vrf1) + self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) - rx = rx[0] - self.verify_dhcp6_solicit(rx, self.pg1, + + self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac, fib_id=1, @@ -702,27 +834,163 @@ class TestDHCP(VppTestCase): # self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1, is_add=0) - self.pg3.add_stream(pkts_solicit_vrf1) + self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) - rx = rx[0] - self.verify_dhcp6_solicit(rx, self.pg1, + + self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac) # - # Cleanup + # Add a second DHCP server in VRF 1 + # expect clients messages to be relay to both configured servers # - self.vapi.dhcp_proxy_config(server_addr_vrf1, + self.pg1.generate_remote_hosts(2) + server_addr2 = socket.inet_pton(AF_INET6, self.pg1.remote_hosts[1].ip6) + + self.vapi.dhcp_proxy_config(server_addr2, + src_addr_vrf1, + rx_table_id=1, + server_table_id=1, + is_ipv6=1) + + # + # We'll need an ND entry for the server to send it packets + # + nd_entry = VppNeighbor(self, + self.pg1.sw_if_index, + self.pg1.remote_hosts[1].mac, + self.pg1.remote_hosts[1].ip6, + af=AF_INET6) + nd_entry.add_vpp_config() + + # + # Send a discover from the client. expect two relayed messages + # The frist packet is sent to the second server + # We're not enforcing that here, it's just the way it is. + # + self.pg3.add_stream(p_solicit_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(2) + + self.verify_dhcp6_solicit(rx[0], self.pg1, + dhcp_solicit_src_vrf1, + self.pg3.remote_mac) + self.verify_dhcp6_solicit(rx[1], self.pg1, + dhcp_solicit_src_vrf1, + self.pg3.remote_mac, + dst_mac=self.pg1.remote_hosts[1].mac, + dst_ip=self.pg1.remote_hosts[1].ip6) + + # + # Send both packets back. Client gets both. + # + p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise(trid=1) / + DHCP6OptStatusCode(statuscode=0)) + p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac) / + IPv6(dst=self.pg1.local_ip6, src=self.pg1._remote_hosts[1].ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise(trid=1) / + DHCP6OptStatusCode(statuscode=0)) + + pkts = [p1, p2] + + self.pg1.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg3.get_capture(2) + + self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1) + self.verify_dhcp6_advert(rx[1], self.pg3, dhcp_solicit_src_vrf1) + + # + # Ensure only solicit messages are duplicated + # + p_request_vrf1 = (Ether(dst=dmac, src=self.pg3.remote_mac) / + IPv6(src=dhcp_solicit_src_vrf1, + dst=dhcp_solicit_dst) / + UDP(sport=DHCP6_SERVER_PORT, + dport=DHCP6_CLIENT_PORT) / + DHCP6_Request()) + + self.pg3.add_stream(p_request_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + + # + # Test we drop DHCP packets from addresses that are not configured as + # DHCP servers + # + p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac) / + IPv6(dst=self.pg1.local_ip6, src="3001::1") / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise(trid=1) / + DHCP6OptStatusCode(statuscode=0)) + self.send_and_assert_no_replies(self.pg1, p2, + "DHCP6 not from server") + + # + # Remove the second DHCP server + # + self.vapi.dhcp_proxy_config(server_addr2, src_addr_vrf1, rx_table_id=1, server_table_id=1, is_ipv6=1, is_add=0) + + # + # Test we can still relay with the first + # + self.pg3.add_stream(p_solicit_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + + self.verify_dhcp6_solicit(rx[0], self.pg1, + dhcp_solicit_src_vrf1, + self.pg3.remote_mac) + + # + # Cleanup + # self.vapi.dhcp_proxy_config(server_addr_vrf1, src_addr_vrf1, + rx_table_id=1, + server_table_id=1, + is_ipv6=1, + is_add=0) + self.vapi.dhcp_proxy_config(server_addr_vrf0, + src_addr_vrf0, + rx_table_id=0, + server_table_id=0, + is_ipv6=1, + is_add=0) + + # duplicate delete + self.vapi.dhcp_proxy_config(server_addr_vrf0, + src_addr_vrf0, rx_table_id=0, server_table_id=0, is_ipv6=1, -- cgit 1.2.3-korg From 69186d930ff43b127269abc568bdc656b1e635ad Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Thu, 27 Apr 2017 21:20:51 -0500 Subject: Fix hostname fencepost error in dhcp_compl_event_callback. Hostnames are limited to 63 characters and a NUL terminator. Change-Id: Ie1724d83675cca5e8cdfcd99d8e56e530a044d5d Signed-off-by: Jon Loeliger --- src/vnet/dhcp/dhcp_api.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/vnet/dhcp/dhcp_api.c') diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index e9c757e8..2c0dd77d 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -192,6 +192,7 @@ dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, { unix_shared_memory_queue_t *q; vl_api_dhcp_compl_event_t *mp; + u32 len; q = vl_api_client_index_to_input_queue (client_index); if (!q) @@ -201,8 +202,9 @@ dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, mp->client_index = client_index; mp->pid = pid; mp->is_ipv6 = is_ipv6; - clib_memcpy (&mp->hostname, hostname, vec_len (hostname)); - mp->hostname[vec_len (hostname) + 1] = '\n'; + len = (vec_len (hostname) < 63) ? vec_len (hostname) : 63; + clib_memcpy (&mp->hostname, hostname, len); + mp->hostname[len] = 0; clib_memcpy (&mp->host_address[0], host_address, 16); clib_memcpy (&mp->router_address[0], router_address, 16); -- cgit 1.2.3-korg From 4729b1ec83855268adcea3e00a3462c06a631075 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 6 Jul 2017 01:39:05 -0700 Subject: DHCP complete event sends mask length Change-Id: I4a529dfab5d0ce6b0bbc0ccbbd89c6b109dbf917 Signed-off-by: Neale Ranns --- src/vnet/dhcp/client.c | 3 ++- src/vnet/dhcp/dhcp.api | 2 ++ src/vnet/dhcp/dhcp_api.c | 5 +++-- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src/vnet/dhcp/dhcp_api.c') diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index 7c3f7f6a..014f17a1 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -194,7 +194,7 @@ int dhcp_client_for_us (u32 bi, vlib_buffer_t * b, /* OK, we own the address (etc), add to the routing table(s) */ if (c->state == DHCP_REQUEST) { - void (*fp)(u32, u32, u8 *, u8, u8 *, u8 *, u8 *) = c->event_callback; + void (*fp)(u32, u32, u8 *, u8, u8, u8 *, u8 *, u8 *) = c->event_callback; dhcp_client_acquire_address (dcm, c); @@ -236,6 +236,7 @@ int dhcp_client_for_us (u32 bi, vlib_buffer_t * b, (*fp) (c->client_index, /* clinet index */ c->pid, c->hostname, + c->subnet_mask_width, 0, /* is_ipv6 */ (u8 *)&c->leased_address, /* host IP address */ (u8 *)&c->router_address, /* router IP address */ diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api index eb0b070d..a2803728 100644 --- a/src/vnet/dhcp/dhcp.api +++ b/src/vnet/dhcp/dhcp.api @@ -81,6 +81,7 @@ autoreply define dhcp_client_config @param client_index - opaque cookie to identify the sender @param pid - client pid registered to receive notification @param is_ipv6 - if non-zero the address is ipv6, else ipv4 + @param mask_width - The length of the subnet mask assigned @param host_address - Host IP address @param router_address - Router IP address @param host_mac - Host MAC address @@ -91,6 +92,7 @@ define dhcp_compl_event u32 pid; u8 hostname[64]; u8 is_ipv6; + u8 mask_width; u8 host_address[16]; u8 router_address[16]; u8 host_mac[6]; diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index 2c0dd77d..5ea93660 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -187,8 +187,8 @@ dhcp_send_details (fib_protocol_t proto, void dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, - u8 is_ipv6, u8 * host_address, u8 * router_address, - u8 * host_mac) + u8 mask_width, u8 is_ipv6, u8 * host_address, + u8 * router_address, u8 * host_mac) { unix_shared_memory_queue_t *q; vl_api_dhcp_compl_event_t *mp; @@ -205,6 +205,7 @@ dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, len = (vec_len (hostname) < 63) ? vec_len (hostname) : 63; clib_memcpy (&mp->hostname, hostname, len); mp->hostname[len] = 0; + mp->mask_width = mask_width; clib_memcpy (&mp->host_address[0], host_address, 16); clib_memcpy (&mp->router_address[0], router_address, 16); -- cgit 1.2.3-korg From 51822bf07a3f0fe72834ea94659faf6e262475ba Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 18 Jul 2017 09:26:53 -0700 Subject: DHCP client option 61 "client_id" the existing seeting of client_id to a VPP version number was unused and so overridden Change-Id: If9ebea936336f1fcca8d07e67186c95f8f8f0ccd Signed-off-by: Neale Ranns --- src/vnet/dhcp/client.c | 15 ++++++++++++++- src/vnet/dhcp/client.h | 1 + src/vnet/dhcp/dhcp.api | 2 ++ src/vnet/dhcp/dhcp_api.c | 3 ++- test/test_dhcp.py | 34 ++++++++++++++++++++++++++++++++-- test/vpp_papi_provider.py | 2 ++ 6 files changed, 53 insertions(+), 4 deletions(-) (limited to 'src/vnet/dhcp/dhcp_api.c') diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c index 8f033d25..25ab3176 100644 --- a/src/vnet/dhcp/client.c +++ b/src/vnet/dhcp/client.c @@ -414,6 +414,16 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c, o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); } + /* send option 61, client_id */ + if (vec_len (c->client_identifier)) + { + o->option = 61; + o->length = vec_len (c->client_identifier); + clib_memcpy (o->data, c->client_identifier, + vec_len (c->client_identifier)); + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + } + /* $$ maybe send the client s/w version if anyone cares */ /* @@ -838,6 +848,7 @@ int dhcp_client_config (vlib_main_t * vm, u32 sw_if_index, u8 * hostname, + u8 * client_id, u32 is_add, u32 client_index, void * event_callback, @@ -854,7 +865,9 @@ dhcp_client_config (vlib_main_t * vm, a->event_callback = event_callback; vec_validate(a->hostname, strlen((char *)hostname) - 1); strncpy((char *)a->hostname, (char *)hostname, vec_len(a->hostname)); - a->client_identifier = format (0, "vpe 1.0%c", 0); + vec_validate(a->client_identifier, strlen((char *)client_id) - 1); + strncpy((char *)a->client_identifier, (char *)client_id, vec_len(a->client_identifier)); + /* * Option 55 request list. These data precisely match * the Ubuntu dhcp client. YMMV. diff --git a/src/vnet/dhcp/client.h b/src/vnet/dhcp/client.h index 1f85d7ce..509d5d4c 100644 --- a/src/vnet/dhcp/client.h +++ b/src/vnet/dhcp/client.h @@ -113,6 +113,7 @@ int dhcp_client_for_us (u32 bi0, int dhcp_client_config (vlib_main_t * vm, u32 sw_if_index, u8 * hostname, + u8 * client_id, u32 is_add, u32 client_index, void *event_callback, diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api index a2803728..c632c087 100644 --- a/src/vnet/dhcp/dhcp.api +++ b/src/vnet/dhcp/dhcp.api @@ -61,6 +61,7 @@ autoreply define dhcp_proxy_set_vss @param context - sender context, to match reply w/ request @param sw_if_index - index of the interface for DHCP client @param hostname - hostname + @param client_id - Client ID - option 61 @param is_add - add the config if non-zero, else delete @param want_dhcp_event - DHCP event sent to the sender via dhcp_compl_event API message if non-zero @@ -72,6 +73,7 @@ autoreply define dhcp_client_config u32 context; u32 sw_if_index; u8 hostname[64]; + u8 client_id[64]; u8 is_add; u8 want_dhcp_event; u32 pid; diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index 5ea93660..d6984f2d 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -227,7 +227,8 @@ static void vl_api_dhcp_client_config_t_handler VALIDATE_SW_IF_INDEX (mp); rv = dhcp_client_config (vm, ntohl (mp->sw_if_index), - mp->hostname, mp->is_add, mp->client_index, + mp->hostname, mp->client_id, + mp->is_add, mp->client_index, mp->want_dhcp_event ? dhcp_compl_event_callback : NULL, mp->pid); diff --git a/test/test_dhcp.py b/test/test_dhcp.py index 1700f6ba..4e8ed4ce 100644 --- a/test/test_dhcp.py +++ b/test/test_dhcp.py @@ -9,7 +9,7 @@ from vpp_neighbor import VppNeighbor from vpp_ip_route import find_route from util import mk_ll_addr -from scapy.layers.l2 import Ether, getmacbyip +from scapy.layers.l2 import Ether, getmacbyip, ARP from scapy.layers.inet import IP, UDP, ICMP from scapy.layers.inet6 import IPv6, in6_getnsmac, in6_mactoifaceid from scapy.layers.dhcp import DHCP, BOOTP, DHCPTypes @@ -189,11 +189,13 @@ class TestDHCP(VppTestCase): self.assertEqual(udp.dport, DHCP4_SERVER_PORT) self.assertEqual(udp.sport, DHCP4_CLIENT_PORT) - def verify_orig_dhcp_discover(self, pkt, intf, hostname): + def verify_orig_dhcp_discover(self, pkt, intf, hostname, client_id=None): self.verify_orig_dhcp_pkt(pkt, intf) 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) def verify_orig_dhcp_request(self, pkt, intf, hostname, ip): self.verify_orig_dhcp_pkt(pkt, intf) @@ -1089,12 +1091,25 @@ class TestDHCP(VppTestCase): self.pg_enable_capture(self.pg_interfaces) self.pg_start() + # + # We'll get an ARP request for the router address + # + rx = self.pg2.get_capture(1) + + self.assertEqual(rx[0][ARP].pdst, self.pg2.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.pg2.local_ip4, 32)) + # remove the left over ARP entry + self.vapi.ip_neighbor_add_del(self.pg2.sw_if_index, + self.pg2.remote_mac, + self.pg2.remote_ip4, + is_add=0) # # remove the DHCP config # @@ -1105,6 +1120,21 @@ class TestDHCP(VppTestCase): # self.assertFalse(find_route(self, self.pg2.local_ip4, 32)) + # + # Start the procedure again. this time have VPP send the clientiid + # + self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, + client_id=self.pg2.local_mac) + + rx = self.pg2.get_capture(1) + + self.verify_orig_dhcp_discover(rx[0], self.pg2, hostname, + self.pg2.local_mac) + + # + # remove the DHCP config + # + self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, is_add=0) if __name__ == '__main__': unittest.main(testRunner=VppTestRunner) diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 31eadad8..2814ef97 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -1758,6 +1758,7 @@ class VppPapiProvider(object): def dhcp_client(self, sw_if_index, hostname, + client_id='', is_add=1, want_dhcp_events=0): return self.api( @@ -1765,6 +1766,7 @@ class VppPapiProvider(object): { 'sw_if_index': sw_if_index, 'hostname': hostname, + 'client_id': client_id, 'is_add': is_add, 'want_dhcp_event': want_dhcp_events, 'pid': os.getpid(), -- cgit 1.2.3-korg