Browse Source

[3554] Changes after review:

 - Moved MAC operations to a new CfgMACSource class
 - Moved macros to HWaddr class
 - Added several unit-tests for MAC sources
 - MAC extraction code moved to separate function in Dhcpv6Srv
Tomek Mrugalski 10 years ago
parent
commit
2662ac5f02

+ 20 - 12
src/bin/dhcp6/dhcp6_srv.cc

@@ -1184,6 +1184,21 @@ Dhcpv6Srv::createRemovalNameChangeRequest(const Lease6Ptr& lease) {
     CfgMgr::instance().getD2ClientMgr().sendRequest(ncr);
 }
 
+HWAddrPtr
+Dhcpv6Srv::getMAC(const Pkt6Ptr& pkt) {
+    CfgMACSources mac_sources = CfgMgr::instance().getCurrentCfg()->
+        getMACSources().get();
+    HWAddrPtr hwaddr;
+    for (CfgMACSources::const_iterator it = mac_sources.begin();
+         it != mac_sources.end(); ++it) {
+        hwaddr = pkt->getMAC(*it);
+        if (hwaddr) {
+            return (hwaddr);
+        }
+    }
+    return (hwaddr);
+}
+
 OptionPtr
 Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
                        const Pkt6Ptr& query, const Pkt6Ptr& answer,
@@ -1255,16 +1270,7 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
 
     // Attempt to get MAC address using configured mechanisms.
     // It's ok if there response is NULL. Hardware address is optional in Lease6.
-    std::vector<uint32_t> mac_sources = CfgMgr::instance().getCurrentCfg()->
-        getMACSources();
-    HWAddrPtr hwaddr;
-    for (std::vector<uint32_t>::const_iterator it = mac_sources.begin();
-         it != mac_sources.end(); ++it) {
-        hwaddr = query->getMAC(*it);
-        if (hwaddr) {
-            break;
-        }
-    }
+    HWAddrPtr hwaddr = getMAC(query);
 
     // Use allocation engine to pick a lease for this client. Allocation engine
     // will try to honour the hint, but it is just a hint - some other address
@@ -1384,8 +1390,7 @@ Dhcpv6Srv::assignIA_PD(const Subnet6Ptr& subnet, const DuidPtr& duid,
 
     // Attempt to get MAC address using any of available mechanisms.
     // It's ok if there response is NULL. Hardware address is optional in Lease6
-    /// @todo: Make this configurable after trac 3554 is done.
-    HWAddrPtr hwaddr = query->getMAC(Pkt::HWADDR_SOURCE_ANY);
+    HWAddrPtr hwaddr = getMAC(query);
 
     LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_PD_REQUEST)
         .arg(duid ? duid->toText() : "(no-duid)").arg(ia->getIAID())
@@ -1577,6 +1582,9 @@ Dhcpv6Srv::extendIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
         lease->fqdn_fwd_ = do_fwd;
         lease->fqdn_rev_ = do_rev;
 
+        /// @todo: check if hardware address has changed since last update.
+        /// And modify lease->hwaddr_ if it did.
+
         ia_rsp->setT1(subnet->getT1());
         ia_rsp->setT2(subnet->getT2());
 

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

@@ -597,6 +597,15 @@ protected:
     void classifyPacket(const Pkt6Ptr& pkt);
 
 
+    /// @brief Attempts to get a MAC/hardware address using configred sources
+    ///
+    /// Tries to extract MAC/hardware address information from the packet
+    /// using MAC sources configured in 'mac-sources' directive.
+    ///
+    /// @param pkt will try to exact MAC address from this packet
+    /// @return HWaddr pointer (or NULL if configured methods fail)
+    HWAddrPtr getMAC(const Pkt6Ptr& pkt);
+
     /// @brief this is a prefix added to the contend of vendor-class option
     ///
     /// If incoming packet has a vendor class option, its content is

+ 57 - 7
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -3628,14 +3628,48 @@ TEST_F(Dhcp6ParserTest, reservationBogus) {
 }
 
 /// The goal of this test is to verify that configuration can include
