From: John Lo Date: Tue, 14 Nov 2017 18:19:26 +0000 (-0500) Subject: Add Support of DHCP VSS Type 0 where VPN-ID is ASCII X-Git-Tag: v18.04-rc0~232 X-Git-Url: https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commitdiff_plain;h=70bfcaf47779340951c1e6f169b1cedcabe708d1 Add Support of DHCP VSS Type 0 where VPN-ID is ASCII Enhence support of DHCP VSS (Virtual Subnet Selection) to include VSS type 0 where VSS info is a NVT (Network Virtual Terminal) ASCII VPN ID where the ASCII string MUST NOT be terminated with a zero byte. Existing code already support VSS type 1, where VSS information is a RFC 2685 VPN-ID of 7 bytes with 3 bytes OUI and 4 bytes VPN index, and VSS type 255 indicating global VPN. Change-Id: I54edbc447c89a2aacd1cc9fc72bd5ba386037608 Signed-off-by: John Lo --- diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 612fba66b0b..cfdce0bec2e 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -50,6 +50,7 @@ #include #include #include +#include #include "vat/json_format.h" @@ -7060,7 +7061,7 @@ api_bridge_domain_add_del (vat_main_t * vam) goto done; } - if ((bd_tag) && (strlen ((char *) bd_tag) > 63)) + if ((bd_tag) && (vec_len (bd_tag) > 63)) { errmsg ("bd-tag cannot be longer than 63"); ret = -99; @@ -7078,8 +7079,10 @@ api_bridge_domain_add_del (vat_main_t * vam) mp->is_add = is_add; mp->mac_age = (u8) mac_age; if (bd_tag) - strcpy ((char *) mp->bd_tag, (char *) bd_tag); - + { + clib_memcpy (mp->bd_tag, bd_tag, vec_len (bd_tag)); + mp->bd_tag[vec_len (bd_tag)] = 0; + } S (mp); W (ret); @@ -9337,15 +9340,19 @@ vl_api_dhcp_proxy_details_t_handler (vl_api_dhcp_proxy_details_t * mp) if (mp->is_ipv6) print (vam->ofp, - "RX Table-ID %d, Source Address %U, VSS FIB-ID %d, VSS OUI %d", + "RX Table-ID %d, Source Address %U, VSS Type %d, " + "VSS VPN-ID '%s', VSS FIB-ID %d, VSS OUI %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 FIB-ID %d, VSS OUI %d", + "RX Table-ID %d, Source Address %U, VSS Type %d, " + "VSS VPN-ID '%s', VSS FIB-ID %d, VSS OUI %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++) @@ -9382,6 +9389,10 @@ 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_bytes (node, "vss-type", &mp->vss_type, + sizeof (mp->vss_type)); + vat_json_object_add_string_copy (node, "vss-vpn-ascii-id", + mp->vss_vpn_ascii_id); vat_json_object_add_uint (node, "vss-fib-id", ntohl (mp->vss_fib_id)); vat_json_object_add_uint (node, "vss-oui", ntohl (mp->vss_oui)); @@ -9456,59 +9467,62 @@ api_dhcp_proxy_set_vss (vat_main_t * vam) vl_api_dhcp_proxy_set_vss_t *mp; u8 is_ipv6 = 0; u8 is_add = 1; - u32 tbl_id; - u8 tbl_id_set = 0; - u32 oui; - u8 oui_set = 0; - u32 fib_id; - u8 fib_id_set = 0; + 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)) - tbl_id_set = 1; - if (unformat (i, "fib_id %d", &fib_id)) - fib_id_set = 1; - if (unformat (i, "oui %d", &oui)) - oui_set = 1; + ; + 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 - { - clib_warning ("parse error '%U'", format_unformat_error, i); - return -99; - } + break; } - if (tbl_id_set == 0) + if (tbl_id == ~0) { - errmsg ("missing tbl id"); + errmsg ("missing tbl_id "); + vec_free (vpn_ascii_id); return -99; } - if (fib_id_set == 0) - { - errmsg ("missing fib id"); - return -99; - } - if (oui_set == 0) + if ((vpn_ascii_id) && (vec_len (vpn_ascii_id) > 128)) { - errmsg ("missing oui"); + 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->fib_id = ntohl (fib_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; } @@ -22344,7 +22358,7 @@ _(sw_interface_set_l2_bridge, \ "enable | disable") \ _(bridge_domain_set_mac_age, "bd_id mac-age 0-255") \ _(bridge_domain_add_del, \ - "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [mac-age 0-255] [bd-tag ] [del]\n") \ + "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [mac-age 0-255] [bd-tag ] [del]\n") \ _(bridge_domain_dump, "[bd_id ]\n") \ _(l2fib_add_del, \ "mac bd_id [del] | sw_if | sw_if_index [static] [filter] [bvi] [count ]\n") \ @@ -22409,7 +22423,7 @@ _(dhcp_proxy_config, \ "svr src \n" \ "rx_vrf_id server_vrf_id [del]") \ _(dhcp_proxy_set_vss, \ - "tbl_id fib_id oui [ipv6] [del]") \ + "tbl_id [fib_id oui | vpn_ascii_id ] [ipv6] [del]") \ _(dhcp_proxy_dump, "ip6") \ _(dhcp_client_config, \ " | sw_if_index [hostname ] [disable_event] [del]") \ diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api index 628b674e1c6..19650f5628b 100644 --- a/src/vnet/dhcp/dhcp.api +++ b/src/vnet/dhcp/dhcp.api @@ -13,7 +13,7 @@ * limitations under the License. */ -vl_api_version 1.0.0 +vl_api_version 1.0.1 /** \brief DHCP Proxy config add / del request @param client_index - opaque cookie to identify the sender @@ -42,8 +42,10 @@ autoreply define dhcp_proxy_config @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param tbl_id - table id - @param oui - first part of vpn id - @param fib_id - second part of vpn id + @vss_type - 0: use ASCI vpn_id; 1: use oui/vpn_index; 255: global vpn + @vpn_ascii - null terminated ASCII VPN ID up to 128 characters + @param oui - first part of rfc2685 vpn id, 3 bytes oui + @param vpn_index - second part of rfc2685 vpn id, 4 bytes vpn index @param is_ipv6 - ip6 if non-zero, else ip4 @param is_add - set vss if non-zero, else delete */ @@ -52,8 +54,10 @@ autoreply define dhcp_proxy_set_vss u32 client_index; u32 context; u32 tbl_id; + u8 vss_type; + u8 vpn_ascii_id[129]; u32 oui; - u32 fib_id; + u32 vpn_index; u8 is_ipv6; u8 is_add; }; @@ -128,6 +132,8 @@ manual_endian manual_print define dhcp_proxy_details u32 rx_vrf_id; u32 vss_oui; u32 vss_fib_id; + u8 vss_type; + u8 vss_vpn_ascii_id[129]; u8 is_ipv6; u8 dhcp_src_address[16]; u8 count; diff --git a/src/vnet/dhcp/dhcp4_proxy_node.c b/src/vnet/dhcp/dhcp4_proxy_node.c index 339a78858a7..cd52be83f71 100644 --- a/src/vnet/dhcp/dhcp4_proxy_node.c +++ b/src/vnet/dhcp/dhcp4_proxy_node.c @@ -229,19 +229,19 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, } } o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); - } + } fl = vlib_buffer_get_free_list (vm, vlib_buffer_get_free_list_index (b0)); // 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; @@ -264,65 +264,53 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, 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; + u32 *o_ifid = (u32 *) &o->data[2]; + *o_ifid = clib_host_to_net_u32 (original_sw_if_index); 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]; + u32 *o_addr = (u32 *) &o->data[8]; + *o_addr = ia0->as_u32; 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; - } - } + if (vss) + { + u32 id_len; /* length of VPN ID */ + + if (vss->vss_type == VSS_TYPE_VPN_ID) + { + id_len = sizeof (vss->vpn_id); /* vpn_id is 7 bytes */ + memcpy (&o->data[15], vss->vpn_id, id_len); + } + else if (vss->vss_type == VSS_TYPE_ASCII) + { + id_len = vec_len (vss->vpn_ascii_id); + memcpy (&o->data[15], vss->vpn_ascii_id, id_len); + } + else /* must be VSS_TYPE_DEFAULT, no VPN ID */ + id_len = 0; + + o->data[12] = 151; /* vss suboption */ + o->data[13] = id_len + 1; /* length: vss_type + id_len */ + o->data[14] = vss->vss_type; /* vss option type */ + o->data[15 + id_len] = 152; /* vss control suboption */ + o->data[16 + id_len] = 0; /* length */ + o->data[17 + id_len] = 0xFF; /* "end-of-options" (0xFF) */ + /* 5 bytes for suboption headers 151+len, 152+len and 0xFF */ + o->length += id_len + 5; + } len = o->length + 3; b0->current_length += len; @@ -341,11 +329,13 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, new_l0 = clib_net_to_host_u16 (u0->length); new_l0 += len; u0->length = clib_host_to_net_u16 (new_l0); - } else { + } + 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; @@ -355,11 +345,11 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, * 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; @@ -387,7 +377,7 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, 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)); @@ -397,15 +387,15 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, 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: @@ -949,54 +939,47 @@ 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; + u8 is_del = 0, vss_type = VSS_TYPE_DEFAULT; + u32 oui = 0, fib_id = 0, tbl_id = ~0; + u8 *vpn_ascii_id = 0; while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { - - if (unformat(input, "delete") || unformat(input, "del")) - is_del = 1; + if (unformat (input, "table %d", &tbl_id)) + ; else if (unformat (input, "oui %d", &oui)) - got_new_vpn_id = 1; + vss_type = VSS_TYPE_VPN_ID; 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; + vss_type = VSS_TYPE_VPN_ID; + else if (unformat (input, "vpn-ascii-id %s", &vpn_ascii_id)) + vss_type = VSS_TYPE_ASCII; + else if (unformat(input, "delete") || unformat(input, "del")) + is_del = 1; else - break; - } + break; + } + if (tbl_id == ~0) return clib_error_return (0, "no table ID specified."); - if (is_del || got_new_vpn_id) + int rv = dhcp_proxy_set_vss (FIB_PROTOCOL_IP4, tbl_id, vss_type, + vpn_ascii_id, oui, fib_id, is_del); + switch (rv) { - 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); - } + case 0: + return 0; + 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 ", + .short_help = "set dhcp option-82 vss [del] table
[oui vpn-id | vpn-ascii-id ]", .function = dhcp_option_82_vss_fn, }; diff --git a/src/vnet/dhcp/dhcp6_packet.h b/src/vnet/dhcp/dhcp6_packet.h index ddcde7a0dd9..24a18144b16 100644 --- a/src/vnet/dhcp/dhcp6_packet.h +++ b/src/vnet/dhcp/dhcp6_packet.h @@ -164,7 +164,8 @@ typedef CLIB_PACKED (struct { typedef CLIB_PACKED (struct { dhcpv6_option_t opt; - u8 data[8]; // data[0]:type, data[1..7]: VPN ID + u8 vss_type; + u8 data[0]; }) dhcpv6_vss_t; typedef CLIB_PACKED (struct { diff --git a/src/vnet/dhcp/dhcp6_proxy_node.c b/src/vnet/dhcp/dhcp6_proxy_node.c index ce7a8fca3bc..3cac278aa53 100644 --- a/src/vnet/dhcp/dhcp6_proxy_node.c +++ b/src/vnet/dhcp/dhcp6_proxy_node.c @@ -330,31 +330,40 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, 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)); + 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 + 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) { + if (vss) + { + u16 id_len; /* length of VPN ID */ + u16 type_len = sizeof (vss1->vss_type); + 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); - } + vss1->vss_type = vss->vss_type; + if (vss->vss_type == VSS_TYPE_VPN_ID) + { + id_len = sizeof (vss->vpn_id); /* vpn_id is 7 bytes */ + memcpy (vss1->data, vss->vpn_id, id_len); + } + else if (vss->vss_type == VSS_TYPE_ASCII) + { + id_len = vec_len (vss->vpn_ascii_id); + memcpy (vss1->data, vss->vpn_ascii_id, id_len); + } + else /* must be VSS_TYPE_DEFAULT, no VPN ID */ + id_len = 0; + + vss1->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_VSS); + vss1->opt.length = clib_host_to_net_u16 (type_len + id_len); + u1->length += type_len + id_len + sizeof (vss1->opt); + b0->current_length += type_len + id_len + sizeof (vss1->opt); + } pkts_to_server++; u1->checksum = 0; @@ -1030,18 +1039,20 @@ 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; + u8 is_del = 0, vss_type = VSS_TYPE_DEFAULT; + u8 *vpn_ascii_id = 0; + u32 oui = 0, 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; + if (unformat (input, "table %d", &tbl_id)) + ; + else if (unformat (input, "oui %d", &oui)) + vss_type = VSS_TYPE_VPN_ID; 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; + vss_type = VSS_TYPE_VPN_ID; + else if (unformat (input, "vpn-ascii-id %s", &vpn_ascii_id)) + vss_type = VSS_TYPE_ASCII; else if (unformat(input, "delete") || unformat(input, "del")) is_del = 1; else @@ -1051,37 +1062,23 @@ dhcpv6_vss_command_fn (vlib_main_t * vm, if (tbl_id ==~0) return clib_error_return (0, "no table ID specified."); - if (is_del || got_new_vss) + int rv = dhcp_proxy_set_vss(FIB_PROTOCOL_IP6, tbl_id, vss_type, + vpn_ascii_id, oui, fib_id, is_del); + switch (rv) { - 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); - } + case 0: + return 0; + 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 ", + .short_help = "set dhcpv6 vss table [oui vpn-id | vpn-ascii-id ]", .function = dhcpv6_vss_command_fn, }; diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index d6984f2d083..ad96e027f57 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -55,14 +55,16 @@ static void vl_api_dhcp_proxy_set_vss_t_handler (vl_api_dhcp_proxy_set_vss_t * mp) { vl_api_dhcp_proxy_set_vss_reply_t *rmp; + u8 *vpn_ascii_id; int rv; - 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); + mp->vpn_ascii_id[sizeof (mp->vpn_ascii_id) - 1] = 0; + vpn_ascii_id = format (0, "%s", mp->vpn_ascii_id); + rv = + dhcp_proxy_set_vss ((mp->is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4), + ntohl (mp->tbl_id), mp->vss_type, vpn_ascii_id, + ntohl (mp->oui), ntohl (mp->vpn_index), + mp->is_add == 0); REPLY_MACRO (VL_API_DHCP_PROXY_SET_VSS_REPLY); } @@ -147,11 +149,27 @@ dhcp_send_details (fib_protocol_t proto, vss = dhcp_get_vss_info (&dhcp_proxy_main, proxy->rx_fib_index, proto); - if (NULL != vss) + if (vss) { - mp->vss_oui = htonl (vss->oui); - mp->vss_fib_id = htonl (vss->fib_id); + mp->vss_type = vss->vss_type; + if (vss->vss_type == VSS_TYPE_ASCII) + { + u32 id_len = vec_len (vss->vpn_ascii_id); + clib_memcpy (mp->vss_vpn_ascii_id, vss->vpn_ascii_id, id_len); + } + else if (vss->vss_type == VSS_TYPE_VPN_ID) + { + u32 oui = ((u32) vss->vpn_id[0] << 16) + ((u32) vss->vpn_id[1] << 8) + + ((u32) vss->vpn_id[2]); + u32 fib_id = ((u32) vss->vpn_id[3] << 24) + + ((u32) vss->vpn_id[4] << 16) + ((u32) vss->vpn_id[5] << 8) + + ((u32) vss->vpn_id[6]); + mp->vss_oui = htonl (oui); + mp->vss_fib_id = htonl (fib_id); + } } + else + mp->vss_type = VSS_TYPE_INVALID; vec_foreach_index (count, proxy->dhcp_servers) { diff --git a/src/vnet/dhcp/dhcp_proxy.c b/src/vnet/dhcp/dhcp_proxy.c index 1784906b7b3..dae631236de 100644 --- a/src/vnet/dhcp/dhcp_proxy.c +++ b/src/vnet/dhcp/dhcp_proxy.c @@ -278,19 +278,60 @@ dhcp_vss_show_walk (dhcp_vss_t *vss, { vlib_main_t * vm = ctx; - vlib_cli_output (vm, "%=6d%=6d%=12d", - rx_table_id, - vss->oui, - vss->fib_id); + if (vss->vss_type == VSS_TYPE_VPN_ID) + { + u32 oui = ((u32) vss->vpn_id[0] << 16) + ((u32) vss->vpn_id[1] << 8) + + ((u32) vss->vpn_id[2]); + u32 fib_id = ((u32) vss->vpn_id[3] << 24) + ((u32) vss->vpn_id[4] << 16) + + ((u32) vss->vpn_id[5] << 8) + ((u32) vss->vpn_id[6]); + vlib_cli_output (vm, " fib_table: %d oui: %d vpn_index: %d", + rx_table_id, oui, fib_id); + } + else if (vss->vss_type == VSS_TYPE_ASCII) + vlib_cli_output (vm, " fib_table: %d vpn_id: %s", + rx_table_id, vss->vpn_ascii_id); + else + vlib_cli_output (vm, " fib_table: %d default global vpn", rx_table_id); return (1); } +void update_vss (dhcp_vss_t *v, + u8 vss_type, + u8 *vpn_ascii_id, + u32 oui, + u32 vpn_index) +{ + v->vss_type = vss_type; + if (v->vpn_ascii_id) + { + if (v->vpn_ascii_id == (u8 *) ~0) + v->vpn_ascii_id = 0; + else + vec_free (v->vpn_ascii_id); + } + + if (vss_type == VSS_TYPE_ASCII) + v->vpn_ascii_id = vpn_ascii_id; + else if (vss_type == VSS_TYPE_VPN_ID) + { + v->vpn_id[0] = (oui >> 16) & 0xff; + v->vpn_id[1] = (oui >> 8) & 0xff; + v->vpn_id[2] = (oui >> 0) & 0xff; + v->vpn_id[3] = (vpn_index >> 24) & 0xff; + v->vpn_id[4] = (vpn_index >> 16) & 0xff; + v->vpn_id[5] = (vpn_index >> 8) & 0xff; + v->vpn_id[6] = (vpn_index >> 0) & 0xff; + } +} + int dhcp_proxy_set_vss (fib_protocol_t proto, u32 tbl_id, + u8 vss_type, + u8 *vpn_ascii_id, u32 oui, - u32 fib_id, - int is_del) + u32 vpn_index, + u8 is_del) { dhcp_proxy_main_t *dm = &dhcp_proxy_main; dhcp_vss_t *v = NULL; @@ -306,43 +347,40 @@ int dhcp_proxy_set_vss (fib_protocol_t proto, 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 */ dhcp_proxy_rx_table_unlock (proto, rx_fib_index); + vec_free (v->vpn_ascii_id); 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; - } - } + { + update_vss (v, vss_type, vpn_ascii_id, oui, vpn_index); + } + } else - { + { if (is_del) - rc = VNET_API_ERROR_NO_SUCH_ENTRY; + 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 */ pool_get (dm->vss[proto], v); - v->fib_id = fib_id; - v->oui = oui; - + update_vss (v, vss_type, vpn_ascii_id, oui, vpn_index); dm->vss_index_by_rx_fib_index[proto][rx_fib_index] = v - dm->vss[proto]; dhcp_proxy_rx_table_lock (proto, rx_fib_index); - } - } + } + } /* Release the lock taken during the create_or_lock at the start */ dhcp_proxy_rx_table_unlock (proto, rx_fib_index); diff --git a/src/vnet/dhcp/dhcp_proxy.h b/src/vnet/dhcp/dhcp_proxy.h index ef2bc0a1926..9b15ac82d1e 100644 --- a/src/vnet/dhcp/dhcp_proxy.h +++ b/src/vnet/dhcp/dhcp_proxy.h @@ -48,13 +48,24 @@ typedef enum { */ typedef struct dhcp_vss_t_ { /** - * @brief ?? RFC doesn't say + * @brief VSS type as defined in RFC 6607: + * 0 for NVT ASCII VPN Identifier + * 1 for RFC 2685 VPN-ID of 7 octects - 3 bytes OUI & 4 bytes VPN index + * 255 for global default VPN */ - u32 oui; + u8 vss_type; +#define VSS_TYPE_ASCII 0 +#define VSS_TYPE_VPN_ID 1 +#define VSS_TYPE_INVALID 123 +#define VSS_TYPE_DEFAULT 255 /** - * @brief VPN-ID + * @brief Type 1 VPN-ID */ - u32 fib_id; + u8 vpn_id[7]; + /** + * @brief Type 0 ASCII VPN Identifier + */ + u8 *vpn_ascii_id; } dhcp_vss_t; /** @@ -152,11 +163,13 @@ int dhcp_vss_show_walk (dhcp_vss_t *vss, /** * @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); +int dhcp_proxy_set_vss (fib_protocol_t proto, + u32 tbl_id, + u8 vss_type, + u8 *vpn_ascii_id, + u32 oui, + u32 vpn_index, + u8 is_del); /** * @brief Dump the proxy configs to the API diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index fd0e88a9bb1..f27acda24dd 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -844,9 +844,13 @@ static void *vl_api_dhcp_proxy_set_vss_t_print s = format (s, "tbl_id %d ", ntohl (mp->tbl_id)); - s = format (s, "fib_id %d ", ntohl (mp->fib_id)); - - s = format (s, "oui %d ", ntohl (mp->oui)); + if (mp->vss_type == VSS_TYPE_VPN_ID) + { + s = format (s, "fib_id %d ", ntohl (mp->vpn_index)); + s = format (s, "oui %d ", ntohl (mp->oui)); + } + else if (mp->vss_type == VSS_TYPE_ASCII) + s = format (s, "vpn_ascii_id %s", mp->vpn_ascii_id); if (mp->is_ipv6 != 0) s = format (s, "ipv6 "); diff --git a/test/test_dhcp.py b/test/test_dhcp.py index 42b80af35d7..7ae98e8e83b 100644 --- a/test/test_dhcp.py +++ b/test/test_dhcp.py @@ -4,7 +4,7 @@ import unittest import socket import struct -from framework import VppTestCase, VppTestRunner +from framework import VppTestCase, VppTestRunner, running_extended_tests from vpp_neighbor import VppNeighbor from vpp_ip_route import find_route, VppIpTable from util import mk_ll_addr @@ -33,12 +33,12 @@ class TestDHCP(VppTestCase): def setUp(self): super(TestDHCP, self).setUp() - # create 3 pg interfaces - self.create_pg_interfaces(range(4)) + # create 6 pg interfaces for pg0 to pg5 + self.create_pg_interfaces(range(6)) self.tables = [] - # pg0 and 1 are IP configured in VRF 0 and 1. - # pg2 and 3 are non IP-configured in VRF 0 and 1 + # pg0 to 2 are IP configured in VRF 0, 1 and 2. + # pg3 to 5 are non IP-configured in VRF 0, 1 and 2. table_id = 0 for table_id in range(1, 4): tbl4 = VppIpTable(self, table_id) @@ -49,7 +49,7 @@ class TestDHCP(VppTestCase): self.tables.append(tbl6) table_id = 0 - for i in self.pg_interfaces[:2]: + for i in self.pg_interfaces[:3]: i.admin_up() i.set_table_ip4(table_id) i.set_table_ip6(table_id) @@ -60,14 +60,14 @@ class TestDHCP(VppTestCase): table_id += 1 table_id = 0 - for i in self.pg_interfaces[2:]: + for i in self.pg_interfaces[3:]: i.admin_up() i.set_table_ip4(table_id) i.set_table_ip6(table_id) table_id += 1 def tearDown(self): - for i in self.pg_interfaces[:2]: + for i in self.pg_interfaces[:3]: i.unconfig_ip4() i.unconfig_ip6() @@ -96,10 +96,11 @@ class TestDHCP(VppTestCase): self.assertTrue(found) - def validate_relay_options(self, pkt, intf, ip_addr, fib_id, oui): + def validate_relay_options(self, pkt, intf, ip_addr, vpn_id, fib_id, oui): dhcp = pkt[DHCP] found = 0 data = [] + id_len = len(vpn_id) for i in dhcp.options: if type(i) is tuple: @@ -110,6 +111,8 @@ class TestDHCP(VppTestCase): data = i[1] if oui != 0: self.assertEqual(len(data), 24) + elif len(vpn_id) > 0: + self.assertEqual(len(data), len(vpn_id)+17) else: self.assertEqual(len(data), 12) @@ -142,8 +145,9 @@ class TestDHCP(VppTestCase): self.assertEqual(data[11], claddr[3]) if oui != 0: - # sub-option 151 encodes the 3 byte oui - # and the 4 byte fib_id + # sub-option 151 encodes vss_type 1, + # the 3 byte oui and the 4 byte fib_id + self.assertEqual(id_len, 0) self.assertEqual(ord(data[12]), 151) self.assertEqual(ord(data[13]), 8) self.assertEqual(ord(data[14]), 1) @@ -159,6 +163,19 @@ class TestDHCP(VppTestCase): self.assertEqual(ord(data[22]), 152) self.assertEqual(ord(data[23]), 0) + if id_len > 0: + # sub-option 151 encode vss_type of 0 + # followerd by vpn_id in ascii + self.assertEqual(oui, 0) + self.assertEqual(ord(data[12]), 151) + self.assertEqual(ord(data[13]), id_len+1) + self.assertEqual(ord(data[14]), 0) + self.assertEqual(data[15:15+id_len], vpn_id) + + # VSS control sub-option + self.assertEqual(ord(data[15+len(vpn_id)]), 152) + self.assertEqual(ord(data[16+len(vpn_id)]), 0) + found = 1 self.assertTrue(found) @@ -174,7 +191,7 @@ class TestDHCP(VppTestCase): found = True self.assertTrue(found) - def verify_dhcp_offer(self, pkt, intf, fib_id=0, oui=0): + def verify_dhcp_offer(self, pkt, intf, vpn_id="", fib_id=0, oui=0): ether = pkt[Ether] self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") self.assertEqual(ether.src, intf.local_mac) @@ -189,7 +206,7 @@ class TestDHCP(VppTestCase): self.verify_dhcp_msg_type(pkt, "offer") data = self.validate_relay_options(pkt, intf, intf.local_ip4, - fib_id, oui) + vpn_id, fib_id, oui) def verify_orig_dhcp_pkt(self, pkt, intf): ether = pkt[Ether] @@ -229,6 +246,7 @@ class TestDHCP(VppTestCase): def verify_relayed_dhcp_discover(self, pkt, intf, src_intf=None, fib_id=0, oui=0, + vpn_id="", dst_mac=None, dst_ip=None): if not dst_mac: dst_mac = intf.remote_mac @@ -259,11 +277,13 @@ class TestDHCP(VppTestCase): data = self.validate_relay_options(pkt, src_intf, src_intf.local_ip4, + vpn_id, fib_id, oui) return data def verify_dhcp6_solicit(self, pkt, intf, peer_ip, peer_mac, + vpn_id="", fib_id=0, oui=0, dst_mac=None, @@ -293,7 +313,10 @@ class TestDHCP(VppTestCase): self.assertEqual(cll.lltype, 1) self.assertEqual(cll.clladdr, peer_mac) + id_len = len(vpn_id) + if fib_id != 0: + self.assertEqual(id_len, 0) vss = pkt[DHCP6OptVSS] self.assertEqual(vss.optlen, 8) self.assertEqual(vss.type, 1) @@ -307,6 +330,13 @@ class TestDHCP(VppTestCase): self.assertEqual(ord(vss.data[5]), 0) self.assertEqual(ord(vss.data[6]), fib_id) + if id_len > 0: + self.assertEqual(oui, 0) + vss = pkt[DHCP6OptVSS] + self.assertEqual(vss.optlen, id_len+1) + self.assertEqual(vss.type, 0) + self.assertEqual(vss.data[0:id_len], vpn_id) + # the relay message should be an encoded Solicit msg = pkt[DHCP6OptRelayMsg] sol = DHCP6_Solicit() @@ -336,7 +366,7 @@ class TestDHCP(VppTestCase): # Verify no response to DHCP request without DHCP config # p_disc_vrf0 = (Ether(dst="ff:ff:ff:ff:ff:ff", - src=self.pg2.remote_mac) / + 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) / @@ -344,17 +374,27 @@ class TestDHCP(VppTestCase): DHCP(options=[('message-type', 'discover'), ('end')])) pkts_disc_vrf0 = [p_disc_vrf0] p_disc_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff", - src=self.pg3.remote_mac) / + src=self.pg4.remote_mac) / + IP(src="0.0.0.0", dst="255.255.255.255") / + UDP(sport=DHCP4_CLIENT_PORT, + dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'discover'), ('end')])) + pkts_disc_vrf1 = [p_disc_vrf1] + p_disc_vrf2 = (Ether(dst="ff:ff:ff:ff:ff:ff", + src=self.pg5.remote_mac) / IP(src="0.0.0.0", dst="255.255.255.255") / UDP(sport=DHCP4_CLIENT_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'discover'), ('end')])) - pkts_disc_vrf1 = [p_disc_vrf0] + pkts_disc_vrf2 = [p_disc_vrf2] - self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0, "DHCP with no configuration") - self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, + self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1, + "DHCP with no configuration") + self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2, "DHCP with no configuration") # @@ -371,7 +411,7 @@ class TestDHCP(VppTestCase): # Discover packets from the client are dropped because there is no # IP address configured on the client facing interface # - self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0, "Discover DHCP no relay address") # @@ -386,13 +426,13 @@ class TestDHCP(VppTestCase): DHCP(options=[('message-type', 'offer'), ('end')])) pkts = [p] - self.send_and_assert_no_replies(self.pg2, pkts, + self.send_and_assert_no_replies(self.pg3, pkts, "Offer DHCP no relay address") # # configure an IP address on the client facing interface # - self.pg2.config_ip4() + self.pg3.config_ip4() # # Try again with a discover packet @@ -401,7 +441,7 @@ class TestDHCP(VppTestCase): # UDP source ports are unchanged # we've no option 82 config so that should be absent # - self.pg2.add_stream(pkts_disc_vrf0) + self.pg3.add_stream(pkts_disc_vrf0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -409,7 +449,7 @@ class TestDHCP(VppTestCase): rx = rx[0] option_82 = self.verify_relayed_dhcp_discover(rx, self.pg0, - src_intf=self.pg2) + src_intf=self.pg3) # # Create an DHCP offer reply from the server with a correctly formatted @@ -429,10 +469,10 @@ class TestDHCP(VppTestCase): self.pg_enable_capture(self.pg_interfaces) self.pg_start() - rx = self.pg2.get_capture(1) + rx = self.pg3.get_capture(1) rx = rx[0] - self.verify_dhcp_offer(rx, self.pg2) + self.verify_dhcp_offer(rx, self.pg3) # # Bogus Option 82: @@ -469,7 +509,7 @@ class TestDHCP(VppTestCase): # # Send a DHCP request in VRF 1. should be dropped. # - self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, + self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1, "DHCP with no configuration VRF 1") # @@ -481,65 +521,91 @@ class TestDHCP(VppTestCase): rx_table_id=0, is_add=0) - self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0, "DHCP config removed VRF 0") - self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, + self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1, "DHCP config removed VRF 1") # - # Add DHCP config for VRF 1 + # Add DHCP config for VRF 1 & 2 # - server_addr = self.pg1.remote_ip4n - src_addr = self.pg1.local_ip4n - self.vapi.dhcp_proxy_config(server_addr, - src_addr, + server_addr1 = self.pg1.remote_ip4n + src_addr1 = self.pg1.local_ip4n + self.vapi.dhcp_proxy_config(server_addr1, + src_addr1, rx_table_id=1, server_table_id=1) + server_addr2 = self.pg2.remote_ip4n + src_addr2 = self.pg2.local_ip4n + self.vapi.dhcp_proxy_config(server_addr2, + src_addr2, + rx_table_id=2, + server_table_id=2) # - # Confim DHCP requests ok in VRF 1. + # Confim DHCP requests ok in VRF 1 & 2. # - dropped on IP config on client interface # - self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, + self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1, "DHCP config removed VRF 1") + self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2, + "DHCP config removed VRF 2") # # configure an IP address on the client facing interface # - self.pg3.config_ip4() - - self.pg3.add_stream(pkts_disc_vrf1) + self.pg4.config_ip4() + self.pg4.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - rx = self.pg1.get_capture(1) rx = rx[0] - self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3) + self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg4) + + self.pg5.config_ip4() + self.pg5.add_stream(pkts_disc_vrf2) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + rx = self.pg2.get_capture(1) + rx = rx[0] + self.verify_relayed_dhcp_discover(rx, self.pg2, src_intf=self.pg5) # # Add VSS config - # table=1, fib=id=1, oui=4 - self.vapi.dhcp_proxy_set_vss(1, 1, 4) + # table=1, vss_type=1, vpn_index=1, oui=4 + # table=2, vss_type=0, vpn_id = "ip4-table-2" + self.vapi.dhcp_proxy_set_vss(1, 1, vpn_index=1, oui=4, is_add=1) + self.vapi.dhcp_proxy_set_vss(2, 0, "ip4-table-2", is_add=1) - self.pg3.add_stream(pkts_disc_vrf1) + self.pg4.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.verify_relayed_dhcp_discover(rx, self.pg1, - src_intf=self.pg3, + src_intf=self.pg4, fib_id=1, oui=4) + self.pg5.add_stream(pkts_disc_vrf2) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + rx = rx[0] + self.verify_relayed_dhcp_discover(rx, self.pg2, + src_intf=self.pg5, + vpn_id="ip4-table-2") + # # Add a second DHCP server in VRF 1 # expect clients messages to be relay to both configured servers # self.pg1.generate_remote_hosts(2) - server_addr2 = socket.inet_pton(AF_INET, self.pg1.remote_hosts[1].ip4) + server_addr12 = socket.inet_pton(AF_INET, self.pg1.remote_hosts[1].ip4) - self.vapi.dhcp_proxy_config(server_addr2, - src_addr, + self.vapi.dhcp_proxy_config(server_addr12, + src_addr1, rx_table_id=1, server_table_id=1, is_add=1) @@ -558,7 +624,7 @@ class TestDHCP(VppTestCase): # 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.pg4.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -566,12 +632,12 @@ class TestDHCP(VppTestCase): option_82 = self.verify_relayed_dhcp_discover( rx[0], self.pg1, - src_intf=self.pg3, + src_intf=self.pg4, dst_mac=self.pg1.remote_hosts[1].mac, dst_ip=self.pg1.remote_hosts[1].ip4, fib_id=1, oui=4) self.verify_relayed_dhcp_discover(rx[1], self.pg1, - src_intf=self.pg3, + src_intf=self.pg4, fib_id=1, oui=4) # @@ -597,10 +663,10 @@ class TestDHCP(VppTestCase): self.pg_enable_capture(self.pg_interfaces) self.pg_start() - rx = self.pg3.get_capture(2) + rx = self.pg4.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) + self.verify_dhcp_offer(rx[0], self.pg4, fib_id=1, oui=4) + self.verify_dhcp_offer(rx[1], self.pg4, fib_id=1, oui=4) # # Ensure offers from non-servers are dropeed @@ -619,7 +685,7 @@ class TestDHCP(VppTestCase): # 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) / + src=self.pg4.remote_mac) / IP(src="0.0.0.0", dst="255.255.255.255") / UDP(sport=DHCP4_CLIENT_PORT, dport=DHCP4_SERVER_PORT) / @@ -627,7 +693,7 @@ class TestDHCP(VppTestCase): DHCP(options=[('message-type', 'request'), ('end')])) - self.pg3.add_stream(p_req_vrf1) + self.pg4.add_stream(p_req_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -636,8 +702,8 @@ class TestDHCP(VppTestCase): # # Remove the second DHCP server # - self.vapi.dhcp_proxy_config(server_addr2, - src_addr, + self.vapi.dhcp_proxy_config(server_addr12, + src_addr1, rx_table_id=1, server_table_id=1, is_add=0) @@ -645,45 +711,55 @@ class TestDHCP(VppTestCase): # # Test we can still relay with the first # - self.pg3.add_stream(pkts_disc_vrf1) + self.pg4.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.verify_relayed_dhcp_discover(rx, self.pg1, - src_intf=self.pg3, + src_intf=self.pg4, fib_id=1, oui=4) # # Remove the VSS config # relayed DHCP has default vlaues in the option. # - self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_add=0) + self.vapi.dhcp_proxy_set_vss(1, is_add=0) + self.vapi.dhcp_proxy_set_vss(2, is_add=0) - self.pg3.add_stream(pkts_disc_vrf1) + self.pg4.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] - self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3) + self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg4) # # remove DHCP config to cleanup # - self.vapi.dhcp_proxy_config(server_addr, - src_addr, + self.vapi.dhcp_proxy_config(server_addr1, + src_addr1, rx_table_id=1, server_table_id=1, is_add=0) + self.vapi.dhcp_proxy_config(server_addr2, + src_addr2, + rx_table_id=2, + server_table_id=2, + is_add=0) - self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0, "DHCP cleanup VRF 0") - self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, + self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1, "DHCP cleanup VRF 1") - self.pg2.unconfig_ip4() + self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2, + "DHCP cleanup VRF 2") + self.pg3.unconfig_ip4() + self.pg4.unconfig_ip4() + self.pg5.unconfig_ip4() def test_dhcp6_proxy(self): """ DHCPv6 Proxy""" @@ -691,30 +767,41 @@ class TestDHCP(VppTestCase): # Verify no response to DHCP request without DHCP config # dhcp_solicit_dst = "ff02::1:2" - dhcp_solicit_src_vrf0 = mk_ll_addr(self.pg2.remote_mac) - dhcp_solicit_src_vrf1 = mk_ll_addr(self.pg3.remote_mac) + dhcp_solicit_src_vrf0 = mk_ll_addr(self.pg3.remote_mac) + dhcp_solicit_src_vrf1 = mk_ll_addr(self.pg4.remote_mac) + dhcp_solicit_src_vrf2 = mk_ll_addr(self.pg5.remote_mac) server_addr_vrf0 = self.pg0.remote_ip6n src_addr_vrf0 = self.pg0.local_ip6n server_addr_vrf1 = self.pg1.remote_ip6n src_addr_vrf1 = self.pg1.local_ip6n + server_addr_vrf2 = self.pg2.remote_ip6n + src_addr_vrf2 = self.pg2.local_ip6n dmac = in6_getnsmac(inet_pton(socket.AF_INET6, dhcp_solicit_dst)) - p_solicit_vrf0 = (Ether(dst=dmac, src=self.pg2.remote_mac) / + p_solicit_vrf0 = (Ether(dst=dmac, src=self.pg3.remote_mac) / IPv6(src=dhcp_solicit_src_vrf0, dst=dhcp_solicit_dst) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Solicit()) - p_solicit_vrf1 = (Ether(dst=dmac, src=self.pg3.remote_mac) / + p_solicit_vrf1 = (Ether(dst=dmac, src=self.pg4.remote_mac) / IPv6(src=dhcp_solicit_src_vrf1, dst=dhcp_solicit_dst) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Solicit()) + p_solicit_vrf2 = (Ether(dst=dmac, src=self.pg5.remote_mac) / + IPv6(src=dhcp_solicit_src_vrf2, + dst=dhcp_solicit_dst) / + UDP(sport=DHCP6_SERVER_PORT, + dport=DHCP6_CLIENT_PORT) / + DHCP6_Solicit()) - self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0, + self.send_and_assert_no_replies(self.pg3, p_solicit_vrf0, + "DHCP with no configuration") + self.send_and_assert_no_replies(self.pg4, p_solicit_vrf1, "DHCP with no configuration") - self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1, + self.send_and_assert_no_replies(self.pg5, p_solicit_vrf2, "DHCP with no configuration") # @@ -728,20 +815,20 @@ class TestDHCP(VppTestCase): server_table_id=0, is_ipv6=1) - self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0, + self.send_and_assert_no_replies(self.pg3, p_solicit_vrf0, "DHCP with no configuration") - self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1, + self.send_and_assert_no_replies(self.pg4, p_solicit_vrf1, "DHCP with no configuration") # # configure an IP address on the client facing interface # - self.pg2.config_ip6() + self.pg3.config_ip6() # # Now the DHCP requests are relayed to the server # - self.pg2.add_stream(p_solicit_vrf0) + self.pg3.add_stream(p_solicit_vrf0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -749,7 +836,7 @@ class TestDHCP(VppTestCase): self.verify_dhcp6_solicit(rx[0], self.pg0, dhcp_solicit_src_vrf0, - self.pg2.remote_mac) + self.pg3.remote_mac) # # Exception cases for rejected relay responses @@ -760,7 +847,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()) - self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, + self.send_and_assert_no_replies(self.pg3, p_adv_vrf0, "DHCP6 not a relay reply") # 2 - no relay message option @@ -769,7 +856,7 @@ class TestDHCP(VppTestCase): UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply() / DHCP6_Advertise()) - self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, + self.send_and_assert_no_replies(self.pg3, p_adv_vrf0, "DHCP not a relay message") # 3 - no circuit ID @@ -779,7 +866,7 @@ class TestDHCP(VppTestCase): DHCP6_RelayReply() / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise()) - self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, + self.send_and_assert_no_replies(self.pg3, p_adv_vrf0, "DHCP6 no circuit ID") # 4 - wrong circuit ID p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / @@ -789,7 +876,7 @@ class TestDHCP(VppTestCase): DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise()) - self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, + self.send_and_assert_no_replies(self.pg3, p_adv_vrf0, "DHCP6 wrong circuit ID") # @@ -799,7 +886,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_RelayReply() / - DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x03') / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) @@ -809,9 +896,9 @@ class TestDHCP(VppTestCase): self.pg_enable_capture(self.pg_interfaces) self.pg_start() - rx = self.pg2.get_capture(1) + rx = self.pg3.get_capture(1) - self.verify_dhcp6_advert(rx[0], self.pg2, "::") + self.verify_dhcp6_advert(rx[0], self.pg3, "::") # # Send the relay response (the advertisement) @@ -820,7 +907,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_RelayReply(peeraddr=dhcp_solicit_src_vrf0) / - DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x03') / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) @@ -830,24 +917,31 @@ class TestDHCP(VppTestCase): self.pg_enable_capture(self.pg_interfaces) self.pg_start() - rx = self.pg2.get_capture(1) + rx = self.pg3.get_capture(1) - self.verify_dhcp6_advert(rx[0], self.pg2, dhcp_solicit_src_vrf0) + self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf0) # - # Add all the config for VRF 1 + # Add all the config for VRF 1 & 2 # self.vapi.dhcp_proxy_config(server_addr_vrf1, src_addr_vrf1, rx_table_id=1, server_table_id=1, is_ipv6=1) - self.pg3.config_ip6() + self.pg4.config_ip6() + + self.vapi.dhcp_proxy_config(server_addr_vrf2, + src_addr_vrf2, + rx_table_id=2, + server_table_id=2, + is_ipv6=1) + self.pg5.config_ip6() # # VRF 1 solicit # - self.pg3.add_stream(p_solicit_vrf1) + self.pg4.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -855,7 +949,20 @@ class TestDHCP(VppTestCase): self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, - self.pg3.remote_mac) + self.pg4.remote_mac) + + # + # VRF 2 solicit + # + self.pg5.add_stream(p_solicit_vrf2) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + + self.verify_dhcp6_solicit(rx[0], self.pg2, + dhcp_solicit_src_vrf2, + self.pg5.remote_mac) # # VRF 1 Advert @@ -864,7 +971,7 @@ class TestDHCP(VppTestCase): 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') / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) @@ -874,16 +981,18 @@ class TestDHCP(VppTestCase): self.pg_enable_capture(self.pg_interfaces) self.pg_start() - rx = self.pg3.get_capture(1) + rx = self.pg4.get_capture(1) - self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1) + self.verify_dhcp6_advert(rx[0], self.pg4, 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) + # table=1, vss_type=1, vpn_index=1, oui=4 + # table=2, vss_type=0, vpn_id = "ip6-table-2" + self.vapi.dhcp_proxy_set_vss(1, 1, oui=4, vpn_index=1, is_ip6=1) + self.vapi.dhcp_proxy_set_vss(2, 0, "IPv6-table-2", is_ip6=1) - self.pg3.add_stream(p_solicit_vrf1) + self.pg4.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -891,17 +1000,28 @@ class TestDHCP(VppTestCase): self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, - self.pg3.remote_mac, + self.pg4.remote_mac, fib_id=1, oui=4) + self.pg5.add_stream(p_solicit_vrf2) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + + self.verify_dhcp6_solicit(rx[0], self.pg2, + dhcp_solicit_src_vrf2, + self.pg5.remote_mac, + vpn_id="IPv6-table-2") + # # Remove the VSS config # relayed DHCP has default vlaues in the option. # - self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1, is_add=0) + self.vapi.dhcp_proxy_set_vss(1, is_ip6=1, is_add=0) - self.pg3.add_stream(p_solicit_vrf1) + self.pg4.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -909,16 +1029,17 @@ class TestDHCP(VppTestCase): self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, - self.pg3.remote_mac) + self.pg4.remote_mac) # # Add a second DHCP server in VRF 1 # expect clients messages to be relay to both configured servers # self.pg1.generate_remote_hosts(2) - server_addr2 = socket.inet_pton(AF_INET6, self.pg1.remote_hosts[1].ip6) + server_addr12 = socket.inet_pton(AF_INET6, + self.pg1.remote_hosts[1].ip6) - self.vapi.dhcp_proxy_config(server_addr2, + self.vapi.dhcp_proxy_config(server_addr12, src_addr_vrf1, rx_table_id=1, server_table_id=1, @@ -939,7 +1060,7 @@ class TestDHCP(VppTestCase): # 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.pg4.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -947,10 +1068,10 @@ class TestDHCP(VppTestCase): self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, - self.pg3.remote_mac) + self.pg4.remote_mac) self.verify_dhcp6_solicit(rx[1], self.pg1, dhcp_solicit_src_vrf1, - self.pg3.remote_mac, + self.pg4.remote_mac, dst_mac=self.pg1.remote_hosts[1].mac, dst_ip=self.pg1.remote_hosts[1].ip6) @@ -961,7 +1082,7 @@ class TestDHCP(VppTestCase): 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') / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) @@ -969,7 +1090,7 @@ class TestDHCP(VppTestCase): 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') / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) @@ -980,22 +1101,22 @@ class TestDHCP(VppTestCase): self.pg_enable_capture(self.pg_interfaces) self.pg_start() - rx = self.pg3.get_capture(2) + rx = self.pg4.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) + self.verify_dhcp6_advert(rx[0], self.pg4, dhcp_solicit_src_vrf1) + self.verify_dhcp6_advert(rx[1], self.pg4, dhcp_solicit_src_vrf1) # # Ensure only solicit messages are duplicated # - p_request_vrf1 = (Ether(dst=dmac, src=self.pg3.remote_mac) / + p_request_vrf1 = (Ether(dst=dmac, src=self.pg4.remote_mac) / IPv6(src=dhcp_solicit_src_vrf1, dst=dhcp_solicit_dst) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Request()) - self.pg3.add_stream(p_request_vrf1) + self.pg4.add_stream(p_request_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -1009,7 +1130,7 @@ class TestDHCP(VppTestCase): 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') / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) @@ -1019,7 +1140,7 @@ class TestDHCP(VppTestCase): # # Remove the second DHCP server # - self.vapi.dhcp_proxy_config(server_addr2, + self.vapi.dhcp_proxy_config(server_addr12, src_addr_vrf1, rx_table_id=1, server_table_id=1, @@ -1029,7 +1150,7 @@ class TestDHCP(VppTestCase): # # Test we can still relay with the first # - self.pg3.add_stream(p_solicit_vrf1) + self.pg4.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -1037,11 +1158,17 @@ class TestDHCP(VppTestCase): self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, - self.pg3.remote_mac) + self.pg4.remote_mac) # # Cleanup # + self.vapi.dhcp_proxy_config(server_addr_vrf2, + src_addr_vrf2, + rx_table_id=2, + server_table_id=2, + is_ipv6=1, + is_add=0) self.vapi.dhcp_proxy_config(server_addr_vrf1, src_addr_vrf1, rx_table_id=1, @@ -1062,8 +1189,9 @@ class TestDHCP(VppTestCase): server_table_id=0, is_ipv6=1, is_add=0) - self.pg2.unconfig_ip6() self.pg3.unconfig_ip6() + self.pg4.unconfig_ip6() + self.pg5.unconfig_ip6() def test_dhcp_client(self): """ DHCP Client""" @@ -1073,119 +1201,119 @@ class TestDHCP(VppTestCase): self.pg_enable_capture(self.pg_interfaces) # - # Configure DHCP client on PG2 and capture the discover sent + # Configure DHCP client on PG3 and capture the discover sent # - self.vapi.dhcp_client(self.pg2.sw_if_index, hostname) + self.vapi.dhcp_client(self.pg3.sw_if_index, hostname) - rx = self.pg2.get_capture(1) + rx = self.pg3.get_capture(1) - self.verify_orig_dhcp_discover(rx[0], self.pg2, hostname) + self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname) # - # Sned back on offer, expect the request + # Send back on offer, expect the request # - p_offer = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / - IP(src=self.pg2.remote_ip4, dst="255.255.255.255") / + p_offer = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / + IP(src=self.pg3.remote_ip4, dst="255.255.255.255") / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / - BOOTP(op=1, yiaddr=self.pg2.local_ip4) / + BOOTP(op=1, yiaddr=self.pg3.local_ip4) / DHCP(options=[('message-type', 'offer'), - ('server_id', self.pg2.remote_ip4), + ('server_id', self.pg3.remote_ip4), ('end')])) - self.pg2.add_stream(p_offer) + self.pg3.add_stream(p_offer) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - rx = self.pg2.get_capture(1) - self.verify_orig_dhcp_request(rx[0], self.pg2, hostname, - self.pg2.local_ip4) + rx = self.pg3.get_capture(1) + self.verify_orig_dhcp_request(rx[0], self.pg3, hostname, + self.pg3.local_ip4) # # Send an acknowloedgement # - p_ack = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / - IP(src=self.pg2.remote_ip4, dst="255.255.255.255") / + p_ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / + IP(src=self.pg3.remote_ip4, dst="255.255.255.255") / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / - BOOTP(op=1, yiaddr=self.pg2.local_ip4) / + BOOTP(op=1, yiaddr=self.pg3.local_ip4) / DHCP(options=[('message-type', 'ack'), ('subnet_mask', "255.255.255.0"), - ('router', self.pg2.remote_ip4), - ('server_id', self.pg2.remote_ip4), + ('router', self.pg3.remote_ip4), + ('server_id', self.pg3.remote_ip4), ('lease_time', 43200), ('end')])) - self.pg2.add_stream(p_ack) + self.pg3.add_stream(p_ack) self.pg_enable_capture(self.pg_interfaces) self.pg_start() # # We'll get an ARP request for the router address # - rx = self.pg2.get_capture(1) + rx = self.pg3.get_capture(1) - self.assertEqual(rx[0][ARP].pdst, self.pg2.remote_ip4) + self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4) self.pg_enable_capture(self.pg_interfaces) # # At the end of this procedure there should be a connected route # in the FIB # - self.assertTrue(find_route(self, self.pg2.local_ip4, 24)) - self.assertTrue(find_route(self, self.pg2.local_ip4, 32)) + self.assertTrue(find_route(self, self.pg3.local_ip4, 24)) + self.assertTrue(find_route(self, self.pg3.local_ip4, 32)) # remove the left over ARP entry - self.vapi.ip_neighbor_add_del(self.pg2.sw_if_index, - mactobinary(self.pg2.remote_mac), - self.pg2.remote_ip4, + self.vapi.ip_neighbor_add_del(self.pg3.sw_if_index, + mactobinary(self.pg3.remote_mac), + self.pg3.remote_ip4, is_add=0) # # remove the DHCP config # - self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, is_add=0) + self.vapi.dhcp_client(self.pg3.sw_if_index, hostname, is_add=0) # # and now the route should be gone # - self.assertFalse(find_route(self, self.pg2.local_ip4, 32)) - self.assertFalse(find_route(self, self.pg2.local_ip4, 24)) + self.assertFalse(find_route(self, self.pg3.local_ip4, 32)) + self.assertFalse(find_route(self, self.pg3.local_ip4, 24)) # # Start the procedure again. this time have VPP send the client-ID # - self.pg2.admin_down() + self.pg3.admin_down() self.sleep(1) - self.pg2.admin_up() - self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, - client_id=self.pg2.local_mac) + self.pg3.admin_up() + self.vapi.dhcp_client(self.pg3.sw_if_index, hostname, + client_id=self.pg3.local_mac) - rx = self.pg2.get_capture(1) + rx = self.pg3.get_capture(1) - self.verify_orig_dhcp_discover(rx[0], self.pg2, hostname, - self.pg2.local_mac) + self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname, + self.pg3.local_mac) - self.pg2.add_stream(p_offer) + self.pg3.add_stream(p_offer) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - rx = self.pg2.get_capture(1) - self.verify_orig_dhcp_request(rx[0], self.pg2, hostname, - self.pg2.local_ip4) + rx = self.pg3.get_capture(1) + self.verify_orig_dhcp_request(rx[0], self.pg3, hostname, + self.pg3.local_ip4) # # unicast the ack to the offered address # - p_ack = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / - IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) / + p_ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / + IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / - BOOTP(op=1, yiaddr=self.pg2.local_ip4) / + BOOTP(op=1, yiaddr=self.pg3.local_ip4) / DHCP(options=[('message-type', 'ack'), ('subnet_mask', "255.255.255.0"), - ('router', self.pg2.remote_ip4), - ('server_id', self.pg2.remote_ip4), + ('router', self.pg3.remote_ip4), + ('server_id', self.pg3.remote_ip4), ('lease_time', 43200), ('end')])) - self.pg2.add_stream(p_ack) + self.pg3.add_stream(p_ack) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -1193,16 +1321,16 @@ class TestDHCP(VppTestCase): # 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)) - self.assertTrue(find_route(self, self.pg2.local_ip4, 24)) + self.assertTrue(find_route(self, self.pg3.local_ip4, 32)) + self.assertTrue(find_route(self, self.pg3.local_ip4, 24)) # # remove the DHCP config # - self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, is_add=0) + self.vapi.dhcp_client(self.pg3.sw_if_index, hostname, is_add=0) - self.assertFalse(find_route(self, self.pg2.local_ip4, 32)) - self.assertFalse(find_route(self, self.pg2.local_ip4, 24)) + self.assertFalse(find_route(self, self.pg3.local_ip4, 32)) + self.assertFalse(find_route(self, self.pg3.local_ip4, 24)) if __name__ == '__main__': diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 66126c599ae..3dd348286de 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -2021,18 +2021,22 @@ class VppPapiProvider(object): def dhcp_proxy_set_vss(self, table_id, - fib_id, - oui, + vss_type=255, + vpn_ascii_id="", + oui=0, + vpn_index=0, is_add=1, is_ip6=0): return self.api( self.papi.dhcp_proxy_set_vss, { 'tbl_id': table_id, - 'fib_id': fib_id, - 'is_ipv6': is_ip6, - 'is_add': is_add, + 'vss_type': vss_type, + 'vpn_ascii_id': vpn_ascii_id, 'oui': oui, + 'vpn_index': vpn_index, + 'is_add': is_add, + 'is_ipv6': is_ip6, }) def dhcp_client(self,