Parcourir la source

[5227] Added slp-service-scope (79) support (optional field similar to status-code)

Francis Dupont il y a 7 ans
Parent
commit
15b7184a74

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

@@ -1285,6 +1285,7 @@ This rather belong to the DDNS configuration
 <row><entry>streettalk-server</entry><entry>75</entry><entry>ipv4-address</entry><entry>true</entry><entry>false</entry></row>
 <row><entry>streettalk-directory-assistance-server</entry><entry>76</entry><entry>ipv4-address</entry><entry>true</entry><entry>false</entry></row>
 <row><entry>user-class</entry><entry>77</entry><entry>binary</entry><entry>false</entry><entry>false</entry></row>
+<row><entry>slp-service-scope</entry><entry>79</entry><entry>record (boolean, string)</entry><entry>false</entry><entry>false</entry></row>
 <!-- The Client FQDN option value is not explicitly configured.
 It is a part of the DDNS/D2 configuration
 <row><entry>fqdn</entry><entry>81</entry><entry>record</entry><entry>false</entry><entry>true</entry></row>

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

@@ -145,7 +145,7 @@ enum DHCPOptionType {
     DHO_STDASERVER                   = 76,
     DHO_USER_CLASS                   = 77,
 //  DHO_DIRECTORY_AGENT              = 78,
-//  DHO_SERVICE_SCOPE                = 79,
+    DHO_SERVICE_SCOPE                = 79,
 //  DHO_RAPID_COMMIT                 = 80,
     DHO_FQDN                         = 81,
     DHO_DHCP_AGENT_OPTIONS           = 82,

+ 80 - 1
src/lib/dhcp/option6_status_code.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -6,8 +6,10 @@
 
 #include <config.h>
 
+#include <dhcp/dhcp4.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/option6_status_code.h>
+#include <dhcp/option_data_types.h>
 #include <util/io_utilities.h>
 #include <iterator>
 #include <sstream>
@@ -19,6 +21,7 @@ namespace {
 
 /// @brief Minimum length of the option (when status message is empty).
 const size_t OPTION6_STATUS_CODE_MIN_LEN = sizeof(uint16_t);
+const size_t OPTION4_SLP_SERVICE_SCOPEMIN_LEN = sizeof(bool);
 
 }; // end of anonymous namespace
 
@@ -135,5 +138,81 @@ Option6StatusCode::getStatusCodeName() const {
     return ("(unknown status code)");
 }
 
+Option4SlpServiceScope::Option4SlpServiceScope(const bool mandatory_flag,
+                                               const std::string& scope_list)
+    : Option(Option::V4, DHO_SERVICE_SCOPE),
+      mandatory_flag_(mandatory_flag), scope_list_(scope_list) {
+}
+
+Option4SlpServiceScope::Option4SlpServiceScope(OptionBufferConstIter begin,
+                                               OptionBufferConstIter end)
+    : Option(Option::V4, DHO_SERVICE_SCOPE),
+      mandatory_flag_(false), scope_list_() {
+
+    // Parse data 
+    unpack(begin, end);
+}
+
+OptionPtr
+Option4SlpServiceScope::clone() const {
+    return (cloneInternal<Option4SlpServiceScope>());
+}
+
+void
+Option4SlpServiceScope::pack(isc::util::OutputBuffer& buf) const {
+    // Pack option header.
+    packHeader(buf);
+    // Write mandatory flag.
+    buf.writeUint8(static_cast<uint8_t>(getMandatoryFlag() ? 1 : 0));
+    // If there is any scope list, write it.
+    if (!scope_list_.empty()) {
+        buf.writeData(&scope_list_[0], scope_list_.size());
+    }
+
+    // SLP service scope has no options, so leave here.
+}
+
+void
+Option4SlpServiceScope::unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
+    // Make sure that the option is not truncated.
+    if (std::distance(begin, end) < OPTION4_SLP_SERVICE_SCOPEMIN_LEN) {
+        isc_throw(OutOfRange, "SLP Service Scope option ("
+                  << DHO_SERVICE_SCOPE << ") truncated");
+    }
+
+    if (*begin == 1) {
+        mandatory_flag_ = true;
+    } else if (*begin == 0) {
+        mandatory_flag_ = false;
+    } else {
+        isc_throw(BadDataTypeCast, "unable to read the buffer as boolean"
+                  << " value. Invalid value " << static_cast<int>(*begin));
+    }
+    begin += sizeof(bool);
+
+    scope_list_.assign(begin, end);
+}
+
+uint16_t
+Option4SlpServiceScope::len() const {
+    return (getHeaderLen() + sizeof(bool) + scope_list_.size());
+}
+
+std::string
+Option4SlpServiceScope::toText(int indent) const {
+    std::ostringstream output;
+    output << headerToText(indent) << ": " << dataToText();
+
+    return (output.str());
+}
+
+std::string
+Option4SlpServiceScope::dataToText() const {
+    std::ostringstream output;
+    output << "mandatory:" << getMandatoryFlag();
+    output << ", scope-list:\"" << scope_list_ << "\"";
+    return (output.str());
+}
+
 } // end of namespace isc::dhcp
 } // end of namespace isc