-/// MAC/Hardware sources.
+/// MAC/Hardware sources. This test also checks if the aliases are
+/// handled properly (rfc6939 = client-addr-relay, rfc4649 = remote-id,
+/// rfc4580 = subscriber-id).
 TEST_F(Dhcp6ParserTest, macSources) {
 
     ConstElementPtr status;
 
     EXPECT_NO_THROW(status = configureDhcp6Server(srv_,
+        Element::fromJSON("{ \"interfaces\": [ \"*\" ],"
+                          "\"mac-sources\": [ \"rfc6939\", \"rfc4649\", \"rfc4580\","
+                          "\"client-link-addr-option\", \"remote-id\", \"subscriber-id\"],"
+                          "\"preferred-lifetime\": 3000,"
+                          "\"rebind-timer\": 2000, "
+                          "\"renew-timer\": 1000, "
+                          "\"subnet6\": [  ], "
+                          "\"valid-lifetime\": 4000 }")));
+
+    // returned value should be 0 (success)
+    checkResult(status, 0);
+
+    CfgMACSources mac_sources = CfgMgr::instance().getStagingCfg()->getMACSources().get();
+    ASSERT_EQ(6, mac_sources.size());
+    // Let's check the aliases. They should be recognized to their base methods.
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, mac_sources[0]);
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_REMOTE_ID, mac_sources[1]);
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID, mac_sources[2]);
+
+    // Let's check if the actual methods are recognized properly.
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, mac_sources[3]);
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_REMOTE_ID, mac_sources[4]);
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID, mac_sources[5]);
+}
+
+/// The goal of this test is to verify that MAC sources configuration can be
+/// empty.
+TEST_F(Dhcp6ParserTest, macSourcesEmpty) {
+
+    ConstElementPtr status;
+
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_,
                     Element::fromJSON("{ \"interfaces\": [ \"*\" ],"
-                                      "\"mac-sources\": [ \"rfc6939\", \"rfc4649\", \"rfc4580\" ],"
+                                      "\"mac-sources\": [ ],"
                                       "\"preferred-lifetime\": 3000,"
                                       "\"rebind-timer\": 2000, "
                                       "\"renew-timer\": 1000, "
@@ -3645,11 +3679,27 @@ TEST_F(Dhcp6ParserTest, macSources) {
     // returned value should be 0 (success)
     checkResult(status, 0);
 
-    vector<uint32_t> mac_sources = CfgMgr::instance().getStagingCfg()->getMACSources();
-    ASSERT_EQ(3, mac_sources.size());
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, mac_sources[0]);
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_REMOTE_ID, mac_sources[1]);
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_SUBSCRIBER_ID, mac_sources[2]);
+    CfgMACSources mac_sources = CfgMgr::instance().getStagingCfg()->getMACSources().get();
+    EXPECT_EQ(0, mac_sources.size());
+}
+
+/// The goal of this test is to verify that MAC sources configuration can
+/// only use valid parameters.
+TEST_F(Dhcp6ParserTest, macSourcesBogus) {
+
+    ConstElementPtr status;
+
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_,
+                    Element::fromJSON("{ \"interfaces\": [ \"*\" ],"
+                                      "\"mac-sources\": [ \"from-wire\" ],"
+                                      "\"preferred-lifetime\": 3000,"
+                                      "\"rebind-timer\": 2000, "
+                                      "\"renew-timer\": 1000, "
+                                      "\"subnet6\": [  ], "
+                                      "\"valid-lifetime\": 4000 }")));
+
+    // returned value should be 1 (failure)
+    checkResult(status, 1);
 }
 
 };

+ 1 - 1
src/bin/dhcp6/tests/dhcp6_client.cc

@@ -63,7 +63,7 @@ Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
     Opts opts = reply->options_;
 
     // Let's try to get a MAC
-    HWAddrPtr hwaddr = reply->getMAC(Pkt::HWADDR_SOURCE_ANY);
+    HWAddrPtr hwaddr = reply->getMAC(HWAddr::HWADDR_SOURCE_ANY);
 
     // Set the global status code to default: success and not received.
     config_.resetGlobalStatusCode();

+ 10 - 0
src/lib/dhcp/hwaddr.cc

