cfg_hosts_unittest.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. // Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <asiolink/io_address.h>
  16. #include <dhcp/duid.h>
  17. #include <dhcp/hwaddr.h>
  18. #include <dhcpsrv/cfg_hosts.h>
  19. #include <dhcpsrv/host.h>
  20. #include <gtest/gtest.h>
  21. #include <sstream>
  22. #include <set>
  23. using namespace isc;
  24. using namespace isc::dhcp;
  25. using namespace isc::asiolink;
  26. namespace {
  27. /// @brief Test fixture class for testing @c CfgHost object holding
  28. /// host reservations specified in the configuration file.
  29. class CfgHostsTest : public ::testing::Test {
  30. public:
  31. /// @brief Constructor.
  32. ///
  33. /// This constructor allocates a collection of @c HWAddr and @c DuidPtr
  34. /// objects used by the unit tests.
  35. ///
  36. /// The allocated HW addresses use the following pattern: 01:02:0A:BB:03:XX
  37. /// where XX is a number between 0 and 0x32. All of them are of the
  38. /// HTYPE_ETHER type.
  39. ///
  40. /// The allocated DUID LLTs use the following pattern:
  41. /// 01:02:03:04:05:06:07:08:09:0A:XX where the XX is a number between
  42. /// 0 and 0x32.
  43. CfgHostsTest();
  44. /// @brief Increases last byte of an address.
  45. ///
  46. /// @param address Address to be increased.
  47. IOAddress increase(const IOAddress& address, const uint8_t num) const;
  48. /// @brief Collection of HW address objects allocated for unit tests.
  49. std::vector<HWAddrPtr> hwaddrs_;
  50. /// @brief Collection of DUIDs allocated for unit tests.
  51. std::vector<DuidPtr> duids_;
  52. /// @brief Collection of IPv4 address objects allocated for unit tests.
  53. std::vector<IOAddress> addressesa_;
  54. std::vector<IOAddress> addressesb_;
  55. };
  56. CfgHostsTest::CfgHostsTest() {
  57. const uint8_t mac_template[] = {
  58. 0x01, 0x02, 0x0A, 0xBB, 0x03, 0x00
  59. };
  60. for (unsigned i = 0; i < 50; ++i) {
  61. std::vector<uint8_t> vec(mac_template,
  62. mac_template + sizeof(mac_template));
  63. vec[vec.size() - 1] = i;
  64. HWAddrPtr hwaddr(new HWAddr(vec, HTYPE_ETHER));
  65. hwaddrs_.push_back(hwaddr);
  66. }
  67. const uint8_t duid_template[] = {
  68. 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x00
  69. };
  70. for (unsigned i = 0; i < 50; ++i) {
  71. std::vector<uint8_t> vec(duid_template,
  72. duid_template + sizeof(mac_template));
  73. vec[vec.size() - 1] = i;
  74. DuidPtr duid(new DUID(vec));
  75. duids_.push_back(duid);
  76. }
  77. const uint32_t addra_template = 0xc0000205; // 192.0.2.5
  78. const uint32_t addrb_template = 0xc00a020a; // 192.10.2.10
  79. for (int i = 0; i < 50; ++i) {
  80. IOAddress addra(addra_template + i);
  81. addressesa_.push_back(addra);
  82. IOAddress addrb(addrb_template + i);
  83. addressesb_.push_back(addrb);
  84. }
  85. }
  86. IOAddress
  87. CfgHostsTest::increase(const IOAddress& address, const uint8_t num) const {
  88. std::vector<uint8_t> vec = address.toBytes();
  89. if (!vec.empty()) {
  90. vec[vec.size() - 1] += num;
  91. return (IOAddress::fromBytes(address.getFamily(), &vec[0]));
  92. }
  93. return (address);
  94. }
  95. // This test checks that hosts with unique HW addresses and DUIDs can be
  96. // retrieved from the host configuration.
  97. TEST_F(CfgHostsTest, getAllNonRepeatingHosts) {
  98. CfgHosts cfg;
  99. // Add 25 hosts identified by HW address and 25 hosts identified by
  100. // DUID. They are added to different subnets.
  101. for (int i = 0; i < 25; ++i) {
  102. cfg.add(HostPtr(new Host(hwaddrs_[i]->toText(false),
  103. "hw-address",
  104. SubnetID(i % 10 + 1), SubnetID(i % 5 + 1),
  105. addressesa_[i])));
  106. cfg.add(HostPtr(new Host(duids_[i]->toText(), "duid",
  107. SubnetID(i % 5 + 1), SubnetID(i % 10 + 1),
  108. addressesb_[i])));
  109. }
  110. // Try to retrieve each added reservation using HW address and DUID. Do it
  111. // in the reverse order to make sure that the order doesn't matter.
  112. for (int i = 24; i >= 0; --i) {
  113. // Get host identified by HW address. The DUID is non-zero but it
  114. // points to a host for which the reservation hasn't been added.
  115. HostCollection hosts = cfg.getAll(hwaddrs_[i], duids_[i + 25]);
  116. ASSERT_EQ(1, hosts.size());
  117. EXPECT_EQ(i % 10 + 1, hosts[0]->getIPv4SubnetID());
  118. EXPECT_EQ(addressesa_[i].toText(),
  119. hosts[0]->getIPv4Reservation().toText());
  120. // Get host identified by DUID. The HW address is non-null but it
  121. // points to a host for which the reservation hasn't been added.
  122. hosts = cfg.getAll(hwaddrs_[i + 25], duids_[i]);
  123. ASSERT_EQ(1, hosts.size());
  124. EXPECT_EQ(i % 5 + 1, hosts[0]->getIPv4SubnetID());
  125. EXPECT_EQ(addressesb_[i].toText(),
  126. hosts[0]->getIPv4Reservation().toText());
  127. }
  128. // Make sure that the reservations do not exist for the hardware addresses
  129. // and DUIDs from the range of 25 to 49.
  130. for (int i = 49; i >= 25; --i) {
  131. EXPECT_TRUE(cfg.getAll(hwaddrs_[i]).empty());
  132. EXPECT_TRUE(cfg.getAll(HWAddrPtr(), duids_[i]).empty());
  133. }
  134. }
  135. // This test verifies that the host can be added to multiple subnets and
  136. // that the getAll message retrieves all instances of the host.
  137. TEST_F(CfgHostsTest, getAllRepeatingHosts) {
  138. CfgHosts cfg;
  139. // Add hosts.
  140. for (int i = 0; i < 25; ++i) {
  141. // Add two hosts, using the same HW address to two distinct subnets.
  142. cfg.add(HostPtr(new Host(hwaddrs_[i]->toText(false),
  143. "hw-address",
  144. SubnetID(1), SubnetID(2),
  145. addressesa_[i])));
  146. cfg.add(HostPtr(new Host(hwaddrs_[i]->toText(false),
  147. "hw-address",
  148. SubnetID(2), SubnetID(3),
  149. addressesb_[i])));
  150. // Add two hosts, using the same DUID to two distinct subnets.
  151. cfg.add(HostPtr(new Host(duids_[i]->toText(), "duid",
  152. SubnetID(1), SubnetID(2),
  153. addressesb_[i])));
  154. cfg.add(HostPtr(new Host(duids_[i]->toText(), "duid",
  155. SubnetID(2), SubnetID(3),
  156. addressesa_[i])));
  157. }
  158. // Verify that hosts can be retrieved.
  159. for (int i = 0; i < 25; ++i) {
  160. // Get host by HW address. The DUID is non-null but the reservation
  161. // should be returned for the HW address because there are no
  162. // reservations for the DUIDs from the range of 25 to 49.
  163. HostCollection hosts = cfg.getAll(hwaddrs_[i], duids_[i + 25]);
  164. ASSERT_EQ(2, hosts.size());
  165. EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
  166. EXPECT_EQ(addressesa_[i], hosts[0]->getIPv4Reservation().toText());
  167. EXPECT_EQ(2, hosts[1]->getIPv4SubnetID());
  168. EXPECT_EQ(addressesb_[i], hosts[1]->getIPv4Reservation().toText());
  169. // Get host by DUID. The HW address is non-null but the reservation
  170. // should be returned for the DUID because there are no
  171. // reservations for the HW addresses from the range of 25 to 49.
  172. hosts = cfg.getAll(hwaddrs_[i + 25], duids_[i]);
  173. ASSERT_EQ(2, hosts.size());
  174. EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
  175. EXPECT_EQ(2, hosts[1]->getIPv4SubnetID());
  176. }
  177. // The getAll function should return empty containers for the HW addresses
  178. // and DUIDs for which the reservations haven't been added.
  179. for (int i = 25; i < 50; ++i) {
  180. EXPECT_TRUE(cfg.getAll(hwaddrs_[i]).empty());
  181. EXPECT_TRUE(cfg.getAll(HWAddrPtr(), duids_[i]).empty());
  182. }
  183. }
  184. // This test checks that all reservations for the specified IPv4 address can
  185. // be retrieved.
  186. TEST_F(CfgHostsTest, getAll4ByAddress) {
  187. CfgHosts cfg;
  188. // Add hosts.
  189. for (int i = 0; i < 25; ++i) {
  190. // Add host identified by the HW address.
  191. cfg.add(HostPtr(new Host(hwaddrs_[i]->toText(false),
  192. "hw-address",
  193. SubnetID(1 + i), SubnetID(0),
  194. IOAddress("192.0.2.5"))));
  195. // Add host identified by the DUID.
  196. cfg.add(HostPtr(new Host(duids_[i]->toText(),
  197. "duid",
  198. SubnetID(1 + i), SubnetID(0),
  199. IOAddress("192.0.2.10"))));
  200. }
  201. HostCollection hosts = cfg.getAll4(IOAddress("192.0.2.10"));
  202. std::set<uint32_t> subnet_ids;
  203. for (HostCollection::const_iterator host = hosts.begin(); host != hosts.end();
  204. ++host) {
  205. subnet_ids.insert((*host)->getIPv4SubnetID());
  206. }
  207. ASSERT_EQ(25, subnet_ids.size());
  208. EXPECT_EQ(1, *subnet_ids.begin());
  209. EXPECT_EQ(25, *subnet_ids.rbegin());
  210. }
  211. // This test checks that the reservations can be retrieved for the particular
  212. // host connected to the specific IPv4 subnet (by subnet id).
  213. TEST_F(CfgHostsTest, get4) {
  214. CfgHosts cfg;
  215. // Add hosts.
  216. for (unsigned i = 0; i < 25; ++i) {
  217. // Add host identified by HW address.
  218. cfg.add(HostPtr(new Host(hwaddrs_[i]->toText(false),
  219. "hw-address",
  220. SubnetID(1 + i % 2), SubnetID(13),
  221. increase(IOAddress("192.0.2.5"), i))));
  222. // Add host identified by DUID.
  223. cfg.add(HostPtr(new Host(duids_[i]->toText(), "duid",
  224. SubnetID(1 + i % 2), SubnetID(13),
  225. increase(IOAddress("192.0.2.100"), i))));
  226. }
  227. for (unsigned i = 0; i < 25; ++i) {
  228. // Retrieve host by HW address. The DUID is non-null but there is no
  229. // reservation made for the DUID so the reservation is returned for
  230. // HW address.
  231. HostPtr host = cfg.get4(SubnetID(1 + i % 2), hwaddrs_[i],
  232. duids_[i + 25]);
  233. ASSERT_TRUE(host);
  234. EXPECT_EQ(1 + i % 2, host->getIPv4SubnetID());
  235. EXPECT_EQ(increase(IOAddress("192.0.2.5"), i),
  236. host->getIPv4Reservation());
  237. // Retrieve host by DUID. The HW address is non-null but there is no
  238. // reservation made for the HW address so the reservation is returned
  239. // for the DUID.
  240. host = cfg.get4(SubnetID(1 + i % 2), hwaddrs_[i + 25], duids_[i]);
  241. ASSERT_TRUE(host);
  242. EXPECT_EQ(1 + i % 2, host->getIPv4SubnetID());
  243. EXPECT_EQ(increase(IOAddress("192.0.2.100"), i),
  244. host->getIPv4Reservation());
  245. }
  246. // Also check that when the get4 finds multiple Host objects that fulfil
  247. // search criteria, it will throw an exception. Note that the reservation
  248. // exist both for hwaddrs_[0] and duids_[0].
  249. EXPECT_THROW(cfg.get4(SubnetID(1), hwaddrs_[0], duids_[0]), DuplicateHost);
  250. }
  251. // This test checks that the reservations can be retrieved for the particular
  252. // host connected to the specific IPv6 subnet (by subnet id).
  253. TEST_F(CfgHostsTest, get6) {
  254. CfgHosts cfg;
  255. // Add hosts.
  256. for (unsigned i = 0; i < 25; ++i) {
  257. // Add host identified by HW address.
  258. HostPtr host = HostPtr(new Host(hwaddrs_[i]->toText(false),
  259. "hw-address",
  260. SubnetID(10), SubnetID(1 + i % 2),
  261. IOAddress("0.0.0.0")));
  262. host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
  263. increase(IOAddress("2001:db8:1::1"),
  264. i)));
  265. cfg.add(host);
  266. // Add host identified by DUID.
  267. host = HostPtr(new Host(duids_[i]->toText(), "duid",
  268. SubnetID(10), SubnetID(1 + i % 2),
  269. IOAddress("0.0.0.0")));
  270. host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
  271. increase(IOAddress("2001:db8:2::1"),
  272. i)));
  273. cfg.add(host);
  274. }
  275. for (unsigned i = 0; i < 25; ++i) {
  276. // Retrieve host by HW address. The DUID is non-null but there is no
  277. // reservation made for the DUID so the reservation is returned for
  278. // HW address.
  279. HostPtr host = cfg.get6(SubnetID(1 + i % 2), duids_[i + 25],
  280. hwaddrs_[i]);
  281. ASSERT_TRUE(host);
  282. EXPECT_EQ(1 + i % 2, host->getIPv6SubnetID());
  283. IPv6ResrvRange reservations =
  284. host->getIPv6Reservations(IPv6Resrv::TYPE_NA);
  285. ASSERT_EQ(1, std::distance(reservations.first, reservations.second));
  286. EXPECT_EQ(increase(IOAddress("2001:db8:1::1"), i),
  287. reservations.first->second.getPrefix());
  288. // Retrieve host by DUID. The HW address is non-null but there is no
  289. // reservation made for the HW address so the reservation is returned
  290. // for the DUID.
  291. host = cfg.get6(SubnetID(1 + i % 2), duids_[i], hwaddrs_[i + 25]);
  292. ASSERT_TRUE(host);
  293. EXPECT_EQ(1 + i % 2, host->getIPv6SubnetID());
  294. reservations = host->getIPv6Reservations(IPv6Resrv::TYPE_NA);
  295. ASSERT_EQ(1, std::distance(reservations.first, reservations.second));
  296. EXPECT_EQ(increase(IOAddress("2001:db8:2::1"), i),
  297. reservations.first->second.getPrefix());
  298. }
  299. // Also check that when the get6 finds multiple Host objects that fulfil
  300. // search criteria, it will throw an exception. Note that the reservation
  301. // exist both for hwaddrs_[0] and duids_[0].
  302. EXPECT_THROW(cfg.get6(SubnetID(1), duids_[0], hwaddrs_[0]), DuplicateHost);
  303. }
  304. // This test checks that the IPv6 reservations can be retrieved for a particular
  305. // (subnet-id, address) tuple.
  306. TEST_F(CfgHostsTest, get6ByAddr) {
  307. CfgHosts cfg;
  308. // Add hosts.
  309. for (unsigned i = 0; i < 25; ++i) {
  310. // Add host identified by DUID.
  311. HostPtr host = HostPtr(new Host(duids_[i]->toText(), "duid",
  312. SubnetID(0), SubnetID(1 + i % 2),
  313. IOAddress("0.0.0.0")));
  314. host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
  315. increase(IOAddress("2001:db8:2::1"),
  316. i)));
  317. cfg.add(host);
  318. }
  319. for (unsigned i = 0; i < 25; ++i) {
  320. // Retrieve host by (subnet-id,address).
  321. HostPtr host = cfg.get6(SubnetID(1 + i % 2),
  322. increase(IOAddress("2001:db8:2::1"), i));
  323. ASSERT_TRUE(host);
  324. EXPECT_EQ(1 + i % 2, host->getIPv6SubnetID());
  325. IPv6ResrvRange reservations =
  326. host->getIPv6Reservations(IPv6Resrv::TYPE_NA);
  327. ASSERT_EQ(1, std::distance(reservations.first, reservations.second));
  328. EXPECT_EQ(increase(IOAddress("2001:db8:2::1"), i),
  329. reservations.first->second.getPrefix());
  330. }
  331. }
  332. // This test checks that the IPv6 reservations can be retrieved for a particular
  333. // (subnet-id, address) tuple.
  334. TEST_F(CfgHostsTest, get6MultipleAddrs) {
  335. CfgHosts cfg;
  336. // Add 25 hosts. Each host has reservations for 5 addresses.
  337. for (unsigned i = 0; i < 25; ++i) {
  338. // Add host identified by DUID.
  339. HostPtr host = HostPtr(new Host(duids_[i]->toText(), "duid",
  340. SubnetID(0), SubnetID(1 + i % 2),
  341. IOAddress("0.0.0.0")));
  342. // Generate 5 unique addresses for this host.
  343. for (int j = 0; j < 5; ++j) {
  344. std::stringstream tmp;
  345. tmp << "2001:db8:" << i << "::" << j;
  346. host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, tmp.str()));
  347. }
  348. cfg.add(host);
  349. }
  350. // We don't care about HW/MAC addresses for now.
  351. HWAddrPtr hwaddr_not_used;
  352. // Now check if we can retrieve each of those 25 hosts by using each
  353. // of their addresses.
  354. for (unsigned i = 0; i < 25; ++i) {
  355. // Check that the host is there.
  356. HostPtr by_duid = cfg.get6(SubnetID(1 + i % 2), duids_[i], hwaddr_not_used);
  357. ASSERT_TRUE(by_duid);
  358. for (unsigned j = 0; j < 5; ++j) {
  359. std::stringstream tmp;
  360. tmp << "2001:db8:" << i << "::" << j;
  361. // Retrieve host by (subnet-id,address).
  362. HostPtr by_addr = cfg.get6(SubnetID(1 + i % 2), tmp.str());
  363. ASSERT_TRUE(by_addr);
  364. // The pointers should match. Maybe we should compare contents
  365. // rather than just pointers? I think there's no reason why
  366. // the code would make any copies of the Host object, so
  367. // the pointers should always point to the same object.
  368. EXPECT_EQ(by_duid, by_addr);
  369. }
  370. }
  371. }
  372. // Checks that it's not possible for a second host to reserve an address
  373. // which is already reserved.
  374. TEST_F(CfgHostsTest, add4AlreadyReserved) {
  375. CfgHosts cfg;
  376. // First host has a reservation for address 192.0.2.1
  377. HostPtr host1 = HostPtr(new Host(hwaddrs_[0]->toText(false),
  378. "hw-address",
  379. SubnetID(1), SubnetID(0),
  380. IOAddress("192.0.2.1")));
  381. // Adding this should work.
  382. EXPECT_NO_THROW(cfg.add(host1));
  383. // The second host has a reservation for the same address.
  384. HostPtr host2 = HostPtr(new Host(hwaddrs_[1]->toText(false),
  385. "hw-address",
  386. SubnetID(1), SubnetID(0),
  387. IOAddress("192.0.2.1")));
  388. // This second host has a reservation for an address that is already
  389. // reserved for the first host, so it should be rejected.
  390. EXPECT_THROW(cfg.add(host2), isc::dhcp::ReservedAddress);
  391. }
  392. // Checks that it's not possible for two hosts to have the same address
  393. // reserved at the same time.
  394. TEST_F(CfgHostsTest, add6Invalid2Hosts) {
  395. CfgHosts cfg;
  396. // First host has a reservation for address 2001:db8::1
  397. HostPtr host1 = HostPtr(new Host(duids_[0]->toText(), "duid",
  398. SubnetID(0), SubnetID(1),
  399. IOAddress("0.0.0.0")));
  400. host1->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
  401. IOAddress("2001:db8::1")));
  402. // Adding this should work.
  403. EXPECT_NO_THROW(cfg.add(host1));
  404. // The second host has a reservation for the same address.
  405. HostPtr host2 = HostPtr(new Host(duids_[1]->toText(), "duid",
  406. SubnetID(0), SubnetID(1),
  407. IOAddress("0.0.0.0")));
  408. host2->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
  409. IOAddress("2001:db8::1")));
  410. // This second host has a reservation for an address that is already
  411. // reserved for the first host, so it should be rejected.
  412. EXPECT_THROW(cfg.add(host2), isc::dhcp::DuplicateHost);
  413. }
  414. TEST_F(CfgHostsTest, zeroSubnetIDs) {
  415. CfgHosts cfg;
  416. ASSERT_THROW(cfg.add(HostPtr(new Host(hwaddrs_[0]->toText(false),
  417. "hw-address",
  418. SubnetID(0), SubnetID(0),
  419. IOAddress("10.0.0.1")))),
  420. isc::BadValue);
  421. }
  422. // This test verifies that it is not possible to add the same Host to the
  423. // same IPv4 subnet twice.
  424. TEST_F(CfgHostsTest, duplicatesSubnet4HWAddr) {
  425. CfgHosts cfg;
  426. // Add a host.
  427. ASSERT_NO_THROW(cfg.add(HostPtr(new Host(hwaddrs_[0]->toText(false),
  428. "hw-address",
  429. SubnetID(10), SubnetID(0),
  430. IOAddress("10.0.0.1")))));
  431. // Try to add the host with the same HW address to the same subnet. The fact
  432. // that the IP address is different here shouldn't really matter.
  433. EXPECT_THROW(cfg.add(HostPtr(new Host(hwaddrs_[0]->toText(false),
  434. "hw-address",
  435. SubnetID(10), SubnetID(0),
  436. IOAddress("10.0.0.10")))),
  437. isc::dhcp::DuplicateHost);
  438. // Now try to add it to a different subnet. It should go through.
  439. EXPECT_NO_THROW(cfg.add(HostPtr(new Host(hwaddrs_[0]->toText(false),
  440. "hw-address",
  441. SubnetID(11), SubnetID(0),
  442. IOAddress("10.0.0.10")))));
  443. }
  444. // This test verifies that it is not possible to add the same Host to the
  445. // same IPv4 subnet twice.
  446. TEST_F(CfgHostsTest, duplicatesSubnet4DUID) {
  447. CfgHosts cfg;
  448. // Add a host.
  449. ASSERT_NO_THROW(cfg.add(HostPtr(new Host(duids_[0]->toText(),
  450. "duid",
  451. SubnetID(10), SubnetID(0),
  452. IOAddress("10.0.0.1")))));
  453. // Try to add the host with the same DUID to the same subnet. The fact
  454. // that the IP address is different here shouldn't really matter.
  455. EXPECT_THROW(cfg.add(HostPtr(new Host(duids_[0]->toText(),
  456. "duid",
  457. SubnetID(10), SubnetID(0),
  458. IOAddress("10.0.0.10")))),
  459. isc::dhcp::DuplicateHost);
  460. // Now try to add it to a different subnet. It should go through.
  461. EXPECT_NO_THROW(cfg.add(HostPtr(new Host(duids_[0]->toText(),
  462. "duid",
  463. SubnetID(11), SubnetID(0),
  464. IOAddress("10.0.0.10")))));
  465. }
  466. // This test verifies that it is not possible to add the same Host to the
  467. // same IPv6 subnet twice.
  468. TEST_F(CfgHostsTest, duplicatesSubnet6HWAddr) {
  469. CfgHosts cfg;
  470. // Add a host.
  471. ASSERT_NO_THROW(cfg.add(HostPtr(new Host(hwaddrs_[0]->toText(false),
  472. "hw-address",
  473. SubnetID(0), SubnetID(1),
  474. IOAddress("0.0.0.0"),
  475. "foo.example.com"))));
  476. // Try to add the host with the same HW address to the same subnet. The fact
  477. // that the IP address is different here shouldn't really matter.
  478. EXPECT_THROW(cfg.add(HostPtr(new Host(hwaddrs_[0]->toText(false),
  479. "hw-address",
  480. SubnetID(0), SubnetID(1),
  481. IOAddress("0.0.0.0"),
  482. "foo.example.com"))),
  483. isc::dhcp::DuplicateHost);
  484. // Now try to add it to a different subnet. It should go through.
  485. EXPECT_NO_THROW(cfg.add(HostPtr(new Host(hwaddrs_[0]->toText(false),
  486. "hw-address",
  487. SubnetID(0), SubnetID(2),
  488. IOAddress("0.0.0.0"),
  489. "foo.example.com"))));
  490. }
  491. // This test verifies that it is not possible to add the same Host to the
  492. // same IPv6 subnet twice.
  493. TEST_F(CfgHostsTest, duplicatesSubnet6DUID) {
  494. CfgHosts cfg;
  495. // Add a host.
  496. ASSERT_NO_THROW(cfg.add(HostPtr(new Host(duids_[0]->toText(),
  497. "duid",
  498. SubnetID(0), SubnetID(1),
  499. IOAddress("0.0.0.0"),
  500. "foo.example.com"))));
  501. // Try to add the host with the same DUID to the same subnet. The fact
  502. // that the IP address is different here shouldn't really matter.
  503. EXPECT_THROW(cfg.add(HostPtr(new Host(duids_[0]->toText(),
  504. "duid",
  505. SubnetID(0), SubnetID(1),
  506. IOAddress("0.0.0.0"),
  507. "foo.example.com"))),
  508. isc::dhcp::DuplicateHost);
  509. // Now try to add it to a different subnet. It should go through.
  510. EXPECT_NO_THROW(cfg.add(HostPtr(new Host(duids_[0]->toText(),
  511. "duid",
  512. SubnetID(0), SubnetID(2),
  513. IOAddress("0.0.0.0"),
  514. "foo.example.com"))));
  515. }
  516. } // end of anonymous namespace