Browse Source

[3145] Unit-tests for IA_PD, several clean-ups

Tomek Mrugalski 11 years ago
parent
commit
302a01c670
4 changed files with 149 additions and 58 deletions
  1. 4 0
      ChangeLog
  2. 15 1
      src/lib/dhcp/option6_ia.cc
  3. 1 1
      src/lib/dhcp/std_option_defs.h
  4. 129 56
      src/lib/dhcp/tests/option6_ia_unittest.cc

+ 4 - 0
ChangeLog

@@ -1,3 +1,7 @@
+6XX.	[func]		tomek
+	libdhcp: Added support for IA_PD and IAPREFIX options.
+	(Trac #3145, git ABCD)
+
 670.	[func]		marcin
 	libdhcpsrv: Added support to MySQL lease database backend to
 	store FQDN data for the lease.

+ 15 - 1
src/lib/dhcp/option6_ia.cc

@@ -30,10 +30,24 @@ namespace dhcp {
 
 Option6IA::Option6IA(uint16_t type, uint32_t iaid)
     :Option(Option::V6, type), iaid_(iaid), t1_(0), t2_(0) {
+
+    // IA_TA has different layout than IA_NA and IA_PD. We can't sue this class
+    if (type == D6O_IA_TA) {
+        isc_throw(BadValue, "Can't use Option6IA for IA_TA as it has "
+                  "a different layout");
+    }
 }
 
-Option6IA::Option6IA(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
+Option6IA::Option6IA(uint16_t type, OptionBufferConstIter begin,
+                     OptionBufferConstIter end)
     :Option(Option::V6, type) {
+
+    // IA_TA has different layout than IA_NA and IA_PD. We can't use this class
+    if (type == D6O_IA_TA) {
+        isc_throw(BadValue, "Can't use Option6IA for IA_TA as it has "
+                  "a different layout");
+    }
+
     unpack(begin, end);
 }
 

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

@@ -214,7 +214,7 @@ RECORD_DECL(IA_NA_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE, OPT_UINT32_TYPE);
 RECORD_DECL(IA_PD_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE, OPT_UINT32_TYPE);
 // ia-prefix
 RECORD_DECL(IA_PREFIX_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE,
-            OPT_UINT8_TYPE, OPT_BINARY_TYPE);
+            OPT_UINT8_TYPE, OPT_IPV6_ADDRESS_TYPE, OPT_BINARY_TYPE);
 // lq-query
 RECORD_DECL(LQ_QUERY_RECORDS, OPT_UINT8_TYPE, OPT_IPV6_ADDRESS_TYPE);
 // lq-relay-data

+ 129 - 56
src/lib/dhcp/tests/option6_ia_unittest.cc

@@ -18,6 +18,7 @@
 #include <dhcp/option.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_iaprefix.h>
 #include <util/buffer.h>
 
 #include <boost/scoped_ptr.hpp>
@@ -43,71 +44,96 @@ public:
             buf_[i] = 255 - i;
         }
     }
-    OptionBuffer buf_;
-    OutputBuffer outBuf_;
-};
 