@@ -27,6 +27,16 @@
 namespace isc {
 namespace dhcp {
 
+const uint32_t HWAddr::HWADDR_SOURCE_ANY = 0xffffffff;
+const uint32_t HWAddr::HWADDR_SOURCE_UNKNOWN = 0x00000000;
+const uint32_t HWAddr::HWADDR_SOURCE_RAW = 0x00000001;
+const uint32_t HWAddr::HWADDR_SOURCE_DUID = 0x00000002;
+const uint32_t HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL = 0x00000004;
+const uint32_t HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION = 0x00000008;
+const uint32_t HWAddr::HWADDR_SOURCE_REMOTE_ID = 0x00000010;
+const uint32_t HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID = 0x00000020;
+const uint32_t HWAddr::HWADDR_SOURCE_DOCSIS = 0x00000040;
+
 HWAddr::HWAddr()
     :htype_(HTYPE_ETHER), source_(0) {
 }

+ 47 - 0
src/lib/dhcp/hwaddr.h

@@ -34,6 +34,53 @@ public:
     /// @brief Maximum size of a hardware address.
     static const size_t MAX_HWADDR_LEN = 20;
 
+    /// @defgroup hw_sources Specifies where a given MAC/hardware address was
+    ///                      obtained.
+    ///
+    /// @brief The list covers all possible MAC/hw address sources.
+    ///
+    /// @{
+
+    /// Not really a type, only used in getMAC() calls.
+    static const uint32_t HWADDR_SOURCE_ANY;
+
+    /// Used when actual origin is not known, e.g. when reading from a
+    /// lease database that didn't store that information.
+    static const uint32_t HWADDR_SOURCE_UNKNOWN;
+
+    /// Obtained first hand from raw socket (100% reliable).
+    static const uint32_t HWADDR_SOURCE_RAW;
+
+    /// Extracted from DUID-LL or DUID-LLT (not 100% reliable as the client
+    /// can send fake DUID).
+    static const uint32_t HWADDR_SOURCE_DUID;
+
+    /// Extracted from IPv6 link-local address. Not 100% reliable, as the
+    /// client can use different IID other than EUI-64, e.g. Windows supports
+    /// RFC4941 and uses random values instead of EUI-64.
+    static const uint32_t HWADDR_SOURCE_IPV6_LINK_LOCAL;
+
+    /// Get it from RFC6939 option. (A relay agent can insert client link layer
+    /// address option). Note that a skilled attacker can fake that by sending
+    /// his request relayed, so the legitimate relay will think it's a second
+    /// relay.
+    static const uint32_t HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION;
+
+    /// A relay can insert remote-id. In some deployments it contains a MAC
+    /// address (RFC4649).
+    static const uint32_t HWADDR_SOURCE_REMOTE_ID;
+
+    /// A relay can insert a subscriber-id option. In some deployments it
+    /// contains a MAC address (RFC4580).
+    static const uint32_t HWADDR_SOURCE_SUBSCRIBER_ID;
+
+    /// A CMTS (acting as DHCP relay agent) that supports DOCSIS standard
+    /// can insert DOCSIS options that contain client's MAC address.
+    /// Client in this context would be a cable modem.
+    static const uint32_t HWADDR_SOURCE_DOCSIS;
+
+    /// @}
+
     /// @brief default constructor
     HWAddr();
 

+ 7 - 45
src/lib/dhcp/pkt.cc

@@ -15,21 +15,12 @@
 #include <utility>
 #include <dhcp/pkt.h>
 #include <dhcp/iface_mgr.h>
+#include <dhcp/hwaddr.h>
 #include <vector>
 
 namespace isc {
 namespace dhcp {
 
-const uint32_t Pkt::HWADDR_SOURCE_ANY = 0xffffffff;
-const uint32_t Pkt::HWADDR_SOURCE_UNKNOWN = 0x00000000;
-const uint32_t Pkt::HWADDR_SOURCE_RAW = 0x00000001;
-const uint32_t Pkt::HWADDR_SOURCE_DUID = 0x00000002;
-const uint32_t Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL = 0x00000004;
-const uint32_t Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION = 0x00000008;
-const uint32_t Pkt::HWADDR_SOURCE_REMOTE_ID = 0x00000010;
-const uint32_t Pkt::HWADDR_SOURCE_SUBSCRIBER_ID = 0x00000020;
-const uint32_t Pkt::HWADDR_SOURCE_DOCSIS = 0x00000040;
-
 Pkt::Pkt(uint32_t transid, const isc::asiolink::IOAddress& local_addr,
          const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
          uint16_t remote_port)
@@ -139,11 +130,11 @@ Pkt::getMAC(uint32_t hw_addr_src) {
     HWAddrPtr mac;
 
     // Method 1: from raw sockets.
-    if (hw_addr_src & HWADDR_SOURCE_RAW) {
+    if (hw_addr_src & HWAddr::HWADDR_SOURCE_RAW) {
         mac = getRemoteHWAddr();
         if (mac) {
             return (mac);
-        } else if (hw_addr_src == HWADDR_SOURCE_RAW) {
+        } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_RAW) {
             // If we're interested only in RAW sockets as source of that info,
             // there's no point in trying other options.
             return (HWAddrPtr());
@@ -153,11 +144,11 @@ Pkt::getMAC(uint32_t hw_addr_src) {
     // Method 2: Extracted from DUID-LLT or DUID-LL
 
     // Method 3: Extracted from source IPv6 link-local address
-    if (hw_addr_src & HWADDR_SOURCE_IPV6_LINK_LOCAL) {
+    if (hw_addr_src & HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL) {
         mac = getMACFromSrcLinkLocalAddr();
         if (mac) {
             return (mac);
-        } else if (hw_addr_src ==  HWADDR_SOURCE_IPV6_LINK_LOCAL) {
+        } else if (hw_addr_src ==  HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL) {
             // If we're interested only in link-local addr as source of that
             // info, there's no point in trying other options.
             return (HWAddrPtr());
@@ -165,11 +156,11 @@ Pkt::getMAC(uint32_t hw_addr_src) {
     }
 
     // Method 4: From client link-layer address option inserted by a relay
-    if (hw_addr_src & HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION) {
+    if (hw_addr_src & HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION) {
         mac = getMACFromIPv6RelayOpt();
         if (mac) {
             return (mac);
-        } else if (hw_addr_src ==  HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION) {
+        } else if (hw_addr_src ==  HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION) {
             // If we're interested only in RFC6939 link layer address as source
             // of that info, there's no point in trying other options.
             return (HWAddrPtr());
@@ -233,34 +224,5 @@ Pkt::getMACFromIPv6(const isc::asiolink::IOAddress& addr) {
     return (HWAddrPtr(new HWAddr(bin, hwtype)));
 }
 
-uint32_t Pkt::MACSourceFromText(const std::string& name) {
-
-    struct {
-        const char * name;
-        uint32_t type;
-    } sources[] = {
-        { "any", Pkt::HWADDR_SOURCE_ANY },
-        { "raw", Pkt::HWADDR_SOURCE_RAW },
-        { "duid", Pkt::HWADDR_SOURCE_DUID },
-        { "ipv6-link-local", Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL },
-        { "client-link-addr-option", Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION },
-        { "rfc6939", Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION },
-        { "remote-id", Pkt::HWADDR_SOURCE_REMOTE_ID },
-        { "rfc4649", Pkt::HWADDR_SOURCE_REMOTE_ID },
-        { "subscriber-id", Pkt::HWADDR_SOURCE_SUBSCRIBER_ID },
-        { "rfc4580", Pkt::HWADDR_SOURCE_SUBSCRIBER_ID },
-        { "docsis", Pkt::HWADDR_SOURCE_DOCSIS }
-    };
-
-    for (int i=0; i < sizeof(sources)/sizeof(sources[0]); ++i) {
-        if (name.compare(sources[i].name) == 0) {
-            return (sources[i].type);
-        }
-    }
-
-    isc_throw(BadValue, "Can't convert '" << name << "' to any known MAC source.");
-}
-
-
 };
 };

+ 0 - 64
src/lib/dhcp/pkt.h

@@ -37,70 +37,6 @@ namespace dhcp {
 /// @note This is abstract class. Please instantiate derived classes
 /// such as @c Pkt4 or @c Pkt6.
 class Pkt {
-public:
-
-    /// @defgroup hw_sources Specifies where a given MAC/hardware address was
-    ///                      obtained.
-    ///
-    /// @brief The list covers all possible MAC/hw address sources.
-    ///
-    /// @{
-
-    /// Not really a type, only used in getMAC() calls.
-    static const uint32_t HWADDR_SOURCE_ANY;
-
-    /// Used when actual origin is not known, e.g. when reading from a
-    /// lease database that didn't store that information.
-    static const uint32_t HWADDR_SOURCE_UNKNOWN;
-
-    /// Obtained first hand from raw socket (100% reliable).
-    static const uint32_t HWADDR_SOURCE_RAW;
-
-    /// Extracted from DUID-LL or DUID-LLT (not 100% reliable as the client
-    /// can send fake DUID).
-    static const uint32_t HWADDR_SOURCE_DUID;
-
-    /// Extracted from IPv6 link-local address. Not 100% reliable, as the
-    /// client can use different IID other than EUI-64, e.g. Windows supports
-    /// RFC4941 and uses random values instead of EUI-64.
-    static const uint32_t HWADDR_SOURCE_IPV6_LINK_LOCAL;
-
-    /// Get it from RFC6939 option. (A relay agent can insert client link layer
-    /// address option). Note that a skilled attacker can fake that by sending
-    /// his request relayed, so the legitimate relay will think it's a second
-    /// relay.
-    static const uint32_t HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION;
-
-    /// A relay can insert remote-id. In some deployments it contains a MAC
-    /// address (RFC4649).
-    static const uint32_t HWADDR_SOURCE_REMOTE_ID;
-
-    /// A relay can insert a subscriber-id option. In some deployments it
-    /// contains a MAC address (RFC4580).
-    static const uint32_t HWADDR_SOURCE_SUBSCRIBER_ID;
-
-    /// A CMTS (acting as DHCP relay agent) that supports DOCSIS standard
-    /// can insert DOCSIS options that contain client's MAC address.
-    /// Client in this context would be a cable modem.
-    static const uint32_t HWADDR_SOURCE_DOCSIS;
-
-    /// @}
-
-    /// @brief Attempts to convert known hardware address sources to uint32_t
-    ///
-    /// Supported strings are: any => 0xffffffff
-    ///                        raw => 0x00000001
-    ///                        duid => 0x00000002
-    ///                        ipv6-link-local 0x00000004
-    ///                        client-link-addr-option, rfc6939 => 0x00000008
-    ///                        remote-id, rfc4649 => 0x00000010
-    ///                        subscriber-id, rfc4580 => 0x00000020
-    ///                        docsis => 0x00000040
-    ///
-    /// @throw BadValue if specified string is unknown
-    /// @return bitmask version of a given method
-    static uint32_t MACSourceFromText(const std::string& name);
-
 protected:
 
     /// @brief Constructor.

+ 6 - 6
src/lib/dhcp/tests/pkt4_unittest.cc

@@ -857,8 +857,8 @@ TEST_F(Pkt4Test, getMAC) {
     Pkt4 pkt(DHCPOFFER, 1234);
 
     // DHCPv4 packet by default doens't have MAC address specified.
-    EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_ANY));
-    EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_RAW));
+    EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
+    EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW));
 
     // Let's invent a MAC
     const uint8_t hw[] = { 2, 4, 6, 8, 10, 12 }; // MAC
@@ -869,12 +869,12 @@ TEST_F(Pkt4Test, getMAC) {
     pkt.setRemoteHWAddr(dummy_hwaddr);
 
     // Now we should be able to get something
-    ASSERT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_ANY));
-    ASSERT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_RAW));
+    ASSERT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
+    ASSERT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW));
 
     // Check that the returned MAC is indeed the expected one
-    ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::HWADDR_SOURCE_ANY));
-    ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::HWADDR_SOURCE_RAW));
+    ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
+    ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW));
 }
 
 } // end of anonymous namespace