+ 92 - 1
src/lib/dhcp/option6_status_code.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -107,6 +107,97 @@ private:
 
 };
 
+/// The SLP Service Scope option has a similar layout...
+
+class Option4SlpServiceScope;
+
+/// @brief Pointer to the @c isc::dhcp::Option4SlpServiceScope.
+typedef boost::shared_ptr<Option4SlpServiceScope> Option4SlpServiceScopePtr;
+
+/// @brief This class represents SLP Service Scope option (79) from RFC2610.
+class Option4SlpServiceScope: public Option {
+public:
+    /// @brief Constructor, used for options constructed (during transmission).
+    ///
+    /// @param mandatory_flag Mandatory flag.
+    /// @param scope_list Textual scope list, may be empty
+    Option4SlpServiceScope(const bool mandatory_flag, const std::string& scope_list);
+
+    /// @brief Constructor, used for received options.
+    ///
+    /// @throw OutOfRange if specified option is truncated
+    ///
+    /// @param begin Iterator to first byte of option data
+    /// @param end Iterator to end of option data (first byte after option end).
+    Option4SlpServiceScope(OptionBufferConstIter begin, OptionBufferConstIter end);
+
+    /// @brief Copies this option and returns a pointer to the copy.
+    virtual OptionPtr clone() const;
+
+    /// @brief Writes option in wire-format.
+    ///
+    /// Writes option in wire-format to buf, returns pointer to first unused
+    /// byte after stored option.
+    ///
+    /// @param [out] buf Pointer to the output buffer.
+    virtual void pack(isc::util::OutputBuffer& buf) const;
+
+    /// @brief Parses received buffer.
+    ///
+    /// @param begin Iterator to first byte of option data
+    /// @param end Iterator to end of option data (first byte after option end)
+    virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end);
+
+    /// @brief Returns total length of the option.
+    ///
+    /// The returned length is a sum of the option header and data fields.
+    virtual uint16_t len() const;
+
+    /// @brief Returns textual representation of the option.
+    ///
+    /// @param indent Number of spaces before printing text.
+    virtual std::string toText(int indent = 0) const;
+
+    /// @brief Returns textual representation of the option data.
+    ///
+    /// This method returns only the status code and the status
+    /// message. It excludes the option header.
+    std::string dataToText() const;
+
+    /// @brief Returns mandatory flag
+    bool getMandatoryFlag() const {
+        return (mandatory_flag_);        
+    }
+
+    /// @brief Sets new mandatory flag.
+    ///
+    /// @param status_code New numeric status code.
+    void setMandatoryFlag(const bool mandatory_flag) {
+        mandatory_flag_ = mandatory_flag;
+    }
+
+    /// @brief Returns scope list.
+    const std::string& getScopeList() const {
+        return (scope_list_);
+    }
+
+    /// @brief Sets new scope list.
+    ///
+    /// @param scope_list New scope list (empty string is allowed).
+    void setScopeList(std::string& scope_list) {
+        scope_list_ = scope_list;
+    }
+
+private:
+
+    /// @brief Mandatory flag.
+    bool mandatory_flag_;
+
+    /// @brief Scope list.
+    std::string scope_list_;
+
+};
+
 } // isc::dhcp namespace
 } // isc namespace
 