-TEST_F(Option6IATest, basic) {
-    buf_[0] = 0xa1; // iaid
-    buf_[1] = 0xa2;
-    buf_[2] = 0xa3;
-    buf_[3] = 0xa4;
+    /// @brief performs basic checks on IA option
+    ///
+    /// Check that an option can be built based on incoming buffer and that
+    /// the option contains expected values.
+    /// @param type specifies option type (IA_NA or IA_PD)
+    void checkIA(uint16_t type) {
+        buf_[0] = 0xa1; // iaid
+        buf_[1] = 0xa2;
+        buf_[2] = 0xa3;
+        buf_[3] = 0xa4;
+
+        buf_[4] = 0x81; // T1
+        buf_[5] = 0x02;
+        buf_[6] = 0x03;
+        buf_[7] = 0x04;
+
+        buf_[8] = 0x84; // T2
+        buf_[9] = 0x03;
+        buf_[10] = 0x02;
+        buf_[11] = 0x01;
+
+        // Create an option
+        // unpack() is called from constructor
+        scoped_ptr<Option6IA> opt(new Option6IA(type,
+                                                buf_.begin(),
+                                                buf_.begin() + 12));
 
-    buf_[4] = 0x81; // T1
-    buf_[5] = 0x02;
-    buf_[6] = 0x03;
-    buf_[7] = 0x04;
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(type, opt->getType());
+        EXPECT_EQ(0xa1a2a3a4, opt->getIAID());
+        EXPECT_EQ(0x81020304, opt->getT1());
+        EXPECT_EQ(0x84030201, opt->getT2());
 
-    buf_[8] = 0x84; // T2
-    buf_[9] = 0x03;
-    buf_[10] = 0x02;
-    buf_[11] = 0x01;
+        // Pack this option again in the same buffer, but in
+        // different place
 
-    // Create an option
-    // unpack() is called from constructor
-    scoped_ptr<Option6IA> opt(new Option6IA(D6O_IA_NA,
-                                            buf_.begin(),
-                                            buf_.begin() + 12));
+        // Test for pack()
+        opt->pack(outBuf_);
 
-    EXPECT_EQ(Option::V6, opt->getUniverse());
-    EXPECT_EQ(D6O_IA_NA, opt->getType());
-    EXPECT_EQ(0xa1a2a3a4, opt->getIAID());
-    EXPECT_EQ(0x81020304, opt->getT1());
-    EXPECT_EQ(0x84030201, opt->getT2());
+        // 12 bytes header + 4 bytes content
+        EXPECT_EQ(12, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(type, opt->getType());
 
-    // Pack this option again in the same buffer, but in
-    // different place
+        EXPECT_EQ(16, outBuf_.getLength()); // lenght(IA_NA) = 16
 
-    // Test for pack()
-    opt->pack(outBuf_);
+        // Check if pack worked properly:
+        InputBuffer out(outBuf_.getData(), outBuf_.getLength());
 
-    // 12 bytes header + 4 bytes content
-    EXPECT_EQ(12, opt->len() - opt->getHeaderLen());
-    EXPECT_EQ(D6O_IA_NA, opt->getType());
+        // - if option type is correct
+        EXPECT_EQ(type, out.readUint16());
 
-    EXPECT_EQ(16, outBuf_.getLength()); // lenght(IA_NA) = 16
+        // - if option length is correct
+        EXPECT_EQ(12, out.readUint16());
 
-    // Check if pack worked properly:
-    InputBuffer out(outBuf_.getData(), outBuf_.getLength());
+        // - if iaid is correct
+        EXPECT_EQ(0xa1a2a3a4, out.readUint32() );
 
-    // - if option type is correct
-    EXPECT_EQ(D6O_IA_NA, out.readUint16());
+        // - if T1 is correct
+        EXPECT_EQ(0x81020304, out.readUint32() );
 
-    // - if option length is correct
-    EXPECT_EQ(12, out.readUint16());
+        // - if T1 is correct
+        EXPECT_EQ(0x84030201, out.readUint32() );
 
-    // - if iaid is correct
-    EXPECT_EQ(0xa1a2a3a4, out.readUint32() );
+        EXPECT_NO_THROW(opt.reset());
+    }
 
-   // - if T1 is correct
-    EXPECT_EQ(0x81020304, out.readUint32() );
+    OptionBuffer buf_;
+    OutputBuffer outBuf_;
+};
 
-    // - if T1 is correct
-    EXPECT_EQ(0x84030201, out.readUint32() );
+TEST_F(Option6IATest, basic) {
+    checkIA(D6O_IA_NA);
+}
 
-    EXPECT_NO_THROW(opt.reset());
+TEST_F(Option6IATest, pdBasic) {
+    checkIA(D6O_IA_PD);
 }
 
+// Check that this class cannot be used for IA_TA (IA_TA has no T1, T2 fields
+// and people tend to think that if it's good for IA_NA and IA_PD, it can
+// be used for IA_TA as well and that is not true)
+TEST_F(Option6IATest, taForbidden) {
+    EXPECT_THROW(Option6IA(D6O_IA_TA, buf_.begin(), buf_.begin() + 50),
+                 BadValue);
+
+    EXPECT_THROW(Option6IA(D6O_IA_TA, 123), BadValue);
+}
+
+// Check that getters/setters are working as expected.
 TEST_F(Option6IATest, simple) {
     scoped_ptr<Option6IA> ia(new Option6IA(D6O_IA_NA, 1234));
 
@@ -131,12 +157,8 @@ TEST_F(Option6IATest, simple) {
     EXPECT_NO_THROW(ia.reset());
 }
 
-
-// test if option can build suboptions
-TEST_F(Option6IATest, suboptions_pack) {
-    buf_[0] = 0xff;
-    buf_[1] = 0xfe;
-    buf_[2] = 0xfc;
+// test if the option can build suboptions
+TEST_F(Option6IATest, suboptionsPack) {
 
     scoped_ptr<Option6IA> ia(new Option6IA(D6O_IA_NA, 0x13579ace));
     ia->setT1(0x2345);
@@ -154,6 +176,7 @@ TEST_F(Option6IATest, suboptions_pack) {
     ASSERT_EQ(4, sub1->len());
     ASSERT_EQ(48, ia->len());
 
+    // This contains expected on-wire format
     uint8_t expected[] = {
         D6O_IA_NA/256, D6O_IA_NA%256, // type
         0, 44, // length
@@ -175,18 +198,68 @@ TEST_F(Option6IATest, suboptions_pack) {
     };
 
     ia->pack(outBuf_);
-    ASSERT_EQ(48, outBuf_.getLength());
 
+    ASSERT_EQ(48, outBuf_.getLength());
     EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 48));
-
     EXPECT_NO_THROW(ia.reset());
 }
 
+// test if IA_PD option can build IAPREFIX suboptions
+TEST_F(Option6IATest, pdSuboptionsPack) {
+
+    // Let's build IA_PD
+    scoped_ptr<Option6IA> ia(new Option6IA(D6O_IA_PD, 0x13579ace));
+    ia->setT1(0x2345);
+    ia->setT2(0x3456);
+
+    // Put some dummy option in it
+    OptionPtr sub1(new Option(Option::V6, 0xcafe));
+
+    // Put a valid IAPREFIX option in it
+    boost::shared_ptr<Option6IAPrefix> addr1(
+        new Option6IAPrefix(D6O_IAPREFIX, IOAddress("2001:db8:1234:5678::abcd"),
+                            91, 0x5000, 0x7000));
+
+    ia->addOption(sub1);
+    ia->addOption(addr1);
+
+    ASSERT_EQ(29, addr1->len());
+    ASSERT_EQ(4, sub1->len());
+    ASSERT_EQ(49, ia->len());
+
+    uint8_t expected[] = {
+        D6O_IA_PD/256, D6O_IA_PD%256, // type
+        0, 45, // length
+        0x13, 0x57, 0x9a, 0xce, // iaid
+        0, 0, 0x23, 0x45,  // T1
+        0, 0, 0x34, 0x56,  // T2
+
+        // iaprefix suboption
+        D6O_IAPREFIX/256, D6O_IAPREFIX%256, // type
+        0, 25, // len
+        0, 0, 0x50, 0, // preferred-lifetime
+        0, 0, 0x70, 0, // valid-lifetime
+        91, // prefix length
+        0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
+        0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
+
+        // suboption
+        0xca, 0xfe, // type
+        0, 0 // len
+    };
+
+    ia->pack(outBuf_);
+    ASSERT_EQ(49, outBuf_.getLength());
+
+    EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 49));
+
+    EXPECT_NO_THROW(ia.reset());
+}
 
 // test if option can parse suboptions
 TEST_F(Option6IATest, suboptions_unpack) {
     // sizeof (expected) = 48 bytes
-    uint8_t expected[] = {
+    const uint8_t expected[] = {
         D6O_IA_NA / 256, D6O_IA_NA % 256, // type
         0, 28, // length
         0x13, 0x57, 0x9a, 0xce, // iaid