+ 23 - 52
src/lib/dhcp/tests/pkt6_unittest.cc

@@ -883,20 +883,20 @@ TEST_F(Pkt6Test, getMAC) {
     Pkt6 pkt(DHCPV6_ADVERTISE, 1234);
 
     // DHCPv6 packet by default doens't have MAC address specified.
-    EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_ANY));
-    EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_RAW));
+    EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
+    EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW));
 
     // We haven't specified source IPv6 address, so this method should
     // fail, too
-    EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL));
+    EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL));
 
     // Let's check if setting IPv6 address improves the situation.
     IOAddress linklocal_eui64("fe80::204:06ff:fe08:0a0c");
     pkt.setRemoteAddr(linklocal_eui64);
-    EXPECT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_ANY));
-    EXPECT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL));
-    EXPECT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL |
-                           Pkt::HWADDR_SOURCE_RAW));
+    EXPECT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
+    EXPECT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL));
+    EXPECT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL |
+                           HWAddr::HWADDR_SOURCE_RAW));
     pkt.setRemoteAddr(IOAddress("::"));
 
     // Let's invent a MAC
@@ -908,14 +908,14 @@ TEST_F(Pkt6Test, getMAC) {
     pkt.setRemoteHWAddr(dummy_hwaddr);
 
     // Now we should be able to get something
-    ASSERT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_ANY));
-    ASSERT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_RAW));
-    EXPECT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL |
-                           Pkt::HWADDR_SOURCE_RAW));
+    ASSERT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
+    ASSERT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW));
+    EXPECT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL |
+                           HWAddr::HWADDR_SOURCE_RAW));
 
     // Check that the returned MAC is indeed the expected one
