Browse Source

[3807] Implemented Pkt6::getLabel and Pkt6::getClientId.

Marcin Siodelski 10 years ago
parent
commit
fe8f693b28
5 changed files with 155 additions and 35 deletions
  1. 1 15
      src/bin/dhcp6/dhcp6_srv.cc
  2. 0 6
      src/bin/dhcp6/dhcp6_srv.h
  3. 36 0
      src/lib/dhcp/pkt6.cc
  4. 34 0
      src/lib/dhcp/pkt6.h
  5. 84 14
      src/lib/dhcp/tests/pkt6_unittest.cc

+ 1 - 15
src/bin/dhcp6/dhcp6_srv.cc

@@ -224,25 +224,11 @@ Dhcpv6Srv::testUnicast(const Pkt6Ptr& pkt) const {
     return (true);
 }
 
-DuidPtr
-Dhcpv6Srv::extractClientId(const Pkt6Ptr& pkt) {
-    // Let's find client's DUID. Client is supposed to include its client-id
-    // option almost all the time (the only exception is an anonymous inf-request,
-    // but that is mostly a theoretical case). Our allocation engine needs DUID
-    // and will refuse to allocate anything to anonymous clients.
-    OptionPtr opt_duid = pkt->getOption(D6O_CLIENTID);
-    if (opt_duid) {
-        return (DuidPtr(new DUID(opt_duid->getData())));
-    } else {
-        return (DuidPtr());
-    }
-}
-
 AllocEngine::ClientContext6
 Dhcpv6Srv::createContext(const Pkt6Ptr& pkt) {
     AllocEngine::ClientContext6 ctx;
     ctx.subnet_ = selectSubnet(pkt);
-    ctx.duid_ = extractClientId(pkt);
+    ctx.duid_ = pkt->getClientId();
     ctx.hwaddr_ = getMAC(pkt);
     alloc_engine_->findReservation(ctx);
 

+ 0 - 6
src/bin/dhcp6/dhcp6_srv.h

@@ -737,12 +737,6 @@ private:
                                const std::string& hostname,
                                bool do_fwd, bool do_rev);
 
-    /// @brief Utility method that extracts DUID from client-id option
-    ///
-    /// @param pkt the message that contains client-id option
-    /// @return extracted DUID (or NULL if client-id is missing)
-    DuidPtr extractClientId(const Pkt6Ptr& pkt);
-
     /// @brief Allocation Engine.
     /// Pointer to the allocation engine that we are currently using
     /// It must be a pointer, because we will support changing engines

+ 36 - 0
src/lib/dhcp/pkt6.cc

@@ -496,6 +496,36 @@ Pkt6::getMACFromDUID() {
 }
 
 std::string