+ 11 - 1
src/lib/dhcp/option_definition.cc

@@ -442,6 +442,14 @@ OptionDefinition::haveStatusCodeFormat() const {
 }
 
 bool
+OptionDefinition::haveServiceScopeFormat() const {
+    return (haveType(OPT_RECORD_TYPE) &&
+            (record_fields_.size() == 2) &&
+            (record_fields_[0] == OPT_BOOLEAN_TYPE) &&
+            (record_fields_[1] == OPT_STRING_TYPE));
+}
+
+bool
 OptionDefinition::haveOpaqueDataTuplesFormat() const {
     return (haveType(OPT_TUPLE_TYPE) && getArrayType());
 }
@@ -856,7 +864,9 @@ OptionDefinition::factorySpecialFormatOption(Option::Universe u,
             return (OptionPtr(new Option6PDExclude(begin, end)));
         }
     } else {
-        if ((getCode() == DHO_FQDN) && haveFqdn4Format()) {
+        if ((getCode() == DHO_SERVICE_SCOPE) && haveServiceScopeFormat()) {
+            return (OptionPtr(new Option4SlpServiceScope(begin, end)));
+        } else if ((getCode() == DHO_FQDN) && haveFqdn4Format()) {
             return (OptionPtr(new Option4ClientFqdn(begin, end)));
         } else if (haveCompressedFqdnListFormat()) {
             return (factoryFqdnList(Option::V4, begin, end));

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

@@ -364,6 +364,15 @@ public:
     /// @return true if option has the format of DHCPv6 Vendor Class option.
     bool haveVendorClass6Format() const;
 
+    /// @brief Check if option has format of the SLP Service Scope
+    /// %Option.
+    ///
+    /// The scope list in the SLP Service Scope option is optional
+    /// (i.e., as the error message in the DHCPv6 Status code option).
+    ///
+    /// @return true if option has the format of SLP Service Scope %Option.
+    bool haveServiceScopeFormat() const;
+
     /// @brief Check if the option has format of DHCPv6 Status Code option.
     ///
     /// @return true if option has the format of DHCPv6 Status code option.

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

@@ -37,6 +37,11 @@ namespace {
 #define NO_RECORD_DEF 0, 0
 #endif
 
+// SLP Service Scope option.
+//
+// The scope list is optional.
+RECORD_DECL(SERVICE_SCOPE_RECORDS, OPT_BOOLEAN_TYPE, OPT_STRING_TYPE);
+
 // fqdn option record fields.
 //
 // Note that the flags field indicates the type of domain
@@ -179,6 +184,8 @@ const OptionDefParams STANDARD_V4_OPTION_DEFINITIONS[] = {
     { "streettalk-server", DHO_STREETTALK_SERVER, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "streettalk-directory-assistance-server", DHO_STDASERVER, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
     { "user-class", DHO_USER_CLASS, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
+    { "slp-service-scope", DHO_SERVICE_SCOPE, OPT_RECORD_TYPE, false,
+      RECORD_DEF(SERVICE_SCOPE_RECORDS), "" },
     { "fqdn", DHO_FQDN, OPT_RECORD_TYPE, false, RECORD_DEF(FQDN_RECORDS), "" },
     { "dhcp-agent-options", DHO_DHCP_AGENT_OPTIONS,
       OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "dhcp-agent-options-space" },

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

@@ -1285,6 +1285,13 @@ TEST_F(LibDhcpTest, stdOptionDefs4) {
     LibDhcpTest::testStdOptionDefs4(DHO_USER_CLASS, begin, end,
                                     typeid(Option));
 
+    LibDhcpTest::testStdOptionDefs4(DHO_SERVICE_SCOPE, begin, end,
+                                    typeid(Option4SlpServiceScope));
+
+    // Check also with empty scope list
+    LibDhcpTest::testStdOptionDefs4(DHO_SERVICE_SCOPE, begin, begin + 1,
+                                    typeid(Option4SlpServiceScope));
+
     LibDhcpTest::testStdOptionDefs4(DHO_FQDN, begin, begin + 3,
                                     typeid(Option4ClientFqdn));