-    ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::HWADDR_SOURCE_ANY));
-    ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::HWADDR_SOURCE_RAW));
+    ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
+    ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW));
 }
 
 // Test checks whether getMACFromIPv6LinkLocal() returns the hardware (MAC)
@@ -941,11 +941,11 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_direct) {
 
     // If received from a global address, this method should fail
     pkt.setRemoteAddr(global);
-    EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL));
+    EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL));
 
     // If received from link-local that is EUI-64 based, it should succeed
     pkt.setRemoteAddr(linklocal_eui64);
-    HWAddrPtr found = pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL);
+    HWAddrPtr found = pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL);
     ASSERT_TRUE(found);
 
     stringstream tmp;
@@ -980,15 +980,15 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_singleRelay) {
 
     // If received from a global address, this method should fail
     pkt.relay_info_[0].peeraddr_ = global;
-    EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL));
+    EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL));
 
     // If received from a link-local that does not use EUI-64, it should fail
     pkt.relay_info_[0].peeraddr_ = linklocal_noneui64;
-    EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL));
+    EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL));
 
     // If received from link-local that is EUI-64 based, it should succeed
     pkt.relay_info_[0].peeraddr_ = linklocal_eui64;
-    HWAddrPtr found = pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL);
+    HWAddrPtr found = pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL);
     ASSERT_TRUE(found);
 
     stringstream tmp;
@@ -1041,7 +1041,7 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_multiRelay) {
     pkt.setIndex(iface->getIndex());
 
     // The method should return MAC based on the first relay that was closest
-    HWAddrPtr found = pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL);
+    HWAddrPtr found = pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL);
     ASSERT_TRUE(found);
 
     // Let's check the info now.
@@ -1058,7 +1058,7 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_singleRelay) {
     Pkt6 pkt(DHCPV6_SOLICIT, 1234);
 
     // Packets that are not relayed should fail
-    EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION));
+    EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION));
 
     // Now pretend it was relayed by a single relay.
     Pkt6::RelayInfo info;
@@ -1075,7 +1075,7 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_singleRelay) {
     pkt.addRelayInfo(info);
     ASSERT_EQ(1, pkt.relay_info_.size());
 
-    HWAddrPtr found = pkt.getMAC(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION);
+    HWAddrPtr found = pkt.getMAC(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION);
     ASSERT_TRUE(found);
 
     stringstream tmp;
@@ -1108,7 +1108,7 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_multipleRelay) {
     pkt.addRelayInfo(info2);
     ASSERT_EQ(2, pkt.relay_info_.size());
 
-    EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION));
+    EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION));
 
     // Let's envolve the packet with a third relay (now the closest to the client)
     // that inserts the correct client_linklayer_addr option.
