Browse Source

[trac3576] Add PXE options

Add the options used by PXE
rfc4578 (dhcpv4)
93 Client_System (arch type)
94 Client NDI (network Interface id)
97 UUID/GUID client machine option def

rfc5970 (dhcpv6)
59 BOOTFILE_URL
60 BOOTFILE_PARAM
61 CLIENT_ARCH_TYPE
62 NII

Option 60 requires a special class in order to process the length & string tuples

As some unreleated tests used option 59 as an undefined option they needed to be
updated to use another option.
Shawn Routhier 9 years ago
parent
commit
65097a0af7

+ 3 - 1
doc/guide/dhcp4-srv.xml

@@ -1085,7 +1085,9 @@ It is merely echoed by the server
 <row><entry>client-last-transaction-time</entry><entry>91</entry><entry>uint32</entry><entry>false</entry><entry>false</entry></row>
 <row><entry>associated-ip</entry><entry>92</entry><entry>ipv4-address</entry><entry>true</entry><entry>false</entry></row>
 -->
-<row><entry>subnet-selection</entry><entry>118</entry><entry>ipv4-address</entry><entry>false</entry><entry>false</entry></row>
+<row><entry>client-system</entry><entry>93</entry><entry>uint16</entry><entry>true</entry><entry>false</entry></row>
+<row><entry>client-ndi</entry><entry>94</entry><entry>record</entry><entry>false</entry><entry>false</entry></row>
+<row><entry>uuid-guid</entry><entry>97</entry><entry>record</entry><entry>false</entry><entry>false</entry></row>
 <row><entry>domain-search</entry><entry>119</entry><entry>binary</entry><entry>false</entry><entry>false</entry></row>
 <row><entry>vivco-suboptions</entry><entry>124</entry><entry>binary</entry><entry>false</entry><entry>false</entry></row>
 <row><entry>vivso-suboptions</entry><entry>125</entry><entry>binary</entry><entry>false</entry><entry>false</entry></row>

+ 4 - 0
doc/guide/dhcp6-srv.xml

@@ -954,6 +954,10 @@ temporarily override a list of interface names and listen on all interfaces.
 <row><entry>clt-time</entry><entry>46</entry><entry>uint32</entry><entry>false</entry></row>
 <row><entry>lq-relay-data</entry><entry>47</entry><entry>record</entry><entry>false</entry></row>
 <row><entry>lq-client-link</entry><entry>48</entry><entry>ipv6-address</entry><entry>true</entry></row>
+<row><entry>bootfile-url</entry><entry>59</entry><entry>string</entry><entry>false</entry></row>
+<row><entry>bootfile-param</entry><entry>60</entry><entry>binary</entry><entry>false</entry></row>
+<row><entry>client-arch-type</entry><entry>61</entry><entry>uint16</entry><entry>true</entry></row>
+<row><entry>nii</entry><entry>62</entry><entry>record</entry><entry>false</entry></row>
 <row><entry>erp-local-domain-name</entry><entry>65</entry><entry>fqdn</entry><entry>false</entry></row>
 <row><entry>rsoo</entry><entry>66</entry><entry>empty</entry><entry>false</entry></row>
 <row><entry>client-linklayer-addr</entry><entry>79</entry><entry>binary</entry><entry>false</entry></row>

+ 6 - 6
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -2067,15 +2067,15 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
     checkResult(status, 1);
     EXPECT_TRUE(errorContainsPosition(status, "<string>"));
 
-    /// @todo The option 59 is a standard DHCPv6 option. However, at this point
+    /// @todo The option 63 is a standard DHCPv6 option. However, at this point
     /// there is no definition for this option in libdhcp++, so it should be
     /// allowed to define it from the configuration interface. This test will
     /// have to be removed once definitions for remaining standard options are
     /// created.
     config =
         "{ \"option-def\": [ {"
-        "      \"name\": \"boot-file-name\","
-        "      \"code\": 59,"
+        "      \"name\": \"geolocation\","
+        "      \"code\": 63,"
         "      \"type\": \"string\","
         "      \"array\": False,"
         "      \"record-types\": \"\","
@@ -2092,12 +2092,12 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
     checkResult(status, 0);
 
     def = CfgMgr::instance().getStagingCfg()->
-        getCfgOptionDef()->get("dhcp6", 59);
+        getCfgOptionDef()->get("dhcp6", 63);
     ASSERT_TRUE(def);
 
     // Check the option data.
-    EXPECT_EQ("boot-file-name", def->getName());
-    EXPECT_EQ(59, def->getCode());
+    EXPECT_EQ("geolocation", def->getName());
+    EXPECT_EQ(63, def->getCode());
     EXPECT_EQ(OPT_STRING_TYPE, def->getType());
     EXPECT_FALSE(def->getArrayType());
 }

