Browse Source

[2417] Added changes suggested in the code review.

Marcin Siodelski 12 years ago
parent
commit
5017e9a8d6

+ 20 - 5
src/bin/dhcp6/config_parser.cc

@@ -617,7 +617,11 @@ private:
                       << " spaces");
                       << " spaces");
         }
         }
 
 
+        // Get option data from the configuration database ('data' field).
+        // Option data is specified by the user as case insensitive string
+        // of hexadecimal digits for each option.
         std::string option_data = getStringParam("data");
         std::string option_data = getStringParam("data");
+        // Transform string of hexadecimal digits into binary format.
         std::vector<uint8_t> binary;
         std::vector<uint8_t> binary;
         try {
         try {
             util::encode::decodeHex(option_data, binary);
             util::encode::decodeHex(option_data, binary);
@@ -625,29 +629,40 @@ private:
             isc_throw(Dhcp6ConfigError, "Parser error: option data is not a valid"
             isc_throw(Dhcp6ConfigError, "Parser error: option data is not a valid"
                       << " string of hexadecimal digits: " << option_data);
                       << " string of hexadecimal digits: " << option_data);
         }
         }
-
+        // Get all existing DHCPv6 option definitions. The one that matches
+        // our option will be picked and used to create it.
         OptionDefContainer option_defs = LibDHCP::getOptionDefs(Option::V6);
         OptionDefContainer option_defs = LibDHCP::getOptionDefs(Option::V6);
+        // Get search index #1. It allows searching for options definitions
+        // using option type value.
         const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
         const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
-
+        // Get all option definitions matching option code we want to create.
         const OptionDefContainerTypeRange& range = idx.equal_range(option_code);
         const OptionDefContainerTypeRange& range = idx.equal_range(option_code);
         size_t num_defs = std::distance(range.first, range.second);
         size_t num_defs = std::distance(range.first, range.second);
         OptionPtr option;
         OptionPtr option;
+        // Currently we do not allow duplicated definitions and if there are
+        // any duplicates we issue internal server error.
         if (num_defs > 1) {
         if (num_defs > 1) {
             isc_throw(Dhcp6ConfigError, "Internal error: currently it is not"
             isc_throw(Dhcp6ConfigError, "Internal error: currently it is not"
                       << " supported to initialize multiple option definitions"
                       << " supported to initialize multiple option definitions"
                       << " for the same option code. This will be supported once"
                       << " for the same option code. This will be supported once"
                       << " there option spaces are implemented.");
                       << " there option spaces are implemented.");
         } else if (num_defs == 0) {
         } else if (num_defs == 0) {
-            // Create the actual option.
+            // @todo We have a limited set of option definitions intiialized at the moment.
+            // In the future we want to initialize option definitions for all options.
+            // Consequently error will be issued if option definition does not exist
+            // for a particular option code. For now it is ok to create generic option
+            // if definition does not exist.
             OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code),
             OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code),
                                         binary));
                                         binary));
             // If option is created succesfully, add it to the storage.
             // If option is created succesfully, add it to the storage.
             options_->push_back(option);
             options_->push_back(option);
         } else {
         } else {
+            // We have exactly one option definition for the particular option code.
+            // use it to create option instance.
             const OptionDefinitionPtr& def = *(range.first);
             const OptionDefinitionPtr& def = *(range.first);
-            // getFactory should never return NULL pointer so we skip
+            // getFactory should never return NULL pointer.
-            // sanity check here.
             Option::Factory* factory = def->getFactory();
             Option::Factory* factory = def->getFactory();
+            assert(factory != NULL);
             try {
             try {
                 OptionPtr option = factory(Option::V6, option_code, binary);
                 OptionPtr option = factory(Option::V6, option_code, binary);
                 options_->push_back(option);
                 options_->push_back(option);

+ 9 - 3
src/bin/dhcp6/dhcp6_messages.mes

@@ -110,9 +110,15 @@ This is a debug message issued during the IPv6 DHCP server startup.
 It lists some information about the parameters with which the server
 It lists some information about the parameters with which the server
 is running.
 is running.
 
 
-% DHCP6_NO_SUBNET_FOR_ADDRESS fail to find subnet for address: %1
+% DHCP6_NO_SUBNET_DEF_OPT failed to find subnet for address %1 when adding default options
-This warning message indicates that server does not support subnet
+This warning message indicates that when attempting to add default options to a response,
-that received DHCPv6 packet comes from.
+the server found that it was not configured to support the subnet from which the DHCPv6
+request was received.  The packet has been ignored.
+
+% DHCP6_NO_SUBNET_REQ_OPT failed to find subnet for address %1 when adding requested options
+This warning message indicates that when attempting to add requested options to a response,
+the server found that it was not configured to support the subnet from which the DHCPv6
+request was received.  The packet has been ignored.
 
 
 % DHCP6_CONFIG_LOAD_FAIL failed to load configuration: %1
 % DHCP6_CONFIG_LOAD_FAIL failed to load configuration: %1
 This critical error message indicates that the initial DHCPv6
 This critical error message indicates that the initial DHCPv6

+ 2 - 2
src/bin/dhcp6/dhcp6_srv.cc

@@ -303,7 +303,7 @@ void Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
     Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
     Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
     // Warn if subnet is not supported and quit.
     // Warn if subnet is not supported and quit.
     if (!subnet) {
     if (!subnet) {
-        LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_FOR_ADDRESS)
+        LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_DEF_OPT)
             .arg(question->getRemoteAddr().toText());
             .arg(question->getRemoteAddr().toText());
         return;
         return;
     }
     }
@@ -325,7 +325,7 @@ void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer)
     // Get the subnet for a particular address.
     // Get the subnet for a particular address.
     Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
     Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
     if (!subnet) {
     if (!subnet) {
-        LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_FOR_ADDRESS)
+        LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_REQ_OPT)
             .arg(question->getRemoteAddr().toText());
             .arg(question->getRemoteAddr().toText());
         return;
         return;
     }
     }