@@ -1123,7 +1123,7 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_multipleRelay) {
     ASSERT_EQ(3, pkt.relay_info_.size());
 
     // Now extract the MAC address from the relayed option
-    HWAddrPtr found = pkt.getMAC(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION);
+    HWAddrPtr found = pkt.getMAC(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION);
     ASSERT_TRUE(found);
 
     stringstream tmp;
@@ -1131,33 +1131,4 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_multipleRelay) {
     EXPECT_EQ(tmp.str(), found->toText(true));
 }
 
-// Checks whether Pkt::MACSourceFromText is working correctly.
-// Technically, this is a Pkt, not Pkt6 test, but since there is no separate
-// unit-tests for Pkt and it is abstract, so it would be tricky to test it
-// directly. Hence test is being run in Pkt6.
-TEST_F(Pkt6Test, MACSourceFromText) {
-    EXPECT_THROW(Pkt::MACSourceFromText("unknown"), BadValue);
-
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_ANY, Pkt::MACSourceFromText("any"));
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_RAW, Pkt::MACSourceFromText("raw"));
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_DUID, Pkt::MACSourceFromText("duid"));
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL,
-              Pkt::MACSourceFromText("ipv6-link-local"));
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION,
-              Pkt::MACSourceFromText("client-link-addr-option"));
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION,
-              Pkt::MACSourceFromText("rfc6939"));
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_REMOTE_ID,
-              Pkt::MACSourceFromText("remote-id"));
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_REMOTE_ID,
-              Pkt::MACSourceFromText("rfc4649"));
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_SUBSCRIBER_ID,
-              Pkt::MACSourceFromText("subscriber-id"));
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_SUBSCRIBER_ID,
-              Pkt::MACSourceFromText("rfc4580"));
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_DOCSIS,
-              Pkt::MACSourceFromText("docsis"));
-
-}
-
 }

+ 1 - 0
src/lib/dhcpsrv/Makefile.am

@@ -69,6 +69,7 @@ libkea_dhcpsrv_la_SOURCES += cfg_option.cc cfg_option.h
 libkea_dhcpsrv_la_SOURCES += cfg_option_def.cc cfg_option_def.h
 libkea_dhcpsrv_la_SOURCES += cfg_subnets4.cc cfg_subnets4.h
 libkea_dhcpsrv_la_SOURCES += cfg_subnets6.cc cfg_subnets6.h
+libkea_dhcpsrv_la_SOURCES += cfg_mac_source.cc cfg_mac_source.h
 libkea_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
 libkea_dhcpsrv_la_SOURCES += csv_lease_file4.cc csv_lease_file4.h
 libkea_dhcpsrv_la_SOURCES += csv_lease_file6.cc csv_lease_file6.h

+ 59 - 0
src/lib/dhcpsrv/cfg_mac_source.cc

@@ -0,0 +1,59 @@
+// Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <dhcpsrv/cfg_mac_source.h>
+#include <exceptions/exceptions.h>
+#include <dhcp/hwaddr.h>
+
+namespace isc {
+namespace dhcp {
+
+CfgMACSource::CfgMACSource() {
+
+    // By default, use any hardware source that is available.
+    mac_sources_.push_back(HWAddr::HWADDR_SOURCE_ANY);
+}
+
+uint32_t CfgMACSource::MACSourceFromText(const std::string& name) {
+
+    struct {
+        const char * name;
+        uint32_t type;
+    } sources[] = {
+        { "any", HWAddr::HWADDR_SOURCE_ANY },
+        { "raw", HWAddr::HWADDR_SOURCE_RAW },
+        { "duid", HWAddr::HWADDR_SOURCE_DUID },
+        { "ipv6-link-local", HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL },
+        { "client-link-addr-option", HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION },
+        { "rfc6939", HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION },
+        { "remote-id", HWAddr::HWADDR_SOURCE_REMOTE_ID },
+        { "rfc4649", HWAddr::HWADDR_SOURCE_REMOTE_ID },
+        { "subscriber-id", HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID },
+        { "rfc4580", HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID },
+        { "docsis", HWAddr::HWADDR_SOURCE_DOCSIS }
+    };
+
+    for (int i=0; i < sizeof(sources)/sizeof(sources[0]); ++i) {
+        if (name.compare(sources[i].name) == 0) {
+            return (sources[i].type);
+        }
+    }
+
+    isc_throw(BadValue, "Can't convert '" << name << "' to any known MAC source.");
+}
+
+
+};
+};

+ 85 - 0
src/lib/dhcpsrv/cfg_mac_source.h

