}
}
+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;
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;
#define PKT6_H
#include <asiolink/io_address.h>
+#include <dhcp/duid.h>
#include <dhcp/option.h>
#include <dhcp/pkt.h>
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.
/// @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
/// 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));
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()),
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());
// 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
}
+// 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());
+
+}
}