+ 14 - 14
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -76,7 +76,7 @@ TEST_F(Dhcpv6SrvTest, basic) {
     // fe80::1234 link-local address on eth0 interface. Obviously
     // fe80::1234 link-local address on eth0 interface. Obviously
     // an attempt to bind this socket will fail.
     // an attempt to bind this socket will fail.
     Dhcpv6Srv* srv = NULL;
     Dhcpv6Srv* srv = NULL;
-    ASSERT_NO_THROW( {
+    ASSERT_NO_THROW({
         // open an unpriviledged port
         // open an unpriviledged port
         srv = new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000);
         srv = new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000);
     });
     });
@@ -88,7 +88,7 @@ TEST_F(Dhcpv6SrvTest, DUID) {
     // tests that DUID is generated properly
     // tests that DUID is generated properly
 
 
     boost::scoped_ptr<Dhcpv6Srv> srv;
     boost::scoped_ptr<Dhcpv6Srv> srv;
-    ASSERT_NO_THROW( {
+    ASSERT_NO_THROW({
         srv.reset(new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000));
         srv.reset(new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000));
     });
     });
 
 
@@ -186,7 +186,7 @@ TEST_F(Dhcpv6SrvTest, solicitBasic) {
     ElementPtr json = Element::fromJSON(config);
     ElementPtr json = Element::fromJSON(config);
 
 
     boost::scoped_ptr<NakedDhcpv6Srv> srv;
     boost::scoped_ptr<NakedDhcpv6Srv> srv;
-    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv()) );
+    ASSERT_NO_THROW(srv.reset(new NakedDhcpv6Srv()));
 
 
     EXPECT_NO_THROW(x = configureDhcp6Server(*srv, json));
     EXPECT_NO_THROW(x = configureDhcp6Server(*srv, json));
     ASSERT_TRUE(x);
     ASSERT_TRUE(x);