@@ -0,0 +1,85 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef CFG_MAC_SOURCE_H
+#define CFG_MAC_SOURCE_H
+
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Container for defined MAC/hardware address sources
+typedef std::vector<uint32_t> CfgMACSources;
+
+/// @brief Wrapper class that holds MAC/hardware address sources
+///
+/// It's a simple wrapper around a vector of uint32_t, with each entry
+/// holding one MAC source.
+class CfgMACSource {
+
+ public:
+    /// @brief Default constructor.
+    ///
+    /// Sets source to 'any'.
+    CfgMACSource();
+
+    /// @brief Attempts to convert known hardware address sources to uint32_t
+    ///
+    /// Supported strings are: <br/>any => 0xffffffff<br/>
+    ///                        raw => 0x00000001<br/>
+    ///                        duid => 0x00000002<br/>
+    ///                        ipv6-link-local 0x00000004<br/>
+    ///                        client-link-addr-option, rfc6939 => 0x00000008<br/>
+    ///                        remote-id, rfc4649 => 0x00000010<br/>
+    ///                        subscriber-id, rfc4580 => 0x00000020<br/>
+    ///                        docsis => 0x00000040<br/>
+    ///
+    /// @throw BadValue if specified string is unknown
+    /// @return bitmask version of a given method
+    static uint32_t MACSourceFromText(const std::string& name);
+
+
+    /// @brief Adds additional MAC/hardware address aquisition.
+    ///
+    /// @param source MAC source (see constants in Pkt::HWADDR_SOURCE_*)
+    ///
+    /// Specified source is being added to the mac_sources_ array.
+    void add(uint32_t source) {
+        mac_sources_.push_back(source);
+    }
+
+    /// @brief Provides access to the configure MAC/Hardware address sources.
+    ///
+    /// @note The const reference returned is only valid as long as the
+    /// object that returned it.
+    const CfgMACSources& get() const {
+        return mac_sources_;
+    }
+
+    /// @brief Removes any configured MAC/Hardware address sources.
+    void clear() {
+        mac_sources_.clear();
+    }
+
+ protected:
+    /// @brief Actual MAC sources storage
+    CfgMACSources mac_sources_;
+
+};
+
+};
+};
+
+#endif

+ 4 - 3
src/lib/dhcpsrv/parsers/dhcp_parsers.cc

@@ -17,6 +17,7 @@
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/cfg_option.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
+#include <dhcpsrv/cfg_mac_source.h>
 #include <hooks/hooks_manager.h>
 #include <util/encode/hex.h>
 #include <util/strutil.h>