+Pkt6::makeLabel(const DuidPtr duid, const uint32_t transid,
+                const HWAddrPtr& hwaddr) {
+    std::stringstream label;
+    // DUID should be present at all times, so explicitly inform when
+    // it is no present (no info).
+    label << "duid=[" << (duid ? duid->toText() : "no info")
+          << "],";
+
+    // HW address is typically not carried in the DHCPv6 mmessages
+    // and can be extracted using various, but not fully reliable,
+    // techniques. If it is not present, don't print anything.
+    if (hwaddr) {
+        label << " [" << hwaddr->toText() << "],";
+    }
+
+    // Transaction id is always there.
+    label << " tid=0x" << std::hex << transid << std::dec;
+
+    return (label.str());
+}
+
+std::string
+Pkt6::getLabel() const {
+    /// @todo Do not print HW address as it is unclear how it should
+    /// be retrieved if there is no access to user configuration which
+    /// specifies the order of various techniques to be used to retrieve
+    /// it.
+    return (makeLabel(getClientId(), getTransid(), HWAddrPtr()));}
+
+std::string
 Pkt6::toText() const {
     stringstream tmp;
     tmp << "localAddr=[" << local_addr_ << "]:" << local_port_
@@ -511,6 +541,12 @@ Pkt6::toText() const {
     return tmp.str();
 }
 
+DuidPtr
+Pkt6::getClientId() const {
+    OptionPtr opt_duid = getOption(D6O_CLIENTID);
+    return (opt_duid ? DuidPtr(new DUID(opt_duid->getData())) : DuidPtr());
+}
+
 isc::dhcp::OptionCollection
 Pkt6::getOptions(uint16_t opt_type) {
     isc::dhcp::OptionCollection found;

+ 34 - 0
src/lib/dhcp/pkt6.h

@@ -16,6 +16,7 @@
 #define PKT6_H
 
 #include <asiolink/io_address.h>
+#include <dhcp/duid.h>
 #include <dhcp/option.h>
 #include <dhcp/pkt.h>
 
@@ -157,6 +158,34 @@ public:
         proto_ = proto;
     }
 
+    /// @brief Returns text representation of the given packet identifiers.
+    ///
+    /// @note The parameters are ordered from the one that should be available
+    /// almost at all times, to the one that is optional. This allows for
+    /// providing default values for the parameters that may not be available
+    /// in some places in the code where @c Pkt6::makeLabel is called.
+    ///
+    /// @param duid Pointer to the client identifier or NULL.
+    /// @param transid Numeric transaction id to include in the string.
+    /// @param hwaddr Hardware address to include in the string or NULL.
+    ///
+    /// @return String with text representation of the packet identifiers.
+    static std::string makeLabel(const DuidPtr duid, const uint32_t transid,
+                                 const HWAddrPtr& hwaddr);
+
+    /// @brief Returns text representation of the primary packet identifiers
+    ///
+    /// This method is intended to be used to provide a consistent way to
+    /// identify packets within log statements.  It is an instance-level
+    /// wrapper around static makeLabel(). See this method for string
+    /// content.
+    ///
+    /// @note Currently this method doesn't include the HW address in the
+    /// returned text.
+    ///
+    /// @return string with text representation
+    virtual std::string getLabel() const;
+
     /// @brief Returns text representation of the packet.
     ///
     /// This function is useful mainly for debugging.
@@ -186,6 +215,11 @@ public:
     /// @param type message type to be set
     virtual void setType(uint8_t type) { msg_type_=type; };
 
+    /// @brief Retrieves the DUID from the Client Identifier option.
+    ///
+    /// @return Pointer to the DUID or NULL if the option doesn't exist.
+    DuidPtr getClientId() const;
+
     /// @brief returns option inserted by relay
     ///
     /// Returns an option from specified relay scope (inserted by a given relay

+ 84 - 14
src/lib/dhcp/tests/pkt6_unittest.cc

@@ -129,9 +129,9 @@ public:
     /// length as an input. This constructor is normally used to parse
     /// received packets. It stores the packet in a data_ field and
     /// therefore unpack() can be called to parse it.
-    Pkt6Ptr packAndClone() {
-        Pkt6Ptr parent(new Pkt6(DHCPV6_SOLICIT, 0x020304));
-
+    ///
+    /// @param parent Packet from which the new packet should be created.
+    Pkt6Ptr packAndClone(Pkt6Ptr& parent) {
         OptionPtr opt1(new Option(Option::V6, 1));
         OptionPtr opt2(new Option(Option::V6, 2));
         OptionPtr opt3(new Option(Option::V6, 100));
@@ -141,17 +141,8 @@ public:
         parent->addOption(opt2);
         parent->addOption(opt3);
 
-        EXPECT_EQ(DHCPV6_SOLICIT, parent->getType());
-
-        // Calculated length should be 16
-        EXPECT_EQ(Pkt6::DHCPV6_PKT_HDR_LEN + 3 * Option::OPTION6_HDR_LEN,
-                  parent->len());
-
         EXPECT_NO_THROW(parent->pack());
 
-        EXPECT_EQ(Pkt6::DHCPV6_PKT_HDR_LEN + 3 * Option::OPTION6_HDR_LEN,
-                  parent->len());
-
         // Create second packet,based on assembled data from the first one
         Pkt6Ptr clone(new Pkt6(static_cast<const uint8_t*>
                                (parent->getBuffer().getData()),
@@ -306,7 +297,8 @@ TEST_F(Pkt6Test, unpack_solicit1) {
 
 TEST_F(Pkt6Test, packUnpack) {
     // Create an on-wire representation of the test packet and clone it.
-    Pkt6Ptr clone = packAndClone();
+    Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 0x020304));
+    Pkt6Ptr clone = packAndClone(pkt);
 
     // Now recreate options list
     ASSERT_NO_THROW(clone->unpack());
@@ -383,7 +375,8 @@ TEST_F(Pkt6Test, unpackMalformed) {
 // the option parsing algorithm by installing a callback function.
 TEST_F(Pkt6Test, packUnpackWithCallback) {
     // Create an on-wire representation of the test packet and clone it.
-    Pkt6Ptr clone = packAndClone();
+    Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 0x020304));
+    Pkt6Ptr clone = packAndClone(pkt);
 
     // Install the custom callback function. We expect that this function
     // will be called to parse options in the packet instead of
@@ -1327,5 +1320,82 @@ TEST_F(Pkt6Test, rsoo) {
 
 }
 
+// Verify that the DUID can be extracted from the DHCPv6 packet
+// holding Client Identifier option.
+TEST_F(Pkt6Test, getClientId) {
+    // Create a packet.
+    Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 0x2312));
+    // Initially, the packet should hold no DUID.
+    EXPECT_FALSE(pkt->getClientId());
+
+    // Create DUID and add it to the packet.
+    const uint8_t duid_data[] = { 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 0 };
+    OptionBuffer duid_vec(duid_data, duid_data + sizeof(duid_data) - 1);
+    pkt->addOption(OptionPtr(new Option(Option::V6, D6O_CLIENTID,
+                                        duid_vec.begin(),
+                                        duid_vec.end())));
+
+    // Simulate the packet transmission over the wire, i.e. create on
+    // wire representation of the packet, and then parse it.
+    Pkt6Ptr pkt_clone = packAndClone(pkt);
+    ASSERT_NO_THROW(pkt_clone->unpack());
+
+    // This time the DUID should be returned.
+    DuidPtr duid = pkt_clone->getClientId();
+    ASSERT_TRUE(duid);
+
+    // And it should be equal to the one that we used to create
+    // the packet.
+    EXPECT_TRUE(duid->getDuid() == duid_vec);
+}
+
+// This test verfies that it is possible to obtain the packet
+// identifiers (DUID, HW Address, transaction id) in the textual
+// format.
+TEST_F(Pkt6Test, makeLabel) {
+    DuidPtr duid(new DUID(DUID::fromText("0102020202030303030303")));
+    HWAddrPtr hwaddr(new HWAddr(HWAddr::fromText("01:02:03:04:05:06",
+                                                 HTYPE_ETHER)));
+
+    // Specify DUID and no HW Address.
+    EXPECT_EQ("duid=[01:02:02:02:02:03:03:03:03:03:03], tid=0x123",
+              Pkt6::makeLabel(duid, 0x123, HWAddrPtr()));
+
+    // Specify HW Address and no DUID.
+    EXPECT_EQ("duid=[no info], [hwtype=1 01:02:03:04:05:06], tid=0x123",
+              Pkt6::makeLabel(DuidPtr(), 0x123, hwaddr));
+
+    // Specify both DUID and HW Address.
+    EXPECT_EQ("duid=[01:02:02:02:02:03:03:03:03:03:03], "
+              "[hwtype=1 01:02:03:04:05:06], tid=0x123",
+              Pkt6::makeLabel(duid, 0x123, hwaddr));
+
+    // Specify neither DUID nor HW Address.
+    EXPECT_EQ("duid=[no info], tid=0x0",
+              Pkt6::makeLabel(DuidPtr(), 0x0, HWAddrPtr()));
+}
+
+// This test verifies that it is possible to obtain the packet
+// identifiers in the textual format from the packet instance.
+TEST_F(Pkt6Test, getLabel) {
+    // Create a packet.
+    Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 0x2312));
+    EXPECT_EQ("duid=[no info], tid=0x2312",
+              pkt->getLabel());
+
+    DuidPtr duid(new DUID(DUID::fromText("0102020202030303030303")));
+    pkt->addOption(OptionPtr(new Option(Option::V6, D6O_CLIENTID,
+                                        duid->getDuid().begin(),
+                                        duid->getDuid().end())));
+
+    // Simulate the packet transmission over the wire, i.e. create on
+    // wire representation of the packet, and then parse it.
+    Pkt6Ptr pkt_clone = packAndClone(pkt);
+    ASSERT_NO_THROW(pkt_clone->unpack());
+
+    EXPECT_EQ("duid=[01:02:02:02:02:03:03:03:03:03:03], tid=0x2312",
+              pkt_clone->getLabel());
+
+}
 
 }