@@ -233,8 +233,8 @@ TEST_F(Dhcpv6SrvTest, solicitBasic) {
     // check if we get response at all
     // check if we get response at all
     ASSERT_TRUE(reply);
     ASSERT_TRUE(reply);
 
 
-    EXPECT_EQ( DHCPV6_ADVERTISE, reply->getType() );
+    EXPECT_EQ(DHCPV6_ADVERTISE, reply->getType());
-    EXPECT_EQ( 1234, reply->getTransid() );
+    EXPECT_EQ(1234, reply->getTransid());
 
 
     // We have not requested option with code 1000 so it should not
     // We have not requested option with code 1000 so it should not
     // be included in the response.
     // be included in the response.
@@ -258,28 +258,28 @@ TEST_F(Dhcpv6SrvTest, solicitBasic) {
     EXPECT_EQ(DHCPV6_ADVERTISE, reply->getType());
     EXPECT_EQ(DHCPV6_ADVERTISE, reply->getType());
 
 
     OptionPtr tmp = reply->getOption(D6O_IA_NA);
     OptionPtr tmp = reply->getOption(D6O_IA_NA);
-    ASSERT_TRUE( tmp );
+    ASSERT_TRUE(tmp);
 
 
     boost::shared_ptr<Option6IA> reply_ia =
     boost::shared_ptr<Option6IA> reply_ia =
         boost::dynamic_pointer_cast<Option6IA>(tmp);
         boost::dynamic_pointer_cast<Option6IA>(tmp);
     ASSERT_TRUE(reply_ia);
     ASSERT_TRUE(reply_ia);
-    EXPECT_EQ( 234, reply_ia->getIAID() );
+    EXPECT_EQ(234, reply_ia->getIAID());
 
 
     // check that there's an address included
     // check that there's an address included
-    EXPECT_TRUE( reply_ia->getOption(D6O_IAADDR));
+    EXPECT_TRUE(reply_ia->getOption(D6O_IAADDR));
 
 
     // check that server included our own client-id
     // check that server included our own client-id
     tmp = reply->getOption(D6O_CLIENTID);
     tmp = reply->getOption(D6O_CLIENTID);
-    ASSERT_TRUE( tmp );
+    ASSERT_TRUE(tmp);
-    EXPECT_EQ(clientid->getType(), tmp->getType() );
+    EXPECT_EQ(clientid->getType(), tmp->getType());
-    ASSERT_EQ(clientid->len(), tmp->len() );
+    ASSERT_EQ(clientid->len(), tmp->len());
 
 
-    EXPECT_TRUE( clientid->getData() == tmp->getData() );
+    EXPECT_TRUE(clientid->getData() == tmp->getData());
 
 
     // check that server included its server-id
     // check that server included its server-id
     tmp = reply->getOption(D6O_SERVERID);
     tmp = reply->getOption(D6O_SERVERID);
-    EXPECT_EQ(tmp->getType(), srv->getServerID()->getType() );
+    EXPECT_EQ(tmp->getType(), srv->getServerID()->getType());
-    ASSERT_EQ(tmp->len(),  srv->getServerID()->len() );
+    ASSERT_EQ(tmp->len(),  srv->getServerID()->len());
 
 
     EXPECT_TRUE(tmp->getData() == srv->getServerID()->getData());
     EXPECT_TRUE(tmp->getData() == srv->getServerID()->getData());
  
  

+ 4 - 1
src/lib/dhcp/libdhcp++.cc

@@ -287,8 +287,11 @@ LibDHCP::initStdOptionDefs6() {
         case D6O_STATUS_CODE:
         case D6O_STATUS_CODE:
             definition->addRecordField(OptionDefinition::UINT16_TYPE);
             definition->addRecordField(OptionDefinition::UINT16_TYPE);
             definition->addRecordField(OptionDefinition::STRING_TYPE);
             definition->addRecordField(OptionDefinition::STRING_TYPE);
-        default:
             break;
             break;
+        default:
+            // The default case is intentionally left empty
+            // as it does not need any processing.
+            ;
         }
         }
         try {
         try {
             definition->validate();
             definition->validate();

+ 7 - 2
src/lib/dhcp/option_definition.h

@@ -413,10 +413,13 @@ private:
 ///
 ///
 /// This container allows to search for DHCP option definition
 /// This container allows to search for DHCP option definition
 /// using two indexes:
 /// using two indexes:
-/// - sequenced: used to access elements in the oreder they have
+/// - sequenced: used to access elements in the order they have
 /// been added to the container
 /// been added to the container
 /// - option code: used to search defintions of options
 /// - option code: used to search defintions of options
 /// with a specified option code (aka option type).
 /// with a specified option code (aka option type).
+/// Note that this container can hold multiple options with the
+/// same code. For this reason, the latter index can be used to
+/// obtain a <b>range of options for a particular option code.
 /// 
 /// 
 /// @todo: need an index to search options using option space name
 /// @todo: need an index to search options using option space name
 /// once option spaces are implemented.
 /// once option spaces are implemented.
@@ -433,7 +436,9 @@ typedef boost::multi_index_container<
             // Use option type as the index key. The type is held
             // Use option type as the index key. The type is held
             // in OptionDefinition object so we have to call
             // in OptionDefinition object so we have to call
             // OptionDefinition::getCode to retrieve this key
             // OptionDefinition::getCode to retrieve this key
-            // for each element.
+            // for each element. The option code is non-unique so
+            // multiple elements with the same option code can
+            // be returned by this index.
             boost::multi_index::const_mem_fun<
             boost::multi_index::const_mem_fun<
                 OptionDefinition,
                 OptionDefinition,
                 uint16_t,
                 uint16_t,

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

@@ -64,19 +64,42 @@ public:
     static void testInitOptionDefs6(const uint16_t code,
     static void testInitOptionDefs6(const uint16_t code,
                              const OptionBuffer& buf,
                              const OptionBuffer& buf,
                              const std::type_info& expected_type) {
                              const std::type_info& expected_type) {
+        // Initialize stdandard options definitions. They are held
+        // in the static container throughout the program.
         LibDHCP::initStdOptionDefs(Option::V6);
         LibDHCP::initStdOptionDefs(Option::V6);
+        // Get all option definitions, we will use them to extract
+        // the definition for a particular option code.
         OptionDefContainer options = LibDHCP::getOptionDefs(Option::V6);
         OptionDefContainer options = LibDHCP::getOptionDefs(Option::V6);
+        // Get the container index #1. This one allows for searching
+        // option definitions using option code.
         const OptionDefContainerTypeIndex& idx = options.get<1>();
         const OptionDefContainerTypeIndex& idx = options.get<1>();
+        // Get 'all' option definitions for a particular option code.
+        // For standard options we expect that the range returned
+        // will contain single option as their codes are unique.
         OptionDefContainerTypeRange range = idx.equal_range(code);
         OptionDefContainerTypeRange range = idx.equal_range(code);
         ASSERT_EQ(1, std::distance(range.first, range.second));
         ASSERT_EQ(1, std::distance(range.first, range.second));
+        // If we have single option definition returned, the
+        // first iterator holds it.
         OptionDefinitionPtr def = *(range.first);
         OptionDefinitionPtr def = *(range.first);
+        // It should not happen that option definition is NULL but
+        // let's make sure (test should take things like that into
+        // account).
         ASSERT_TRUE(def);
         ASSERT_TRUE(def);
+        // Check that option definition is valid.
         ASSERT_NO_THROW(def->validate());
         ASSERT_NO_THROW(def->validate());
+        // Get the factory function for the particular option
+        // definition. We will use this factory function to
+        // create option instance.
         Option::Factory* factory = NULL;
         Option::Factory* factory = NULL;
         ASSERT_NO_THROW(factory = def->getFactory());
         ASSERT_NO_THROW(factory = def->getFactory());
         OptionPtr option;
         OptionPtr option;
+        // Create the option.
         ASSERT_NO_THROW(option = factory(Option::V6, code, buf));
         ASSERT_NO_THROW(option = factory(Option::V6, code, buf));
+        // Make sure it is not NULL.
         ASSERT_TRUE(option);
         ASSERT_TRUE(option);
+        // And the actual object type is the one that we expect.
+        // Note that for many options there are dedicated classes
+        // derived from Option class to represent them.
         EXPECT_TRUE(typeid(*option) == expected_type);
         EXPECT_TRUE(typeid(*option) == expected_type);
     }
     }
 };
 };

+ 13 - 0
src/lib/dhcp/tests/option_definition_unittest.cc

@@ -282,25 +282,38 @@ TEST_F(OptionDefinitionTest, factoryEmpty) {
 }
 }
 
 
 TEST_F(OptionDefinitionTest, factoryBinary) {
 TEST_F(OptionDefinitionTest, factoryBinary) {
+    // Binary option is the one that is represented by the generic
+    // Option class. In fact all options can be represented by this
+    // class but for some of them it is just natural. The SERVERID
+    // option consists of the option code, length and binary data so
+    // this one was picked for this test.
     OptionDefinition opt_def("OPTION_SERVERID", D6O_SERVERID, "binary");
     OptionDefinition opt_def("OPTION_SERVERID", D6O_SERVERID, "binary");
     Option::Factory* factory(NULL);
     Option::Factory* factory(NULL);
     EXPECT_NO_THROW(factory = opt_def.getFactory());
     EXPECT_NO_THROW(factory = opt_def.getFactory());
     ASSERT_TRUE(factory != NULL);
     ASSERT_TRUE(factory != NULL);
 
 
+    // Prepare some dummy data (serverid): 0, 1, 2 etc.
     OptionBuffer buf(14);
     OptionBuffer buf(14);
     for (int i = 0; i < 14; ++i) {
     for (int i = 0; i < 14; ++i) {
         buf[i] = i;
         buf[i] = i;
     }
     }
+    // Create option instance with the factory function.
+    // If the OptionDefinition code works properly than
+    // object of the type Option should be returned.
     OptionPtr option_v6;
     OptionPtr option_v6;
     ASSERT_NO_THROW(
     ASSERT_NO_THROW(
         option_v6 = factory(Option::V6, D6O_SERVERID, buf);
         option_v6 = factory(Option::V6, D6O_SERVERID, buf);
     );
     );
     // Expect base option type returned.
     // Expect base option type returned.
     ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
     ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
+    // Sanity check on universe, length and size. These are
+    // the basic parameters identifying any option.
     EXPECT_EQ(Option::V6, option_v6->getUniverse());
     EXPECT_EQ(Option::V6, option_v6->getUniverse());
     EXPECT_EQ(4, option_v6->getHeaderLen());
     EXPECT_EQ(4, option_v6->getHeaderLen());
     ASSERT_EQ(buf.size(), option_v6->getData().size());
     ASSERT_EQ(buf.size(), option_v6->getData().size());
 
 
+    // Get the server id data from the option and compare
+    // against reference buffer. They are expected to match.
     EXPECT_TRUE(std::equal(option_v6->getData().begin(),
     EXPECT_TRUE(std::equal(option_v6->getData().begin(),
                            option_v6->getData().end(),
                            option_v6->getData().end(),
                            buf.begin()));
                            buf.begin()));