@@ -226,13 +227,13 @@ MACSourcesListConfigParser::build(ConstElementPtr value) {
 
     // By default, there's only one source defined: ANY.
     // If user specified anything, we need to get rid of that default.
-    CfgMgr::instance().getStagingCfg()->clearMACSources();
+    CfgMgr::instance().getStagingCfg()->getMACSources().clear();
 
     BOOST_FOREACH(ConstElementPtr source_elem, value->listValue()) {
         std::string source_str = source_elem->stringValue();
         try {
-            source = Pkt::MACSourceFromText(source_str);
-            CfgMgr::instance().getStagingCfg()->addMACSource(source);
+            source = CfgMACSource::MACSourceFromText(source_str);
+            CfgMgr::instance().getStagingCfg()->getMACSources().add(source);
         } catch (const std::exception& ex) {
             isc_throw(DhcpConfigError, "Failed to convert '"
                       << source_str << "' to any recognized MAC source:"

+ 0 - 6
src/lib/dhcpsrv/srv_config.cc

@@ -29,18 +29,12 @@ SrvConfig::SrvConfig()
     : sequence_(0), cfg_option_def_(new CfgOptionDef()),
       cfg_option_(new CfgOption()), cfg_subnets4_(new CfgSubnets4()),
       cfg_subnets6_(new CfgSubnets6()), cfg_hosts_(new CfgHosts()) {
-
-    // By default, use any hardware source that is available.
-    mac_sources_.push_back(Pkt::HWADDR_SOURCE_ANY);
 }
 
 SrvConfig::SrvConfig(const uint32_t sequence)
     : sequence_(sequence), cfg_option_def_(new CfgOptionDef()),
       cfg_option_(new CfgOption()), cfg_subnets4_(new CfgSubnets4()),
       cfg_subnets6_(new CfgSubnets6()), cfg_hosts_(new CfgHosts()) {
-
-    // By default, use any hardware source that is available.
-    mac_sources_.push_back(Pkt::HWADDR_SOURCE_ANY);
 }
 
 std::string

+ 14 - 19
src/lib/dhcpsrv/srv_config.h

@@ -21,6 +21,7 @@
 #include <dhcpsrv/cfg_option_def.h>
 #include <dhcpsrv/cfg_subnets4.h>
 #include <dhcpsrv/cfg_subnets6.h>
+#include <dhcpsrv/cfg_mac_source.h>
 #include <dhcpsrv/logging_info.h>
 #include <boost/shared_ptr.hpp>
 #include <vector>
@@ -235,30 +236,24 @@ public:
         return (cfg_hosts_);
     }
 
-    /// @brief Adds additional MAC/hardware address aquisition.
-    ///
-    /// @param source MAC source (see constants in Pkt::HWADDR_SOURCE_*)
-    ///
-    /// Specified source is being added to the mac_sources_ array.
-    void addMACSource(uint32_t source) {
-        mac_sources_.push_back(source);
-    }
+    //@}
 
-    /// @brief Provides access to the configure MAC/Hardware address sources.
+    /// @brief Returns non-const reference to an array that stores
+    ///        MAC/hardware address sources.
     ///
-    /// @note The const reference returned is only valid as long as the
-    /// object that returned it.
-    const std::vector<uint32_t>& getMACSources() const {
-        return mac_sources_;
+    /// @return non-const reference to MAC/hardware address sources
+    CfgMACSource& getMACSources() {
+        return (cfg_mac_source_);
     }
 
-    /// @brief Removes any configured MAC/Hardware address sources.
-    void clearMACSources() {
-        mac_sources_.clear();
+    /// @brief Returns const reference to an array that stores
+    ///        MAC/hardware address sources.
+    ///
+    /// @return const reference to MAC/hardware address sources
+    const CfgMACSource& getMACSources() const {
+        return (cfg_mac_source_);
     }
 
-    //@}
-
     /// @brief Copies the currnet configuration to a new configuration.
     ///
     /// This method copies the parameters stored in the configuration to
@@ -372,7 +367,7 @@ private:
     CfgHostsPtr cfg_hosts_;
 
     /// @brief A list of configured MAC sources.
-    std::vector<uint32_t> mac_sources_;
+    CfgMACSource cfg_mac_source_;
 };
 
 /// @name Pointers to the @c SrvConfig object.

+ 1 - 0
src/lib/dhcpsrv/tests/Makefile.am

@@ -57,6 +57,7 @@ libdhcpsrv_unittests_SOURCES += alloc_engine_unittest.cc
 libdhcpsrv_unittests_SOURCES += callout_handle_store_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_hosts_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_iface_unittest.cc
+libdhcpsrv_unittests_SOURCES += cfg_mac_source_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_option_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_option_def_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_subnets4_unittest.cc

+ 54 - 0
src/lib/dhcpsrv/tests/cfg_mac_source_unittest.cc

@@ -0,0 +1,54 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dhcpsrv/cfg_mac_source.h>
+#include <dhcp/hwaddr.h>
+#include <exceptions/exceptions.h>
+#include <gtest/gtest.h>
+
+namespace {
+
+using namespace isc;
+using namespace isc::dhcp;
+
+// Checks whether CfgMACSource::MACSourceFromText is working correctly.
+// Technically, this is a Pkt, not Pkt6 test, but since there is no separate
+// unit-tests for Pkt and it is abstract, so it would be tricky to test it
+// directly. Hence test is being run in Pkt6.
+TEST(CfgMACSourceTest, MACSourceFromText) {
+    EXPECT_THROW(CfgMACSource::MACSourceFromText("unknown"), BadValue);
+
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_ANY, CfgMACSource::MACSourceFromText("any"));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_RAW, CfgMACSource::MACSourceFromText("raw"));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_DUID, CfgMACSource::MACSourceFromText("duid"));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL,
+              CfgMACSource::MACSourceFromText("ipv6-link-local"));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION,
+              CfgMACSource::MACSourceFromText("client-link-addr-option"));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION,
+              CfgMACSource::MACSourceFromText("rfc6939"));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_REMOTE_ID,
+              CfgMACSource::MACSourceFromText("remote-id"));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_REMOTE_ID,
+              CfgMACSource::MACSourceFromText("rfc4649"));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID,
+              CfgMACSource::MACSourceFromText("subscriber-id"));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID,
+              CfgMACSource::MACSourceFromText("rfc4580"));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_DOCSIS,
+              CfgMACSource::MACSourceFromText("docsis"));
+
+}
+
+};

+ 4 - 3
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc

@@ -22,6 +22,7 @@
 #include <dhcp/tests/iface_mgr_test_config.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/subnet.h>
+#include <dhcpsrv/cfg_mac_source.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
 #include <dhcpsrv/tests/test_libraries.h>
 #include <dhcpsrv/testutils/config_result_check.h>
@@ -306,11 +307,11 @@ TEST_F(DhcpParserTest, MacSourcesListConfigParserTest) {
     // eth2 was not added.
     SrvConfigPtr cfg = CfgMgr::instance().getStagingCfg();
     ASSERT_TRUE(cfg);
-    vector<uint32_t> configured_sources =  cfg->getMACSources();
+    CfgMACSources configured_sources =  cfg->getMACSources().get();
 
     ASSERT_EQ(2, configured_sources.size());
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_DUID, configured_sources[0]);
-    EXPECT_EQ(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL, configured_sources[1]);
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_DUID, configured_sources[0]);
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL, configured_sources[1]);
 }
 
 /// @brief Test Fixture class which provides basic structure for testing