| /* |
| * Copyright (c) 2015 Cisco and/or its affiliates. |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at: |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <vat/vat.h> |
| #include <vlibapi/api.h> |
| #include <vlibmemory/api.h> |
| #include <vppinfra/error.h> |
| |
| #include <dhcp/client.h> |
| #include <dhcp/dhcp_proxy.h> |
| #include <vnet/ip/ip_format_fns.h> |
| #include <vnet/ethernet/ethernet_format_fns.h> |
| |
| /* define message IDs */ |
| #include <dhcp/dhcp.api_enum.h> |
| #include <dhcp/dhcp.api_types.h> |
| |
| typedef struct |
| { |
| /* API message ID base */ |
| u16 msg_id_base; |
| vat_main_t *vat_main; |
| } dhcp_test_main_t; |
| |
| dhcp_test_main_t dhcp_test_main; |
| |
| #define __plugin_msg_base dhcp_test_main.msg_id_base |
| #include <vlibapi/vat_helper_macros.h> |
| |
| /* Macro to finish up custom dump fns */ |
| #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) |
| #define FINISH \ |
| vec_add1 (s, 0); \ |
| vl_print (handle, (char *)s); \ |
| vec_free (s); \ |
| return handle; |
| |
| static int |
| api_dhcp_proxy_config (vat_main_t * vam) |
| { |
| unformat_input_t *i = vam->input; |
| vl_api_dhcp_proxy_config_t *mp; |
| u32 rx_vrf_id = 0; |
| u32 server_vrf_id = 0; |
| u8 is_add = 1; |
| u8 v4_address_set = 0; |
| u8 v6_address_set = 0; |
| ip4_address_t v4address; |
| ip6_address_t v6address; |
| u8 v4_src_address_set = 0; |
| u8 v6_src_address_set = 0; |
| ip4_address_t v4srcaddress; |
| ip6_address_t v6srcaddress; |
| int ret; |
| |
| /* Parse args required to build the message */ |
| while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) |
| { |
| if (unformat (i, "del")) |
| is_add = 0; |
| else if (unformat (i, "rx_vrf_id %d", &rx_vrf_id)) |
| ; |
| else if (unformat (i, "server_vrf_id %d", &server_vrf_id)) |
| ; |
| else if (unformat (i, "svr %U", unformat_ip4_address, &v4address)) |
| v4_address_set = 1; |
| else if (unformat (i, "svr %U", unformat_ip6_address, &v6address)) |
| v6_address_set = 1; |
| else if (unformat (i, "src %U", unformat_ip4_address, &v4srcaddress)) |
| v4_src_address_set = 1; |
| else if (unformat (i, "src %U", unformat_ip6_address, &v6srcaddress)) |
| v6_src_address_set = 1; |
| else |
| break; |
| } |
| |
| if (v4_address_set && v6_address_set) |
| { |
| errmsg ("both v4 and v6 server addresses set"); |
| return -99; |
| } |
| if (!v4_address_set && !v6_address_set) |
| { |
| errmsg ("no server addresses set"); |
| return -99; |
| } |
| |
| if (v4_src_address_set && v6_src_address_set) |
| { |
| errmsg ("both v4 and v6 src addresses set"); |
| return -99; |
| } |
| if (!v4_src_address_set && !v6_src_address_set) |
| { |
| errmsg ("no src addresses set"); |
| return -99; |
| } |
| |
| if (!(v4_src_address_set && v4_address_set) && |
| !(v6_src_address_set && v6_address_set)) |
| { |
| errmsg ("no matching server and src addresses set"); |
| return -99; |
| } |
| |
| /* Construct the API message */ |
| M (DHCP_PROXY_CONFIG, mp); |
| |
| mp->is_add = is_add; |
| mp->rx_vrf_id = ntohl (rx_vrf_id); |
| mp->server_vrf_id = ntohl (server_vrf_id); |
| if (v6_address_set) |
| { |
| clib_memcpy (&mp->dhcp_server.un, &v6address, sizeof (v6address)); |
| clib_memcpy (&mp->dhcp_src_address.un, &v6srcaddress, |
| sizeof (v6address)); |
| } |
| else |
| { |
| clib_memcpy (&mp->dhcp_server.un, &v4address, sizeof (v4address)); |
| clib_memcpy (&mp->dhcp_src_address.un, &v4srcaddress, |
| sizeof (v4address)); |
| } |
| |
| /* send it... */ |
| S (mp); |
| |
| /* Wait for a reply, return good/bad news */ |
| W (ret); |
| return ret; |
| } |
| |
| static void |
| vl_api_dhcp_proxy_details_t_handler (vl_api_dhcp_proxy_details_t * mp) |
| { |
| vat_main_t *vam = &vat_main; |
| u32 i, count = mp->count; |
| vl_api_dhcp_server_t *s; |
| |
| if (mp->is_ipv6) |
| print (vam->ofp, |
| "RX Table-ID %d, Source Address %U, VSS Type %d, " |
| "VSS ASCII VPN-ID '%s', VSS RFC2685 VPN-ID (oui:id) %d:%d", |
| ntohl (mp->rx_vrf_id), |
| format_ip6_address, mp->dhcp_src_address, |
| mp->vss_type, mp->vss_vpn_ascii_id, |
| ntohl (mp->vss_oui), ntohl (mp->vss_fib_id)); |
| else |
| print (vam->ofp, |
| "RX Table-ID %d, Source Address %U, VSS Type %d, " |
| "VSS ASCII VPN-ID '%s', VSS RFC2685 VPN-ID (oui:id) %d:%d", |
| ntohl (mp->rx_vrf_id), |
| format_ip4_address, mp->dhcp_src_address, |
| mp->vss_type, mp->vss_vpn_ascii_id, |
| ntohl (mp->vss_oui), ntohl (mp->vss_fib_id)); |
| |
| for (i = 0; i < count; i++) |
| { |
| s = &mp->servers[i]; |
| |
| if (mp->is_ipv6) |
| print (vam->ofp, |
| " Server Table-ID %d, Server Address %U", |
| ntohl (s->server_vrf_id), format_ip6_address, s->dhcp_server); |
| else |
| print (vam->ofp, |
| " Server Table-ID %d, Server Address %U", |
| ntohl (s->server_vrf_id), format_ip4_address, s->dhcp_server); |
| } |
| } |
| |
| static int |
| api_dhcp_proxy_dump (vat_main_t * vam) |
| { |
| unformat_input_t *i = vam->input; |
| vl_api_dhcp_plugin_control_ping_t *mp_ping; |
| vl_api_dhcp_proxy_dump_t *mp; |
| u8 is_ipv6 = 0; |
| int ret; |
| |
| while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) |
| { |
| if (unformat (i, "ipv6")) |
| is_ipv6 = 1; |
| else |
| { |
| clib_warning ("parse error '%U'", format_unformat_error, i); |
| return -99; |
| } |
| } |
| |
| M (DHCP_PROXY_DUMP, mp); |
| |
| mp->is_ip6 = is_ipv6; |
| S (mp); |
| |
| /* Use a control ping for synchronization */ |
| MPING (DHCP_PLUGIN_CONTROL_PING, mp_ping); |
| S (mp_ping); |
| |
| W (ret); |
| return ret; |
| } |
| |
| static int |
| api_dhcp_proxy_set_vss (vat_main_t * vam) |
| { |
| unformat_input_t *i = vam->input; |
| vl_api_dhcp_proxy_set_vss_t *mp; |
| u8 is_ipv6 = 0; |
| u8 is_add = 1; |
| u32 tbl_id = ~0; |
| u8 vss_type = VSS_TYPE_DEFAULT; |
| u8 *vpn_ascii_id = 0; |
| u32 oui = 0; |
| u32 fib_id = 0; |
| int ret; |
| |
| while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) |
| { |
| if (unformat (i, "tbl_id %d", &tbl_id)) |
| ; |
| else if (unformat (i, "vpn_ascii_id %s", &vpn_ascii_id)) |
| vss_type = VSS_TYPE_ASCII; |
| else if (unformat (i, "fib_id %d", &fib_id)) |
| vss_type = VSS_TYPE_VPN_ID; |
| else if (unformat (i, "oui %d", &oui)) |
| vss_type = VSS_TYPE_VPN_ID; |
| else if (unformat (i, "ipv6")) |
| is_ipv6 = 1; |
| else if (unformat (i, "del")) |
| is_add = 0; |
| else |
| break; |
| } |
| |
| if (tbl_id == ~0) |
| { |
| errmsg ("missing tbl_id "); |
| vec_free (vpn_ascii_id); |
| return -99; |
| } |
| |
| if ((vpn_ascii_id) && (vec_len (vpn_ascii_id) > 128)) |
| { |
| errmsg ("vpn_ascii_id cannot be longer than 128 "); |
| vec_free (vpn_ascii_id); |
| return -99; |
| } |
| |
| M (DHCP_PROXY_SET_VSS, mp); |
| mp->tbl_id = ntohl (tbl_id); |
| mp->vss_type = vss_type; |
| if (vpn_ascii_id) |
| { |
| clib_memcpy (mp->vpn_ascii_id, vpn_ascii_id, vec_len (vpn_ascii_id)); |
| mp->vpn_ascii_id[vec_len (vpn_ascii_id)] = 0; |
| } |
| mp->vpn_index = ntohl (fib_id); |
| mp->oui = ntohl (oui); |
| mp->is_ipv6 = is_ipv6; |
| mp->is_add = is_add; |
| |
| S (mp); |
| W (ret); |
| |
| vec_free (vpn_ascii_id); |
| return ret; |
| } |
| |
| static int |
| api_dhcp_client_config (vat_main_t * vam) |
| { |
| unformat_input_t *i = vam->input; |
| vl_api_dhcp_client_config_t *mp; |
| u32 sw_if_index; |
| u8 sw_if_index_set = 0; |
| u8 is_add = 1; |
| u8 *hostname = 0; |
| u8 disable_event = 0; |
| int ret; |
| |
| /* Parse args required to build the message */ |
| while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) |
| { |
| if (unformat (i, "del")) |
| is_add = 0; |
| else if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) |
| sw_if_index_set = 1; |
| else if (unformat (i, "sw_if_index %d", &sw_if_index)) |
| sw_if_index_set = 1; |
| else if (unformat (i, "hostname %s", &hostname)) |
| ; |
| else if (unformat (i, "disable_event")) |
| disable_event = 1; |
| else |
| break; |
| } |
| |
| if (sw_if_index_set == 0) |
| { |
| errmsg ("missing interface name or sw_if_index"); |
| return -99; |
| } |
| |
| if (vec_len (hostname) > 63) |
| { |
| errmsg ("hostname too long"); |
| } |
| vec_add1 (hostname, 0); |
| |
| /* Construct the API message */ |
| M (DHCP_CLIENT_CONFIG, mp); |
| |
| mp->is_add = is_add; |
| mp->client.sw_if_index = htonl (sw_if_index); |
| clib_memcpy (mp->client.hostname, hostname, vec_len (hostname)); |
| vec_free (hostname); |
| mp->client.want_dhcp_event = disable_event ? 0 : 1; |
| mp->client.pid = htonl (getpid ()); |
| |
| /* send it... */ |
| S (mp); |
| |
| /* Wait for a reply, return good/bad news */ |
| W (ret); |
| return ret; |
| } |
| |
| static int |
| api_want_dhcp6_reply_events (vat_main_t * vam) |
| { |
| return -1; |
| } |
| |
| static int |
| api_want_dhcp6_pd_reply_events (vat_main_t * vam) |
| { |
| return -1; |
| } |
| |
| static int |
| api_dhcp6_send_client_message (vat_main_t * vam) |
| { |
| return -1; |
| } |
| |
| static int |
| api_dhcp6_pd_send_client_message (vat_main_t * vam) |
| { |
| return -1; |
| } |
| |
| static void |
| vl_api_dhcp_client_details_t_handler (vl_api_dhcp_client_details_t * mp) |
| { |
| vat_main_t *vam = &vat_main; |
| vl_api_dhcp_client_t *cp; |
| vl_api_dhcp_lease_t *lp; |
| |
| cp = &mp->client; |
| lp = &mp->lease; |
| |
| print (vam->ofp, "sw_if_index %d, id '%s'", ntohl (cp->sw_if_index), |
| cp->id); |
| |
| print (vam->ofp, "leased address %U, router address %U", |
| format_ip4_address, &lp->host_address.un, |
| format_ip4_address, &lp->router_address.un); |
| } |
| |
| static int |
| api_dhcp_client_dump (vat_main_t * vam) |
| { |
| vl_api_dhcp_plugin_control_ping_t *mp_ping; |
| vl_api_dhcp_client_dump_t *mp; |
| int ret; |
| |
| M (DHCP_CLIENT_DUMP, mp); |
| |
| S (mp); |
| |
| /* Use a control ping for synchronization */ |
| MPING (DHCP_PLUGIN_CONTROL_PING, mp_ping); |
| S (mp_ping); |
| |
| W (ret); |
| return ret; |
| } |
| |
| static int |
| api_dhcp6_duid_ll_set (vat_main_t * vam) |
| { |
| return -1; |
| } |
| |
| static int |
| api_dhcp6_clients_enable_disable (vat_main_t * vam) |
| { |
| return -1; |
| } |
| |
| static int |
| api_dhcp_plugin_control_ping (vat_main_t * vam) |
| { |
| return -1; |
| } |
| |
| static int |
| api_dhcp_plugin_get_version (vat_main_t * vam) |
| { |
| return -1; |
| } |
| |
| static void |
| vl_api_dhcp_plugin_get_version_reply_t_handler |
| (vl_api_dhcp_plugin_get_version_reply_t * mp) |
| { |
| vat_main_t *vam = dhcp_test_main.vat_main; |
| clib_warning ("DHCP plugin version: %d.%d", ntohl (mp->major), |
| ntohl (mp->minor)); |
| vam->result_ready = 1; |
| } |
| |
| static void |
| vl_api_dhcp_plugin_control_ping_reply_t_handler |
| (vl_api_dhcp_plugin_control_ping_reply_t * mp) |
| { |
| vat_main_t *vam = dhcp_test_main.vat_main; |
| i32 retval = ntohl (mp->retval); |
| if (vam->async_mode) |
| { |
| vam->async_errors += (retval < 0); |
| } |
| else |
| { |
| vam->retval = retval; |
| vam->result_ready = 1; |
| } |
| } |
| |
| #include <dhcp/dhcp.api_test.c> |
| |
| /* |
| * fd.io coding-style-patch-verification: ON |
| * |
| * Local Variables: |
| * eval: (c-set-style "gnu") |
| * End: |
| */ |