+ 1 - 0
src/lib/dhcp/Makefile.am

@@ -41,6 +41,7 @@ libkea_dhcp___la_SOURCES += option.cc option.h
 libkea_dhcp___la_SOURCES += option_custom.cc option_custom.h
 libkea_dhcp___la_SOURCES += option_data_types.cc option_data_types.h
 libkea_dhcp___la_SOURCES += option_definition.cc option_definition.h
+libkea_dhcp___la_SOURCES += option_opaque_data_tuples.cc option_opqaue_data_tuples.h
 libkea_dhcp___la_SOURCES += option_space.cc option_space.h
 libkea_dhcp___la_SOURCES += option_string.cc option_string.h
 libkea_dhcp___la_SOURCES += protocol_util.cc protocol_util.h

+ 3 - 3
src/lib/dhcp/dhcp4.h

@@ -165,11 +165,11 @@ enum DHCPOptionType {
     DHO_AUTHENTICATE                 = 90,  /* RFC3118, was 210 */
     DHO_CLIENT_LAST_TRANSACTION_TIME = 91,
     DHO_ASSOCIATED_IP                = 92,
-//  DHO_SYSTEM                       = 93,
-//  DHO_NDI                          = 94,
+    DHO_SYSTEM                       = 93, /* RFC4578 */
+    DHO_NDI                          = 94, /* RFC4578 */
 //  DHO_LDAP                         = 95,
     // 96 is removed/unassigned
-//  DHO_UUID_GUID                    = 97,
+    DHO_UUID_GUID                    = 97, /* RFC4578 */
 //  DHO_USER_AUTH                    = 98,
 //  DHO_GEOCONF_CIVIC                = 99,
 //  DHO_PCODE                        = 100,

+ 4 - 4
src/lib/dhcp/dhcp6.h

@@ -82,10 +82,10 @@
 //#define D6O_NTP_SERVER                          56 /* RFC5908 */
 //#define D6O_V6_ACCESS_DOMAIN                    57 /* RFC5986 */
 //#define D6O_SIP_UA_CS_LIST                      58 /* RFC6011 */
-//#define D6O_BOOTFILE_URL                        59 /* RFC5970 */
-//#define D6O_BOOTFILE_PARAM                      60 /* RFC5970 */
-//#define D6O_CLIENT_ARCH_TYPE                    61 /* RFC5970 */
-//#define D6O_NII                                 62 /* RFC5970 */
+#define D6O_BOOTFILE_URL                        59 /* RFC5970 */
+#define D6O_BOOTFILE_PARAM                      60 /* RFC5970 */
+#define D6O_CLIENT_ARCH_TYPE                    61 /* RFC5970 */
+#define D6O_NII                                 62 /* RFC5970 */
 //#define D6O_GEOLOCATION                         63 /* RFC6225 */
 //#define D6O_AFTR_NAME                           64 /* RFC6334 */
 #define D6O_ERP_LOCAL_DOMAIN_NAME               65 /* RFC6440 */

+ 9 - 0
src/lib/dhcp/option_definition.cc

@@ -27,6 +27,7 @@
 #include <dhcp/option_definition.h>
 #include <dhcp/option_int.h>
 #include <dhcp/option_int_array.h>
+#include <dhcp/option_opaque_data_tuples.h>
 #include <dhcp/option_space.h>
 #include <dhcp/option_string.h>
 #include <dhcp/option_vendor.h>
@@ -437,6 +438,11 @@ OptionDefinition::haveStatusCodeFormat() const {
 }
 
 bool
+OptionDefinition::haveOpaqueDataTuplesFormat() const {
+    return (getType() == OPT_BINARY_TYPE);
+}
+
+bool
 OptionDefinition::convertToBool(const std::string& value_str) const {
     // Case insensitve check that the input is one of: "true" or "false".
     if (boost::iequals(value_str, "true")) {
@@ -696,6 +702,9 @@ OptionDefinition::factorySpecialFormatOption(Option::Universe u,
         } else if (getCode() == D6O_STATUS_CODE && haveStatusCodeFormat()) {
             // Status Code (option code 13)
             return (OptionPtr(new Option6StatusCode(begin, end)));
+        } else if (getCode() == D6O_BOOTFILE_PARAM && haveOpaqueDataTuplesFormat()) {
+            // Bootfile params (option code 60)
+            return (OptionPtr(new OptionOpaqueDataTuples(Option::V6, getCode(), begin, end)));
         }
     } else {
         if ((getCode() == DHO_FQDN) && haveFqdn4Format()) {

+ 5 - 0
src/lib/dhcp/option_definition.h

@@ -370,6 +370,11 @@ public:
     /// @return true if option has the format of DHCPv6 Status code option.
     bool haveStatusCodeFormat() const;
 
+    /// @brief Check if the option has format of OpaqueDataTuples type options.
+    ///
+    /// @return true if option has the format of OpaqueDataTuples type options.
+    bool haveOpaqueDataTuplesFormat() const;
+
     /// @brief Option factory.
     ///
     /// This function creates an instance of DHCP option using

+ 19 - 0
src/lib/dhcp/std_option_defs.h

@@ -72,6 +72,13 @@ RECORD_DECL(FQDN_RECORDS, OPT_UINT8_TYPE, OPT_UINT8_TYPE, OPT_UINT8_TYPE,
 // Opaque data is represented here by the binary data field.
 RECORD_DECL(VIVCO_RECORDS, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
 
+// RFC4578 (PXE) record fields
+//
+// Three 1 byte fileds to describe a network interface: type, major and minor
+RECORD_DECL(CLIENT_NDI_RECORDS, OPT_UINT8_TYPE, OPT_UINT8_TYPE, OPT_UINT8_TYPE);
+// A client identifer: a 1 byte type field followed by opaque data depending on the type
+RECORD_DECL(UUID_GUID_RECORDS, OPT_UINT8_TYPE, OPT_BINARY_TYPE);
+
 /// @brief Definitions of standard DHCPv4 options.
 const OptionDefParams OPTION_DEF_PARAMS4[] = {
     { "subnet-mask", DHO_SUBNET_MASK, OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF, "" },
@@ -188,6 +195,9 @@ const OptionDefParams OPTION_DEF_PARAMS4[] = {
     { "client-last-transaction-time", DHO_CLIENT_LAST_TRANSACTION_TIME,
       OPT_UINT32_TYPE, false, NO_RECORD_DEF, "" },
     { "associated-ip", DHO_ASSOCIATED_IP, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
+    { "client-system", DHO_SYSTEM, OPT_UINT16_TYPE, true, NO_RECORD_DEF, "" },
+    { "client-ndi", DHO_NDI, OPT_RECORD_TYPE, false, RECORD_DEF(CLIENT_NDI_RECORDS), "" },
+    { "uuid-guid", DHO_UUID_GUID, OPT_RECORD_TYPE, false, RECORD_DEF(UUID_GUID_RECORDS), "" },
     { "subnet-selection", DHO_SUBNET_SELECTION,
       OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF, "" },
     // The following options need a special encoding of data
@@ -240,6 +250,11 @@ RECORD_DECL(VENDOR_CLASS_RECORDS, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
 RECORD_DECL(SIGNATURE_RECORDS, OPT_UINT8_TYPE, OPT_UINT8_TYPE,
             OPT_BINARY_TYPE);
 
+// RFC5970 (PXE) Class record fields
+//
+// Three 1 byte fileds to describe a network interface: type, major and minor
+RECORD_DECL(CLIENT_NII_RECORDS, OPT_UINT8_TYPE, OPT_UINT8_TYPE, OPT_UINT8_TYPE);
+
 /// Standard DHCPv6 option definitions.
 ///
 /// @warning in this array, the initializers are provided for all
@@ -329,6 +344,10 @@ const OptionDefParams OPTION_DEF_PARAMS6[] = {
       RECORD_DEF(LQ_RELAY_DATA_RECORDS), "" },
     { "lq-client-link", D6O_LQ_CLIENT_LINK, OPT_IPV6_ADDRESS_TYPE, true,
       NO_RECORD_DEF, "" },
+    { "bootfile-url", D6O_BOOTFILE_URL, OPT_STRING_TYPE, false, NO_RECORD_DEF, "" },
+    { "bootfile-param", D6O_BOOTFILE_PARAM, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
+    { "client-arch-type", D6O_CLIENT_ARCH_TYPE, OPT_UINT16_TYPE, true, NO_RECORD_DEF, "" },
+    { "nii", D6O_NII, OPT_RECORD_TYPE, false, RECORD_DEF(CLIENT_NII_RECORDS), "" },
     { "erp-local-domain-name", D6O_ERP_LOCAL_DOMAIN_NAME, OPT_FQDN_TYPE, false,
       NO_RECORD_DEF, "" },
     { "rsoo", D6O_RSOO, OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "rsoo-opts" },

+ 1 - 1
src/lib/dhcp/tests/Makefile.am

@@ -51,7 +51,6 @@ libdhcp___unittests_SOURCES += hwaddr_unittest.cc
 libdhcp___unittests_SOURCES += iface_mgr_unittest.cc
 libdhcp___unittests_SOURCES += iface_mgr_test_config.cc iface_mgr_test_config.h
 libdhcp___unittests_SOURCES += libdhcp++_unittest.cc
-libdhcp___unittests_SOURCES += opaque_data_tuple_unittest.cc
 libdhcp___unittests_SOURCES += option4_addrlst_unittest.cc
 libdhcp___unittests_SOURCES += option4_client_fqdn_unittest.cc
 libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc
@@ -65,6 +64,7 @@ libdhcp___unittests_SOURCES += option_int_array_unittest.cc
 libdhcp___unittests_SOURCES += option_data_types_unittest.cc
 libdhcp___unittests_SOURCES += option_definition_unittest.cc
 libdhcp___unittests_SOURCES += option_custom_unittest.cc
+libdhcp___unittests_SOURCES += option_opaque_data_tuples_unittest.cc
 libdhcp___unittests_SOURCES += option_unittest.cc
 libdhcp___unittests_SOURCES += option_space_unittest.cc
 libdhcp___unittests_SOURCES += option_string_unittest.cc

+ 30 - 0
src/lib/dhcp/tests/libdhcp++_unittest.cc

@@ -29,6 +29,7 @@
 #include <dhcp/option_custom.h>
 #include <dhcp/option_int.h>
 #include <dhcp/option_int_array.h>
+#include <dhcp/option_opaque_data_tuples.h>
 #include <dhcp/option_string.h>
 #include <dhcp/option_vendor.h>
 #include <dhcp/option_vendor_class.h>
@@ -941,6 +942,15 @@ TEST_F(LibDhcpTest, stdOptionDefs4) {
     LibDhcpTest::testStdOptionDefs4(DHO_SUBNET_SELECTION, begin, end,
                                     typeid(OptionCustom));
 
+    LibDhcpTest::testStdOptionDefs4(DHO_SYSTEM, begin, end,
+                                    typeid(OptionIntArray<uint16_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_NDI, begin, begin + 3,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_UUID_GUID, begin, begin + 17,
+                                    typeid(OptionCustom));
+
     LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_SEARCH, begin, end,
                                     typeid(Option));
 
@@ -1016,6 +1026,13 @@ TEST_F(LibDhcpTest, stdOptionDefs6) {
     std::vector<uint8_t> vclass_buf(vclass_data,
                                     vclass_data + sizeof(vclass_data));;
 
+    // Initialize test buffer for Bootfile Param option.
+    const char bparam_data[] = {
+        0x00, 0x01, 0x02
+    };
+    std::vector<uint8_t> bparam_buf(bparam_data,
+                                     bparam_data + sizeof(bparam_data));;
+
     // The actual test starts here for all supported option codes.
     LibDhcpTest::testStdOptionDefs6(D6O_CLIENTID, begin, end,
                                     typeid(Option));
@@ -1161,6 +1178,19 @@ TEST_F(LibDhcpTest, stdOptionDefs6) {
     LibDhcpTest::testStdOptionDefs6(D6O_LQ_CLIENT_LINK, begin, end,
                                     typeid(Option6AddrLst));
 
+    LibDhcpTest::testStdOptionDefs6(D6O_BOOTFILE_URL, begin, end,
+				    typeid(OptionString));
+
+    LibDhcpTest::testStdOptionDefs6(D6O_BOOTFILE_PARAM, bparam_buf.begin(),
+                                    bparam_buf.end(),
+				    typeid(OptionOpaqueDataTuples));
+
+    LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_ARCH_TYPE, begin, end,
+				    typeid(OptionIntArray<uint16_t>));
+
+    LibDhcpTest::testStdOptionDefs6(D6O_NII, begin, begin + 3,
+				    typeid(OptionCustom));
+
     LibDhcpTest::testStdOptionDefs6(D6O_RSOO, begin, end,
                                     typeid(OptionCustom),
                                     "rsoo-opts");

+ 2 - 2
src/lib/dhcpsrv/tests/cfg_option_def_unittest.cc

@@ -231,9 +231,9 @@ TEST(CfgOptionDefTest, overrideStdOptionDef) {
     def.reset(new OptionDefinition("sntp-servers", D6O_SNTP_SERVERS,
                                    "ipv4-address"));
     EXPECT_THROW(cfg.add(def, DHCP6_OPTION_SPACE), isc::BadValue);
-    // There is no definition for option 59 in libdhcp++ yet, so it should
+    // There is no definition for option 63 in libdhcp++ yet, so it should
     // be possible provide a custom definition.
-    def.reset(new OptionDefinition("bootfile-url", 59, "uint32"));
+    def.reset(new OptionDefinition("geolocation", 63, "uint32"));
     EXPECT_NO_THROW(cfg.add(def, DHCP6_OPTION_SPACE));
 }