dora_unittest.cc 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077
  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 <cc/data.h>
  17. #include <dhcp/dhcp4.h>
  18. #include <dhcp/tests/iface_mgr_test_config.h>
  19. #include <dhcpsrv/cfgmgr.h>
  20. #include <dhcpsrv/host.h>
  21. #include <dhcpsrv/host_mgr.h>
  22. #include <dhcpsrv/subnet_id.h>
  23. #include <dhcp4/tests/dhcp4_test_utils.h>
  24. #include <dhcp4/tests/dhcp4_client.h>
  25. #include <boost/shared_ptr.hpp>
  26. #include <stats/stats_mgr.h>
  27. using namespace isc;
  28. using namespace isc::asiolink;
  29. using namespace isc::data;
  30. using namespace isc::dhcp;
  31. using namespace isc::dhcp::test;
  32. namespace {
  33. /// @brief Set of JSON configurations used throughout the DORA tests.
  34. ///
  35. /// - Configuration 0:
  36. /// - Used for testing direct traffic
  37. /// - 1 subnet: 10.0.0.0/24
  38. /// - 1 pool: 10.0.0.10-10.0.0.100
  39. /// - Router option present: 10.0.0.200 and 10.0.0.201
  40. /// - Domain Name Server option present: 10.0.0.202, 10.0.0.203.
  41. /// - Log Servers option present: 192.0.2.200 and 192.0.2.201
  42. /// - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
  43. ///
  44. /// - Configuration 1:
  45. /// - Use for testing relayed messages
  46. /// - 1 subnet: 192.0.2.0/24
  47. /// - Router option present: 192.0.2.200 and 192.0.2.201
  48. /// - Domain Name Server option present: 192.0.2.202, 192.0.2.203.
  49. /// - Log Servers option present: 192.0.2.200 and 192.0.2.201
  50. /// - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
  51. ///
  52. /// - Configuration 2:
  53. /// - Use for testing simple scenarios with host reservations
  54. /// - 1 subnet: 10.0.0.0/24
  55. /// - One reservation for the client using MAC address:
  56. /// aa:bb:cc:dd:ee:ff, reserved address 10.0.0.7
  57. const char* DORA_CONFIGS[] = {
  58. // Configuration 0
  59. "{ \"interfaces-config\": {"
  60. " \"interfaces\": [ \"*\" ]"
  61. "},"
  62. "\"valid-lifetime\": 600,"
  63. "\"subnet4\": [ { "
  64. " \"subnet\": \"10.0.0.0/24\", "
  65. " \"id\": 1,"
  66. " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
  67. " \"option-data\": [ {"
  68. " \"name\": \"routers\","
  69. " \"code\": 3,"
  70. " \"data\": \"10.0.0.200,10.0.0.201\","
  71. " \"csv-format\": true,"
  72. " \"space\": \"dhcp4\""
  73. " },"
  74. " {"
  75. " \"name\": \"domain-name-servers\","
  76. " \"code\": 6,"
  77. " \"data\": \"10.0.0.202,10.0.0.203\","
  78. " \"csv-format\": true,"
  79. " \"space\": \"dhcp4\""
  80. " },"
  81. " {"
  82. " \"name\": \"log-servers\","
  83. " \"code\": 7,"
  84. " \"data\": \"10.0.0.200,10.0.0.201\","
  85. " \"csv-format\": true,"
  86. " \"space\": \"dhcp4\""
  87. " },"
  88. " {"
  89. " \"name\": \"cookie-servers\","
  90. " \"code\": 8,"
  91. " \"data\": \"10.0.0.202,10.0.0.203\","
  92. " \"csv-format\": true,"
  93. " \"space\": \"dhcp4\""
  94. " } ]"
  95. " } ]"
  96. "}",
  97. // Configuration 1
  98. "{ \"interfaces-config\": {"
  99. " \"interfaces\": [ \"*\" ]"
  100. "},"
  101. "\"valid-lifetime\": 600,"
  102. "\"subnet4\": [ { "
  103. " \"subnet\": \"192.0.2.0/24\", "
  104. " \"option-data\": [ {"
  105. " \"name\": \"routers\","
  106. " \"code\": 3,"
  107. " \"data\": \"192.0.2.200,192.0.2.201\","
  108. " \"csv-format\": true,"
  109. " \"space\": \"dhcp4\""
  110. " },"
  111. " {"
  112. " \"name\": \"domain-name-servers\","
  113. " \"code\": 6,"
  114. " \"data\": \"192.0.2.202,192.0.2.203\","
  115. " \"csv-format\": true,"
  116. " \"space\": \"dhcp4\""
  117. " },"
  118. " {"
  119. " \"name\": \"log-servers\","
  120. " \"code\": 7,"
  121. " \"data\": \"10.0.0.200,10.0.0.201\","
  122. " \"csv-format\": true,"
  123. " \"space\": \"dhcp4\""
  124. " },"
  125. " {"
  126. " \"name\": \"cookie-servers\","
  127. " \"code\": 8,"
  128. " \"data\": \"10.0.0.202,10.0.0.203\","
  129. " \"csv-format\": true,"
  130. " \"space\": \"dhcp4\""
  131. " } ]"
  132. " } ]"
  133. "}",
  134. // Configuration 2
  135. "{ \"interfaces-config\": {"
  136. " \"interfaces\": [ \"*\" ]"
  137. "},"
  138. "\"valid-lifetime\": 600,"
  139. "\"subnet4\": [ { "
  140. " \"subnet\": \"10.0.0.0/24\", "
  141. " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
  142. " \"reservations\": [ "
  143. " {"
  144. " \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
  145. " \"ip-address\": \"10.0.0.7\""
  146. " }"
  147. " ]"
  148. "} ]"
  149. "}"
  150. };
  151. /// @brief Test fixture class for testing 4-way (DORA) exchanges.
  152. ///
  153. /// @todo Currently there is a limit number of test cases covered here.
  154. /// In the future it is planned that the tests from the
  155. /// dhcp4_srv_unittest.cc will be migrated here and will use the
  156. /// @c Dhcp4Client class.
  157. class DORATest : public Dhcpv4SrvTest {
  158. public:
  159. /// @brief Constructor.
  160. ///
  161. /// Sets up fake interfaces.
  162. DORATest()
  163. : Dhcpv4SrvTest(),
  164. iface_mgr_test_config_(true) {
  165. IfaceMgr::instance().openSockets4();
  166. // Let's wipe all existing statistics.
  167. isc::stats::StatsMgr::instance().removeAll();
  168. }
  169. /// @brief Desctructor.
  170. ///
  171. /// Cleans up statistics after the test.
  172. ~DORATest() {
  173. // Let's wipe all existing statistics.
  174. isc::stats::StatsMgr::instance().removeAll();
  175. }
  176. /// @brief Test that server doesn't allocate the lease for a client
  177. /// which has the same address or client identifier as another client.
  178. ///
  179. /// This test checks the server's behavior in the following scenario:
  180. /// - Client A identifies itself to the server using the hardware address
  181. /// and client identifier or only one of those.
  182. /// - Client A performs the 4-way exchange and obtains a lease from the server.
  183. /// - Client B uses the same HW address or client identifier as the client A.
  184. /// - Client B uses both HW address and client identifier if the client A is using
  185. /// only one of them. Client B uses one of the HW address or client
  186. /// identifier if the client A is using both.
  187. /// - Client B sends the DHCPDISCOVER to the server.
  188. /// The server determines that there is a lease for the client A using the
  189. /// same HW address as the client B. Server discards the client's message and
  190. /// doesn't offer the lease for the client B to prevent allocation of the
  191. /// lease without a unique identifier.
  192. /// - The client sends the DHCPREQUEST and the server sends the DHCPNAK for the
  193. /// same reason.
  194. /// - The client A renews its address successfully.
  195. ///
  196. /// The specific test cases using this test must make sure that one of the
  197. /// provided parameters is an empty string. This simulates the situation where
  198. /// one of the clients has only one of the identifiers and the other one has
  199. /// two.
  200. ///
  201. /// @param hwaddr_a HW address of client A.
  202. /// @param clientid_a Client id of client A.
  203. /// @param hwaddr_b HW address of client B.
  204. /// @param clientid_b Client id of client B.
  205. void oneAllocationOverlapTest(const std::string& hwaddr_a,
  206. const std::string& clientid_a,
  207. const std::string& hwaddr_b,
  208. const std::string& clientid_b);
  209. /// @brief Test that server can allocate the lease for a client having
  210. /// the same HW Address or client id as another client.
  211. ///
  212. /// This test checks the server behavior in the following situation:
  213. /// - Client A identifies itself to the server using client identifier
  214. /// and the hardware address and requests allocation of the new lease.
  215. /// - Server allocates the lease to the client.
  216. /// - Client B has a different hardware address or client identifier than
  217. /// the client A, but the other identifier is equal to the corresponding
  218. /// identifier of the client A.
  219. /// - Client B sends DHCPDISCOVER.
  220. /// - Server should determine that the client B is not client A, because
  221. /// it is using a different hadrware address or client identifier.
  222. /// As a consequence, the server should offer a different address to the
  223. /// client B.
  224. /// - The client B performs the 4-way exchange again, and the server
  225. /// allocates a new address to the client, which should be different
  226. /// than the address used by the client A.
  227. /// - Client B is in the renewing state and it successfully renews its
  228. /// address.
  229. /// - The client A also renews its address successfully.
  230. ///
  231. /// @param hwaddr_a HW address of client A.
  232. /// @param clientid_a Client id of client A.
  233. /// @param hwaddr_b HW address of client B.
  234. /// @param clientid_b Client id of client B.
  235. void twoAllocationsOverlapTest(const std::string& hwaddr_a,
  236. const std::string& clientid_a,
  237. const std::string& hwaddr_b,
  238. const std::string& clientid_b);
  239. /// @brief Interface Manager's fake configuration control.
  240. IfaceMgrTestConfig iface_mgr_test_config_;
  241. };
  242. /// This test verifies that the client in the SELECTING state can get
  243. /// an address when it doesn't request any specific address in the
  244. /// DHCPDISCOVER message.
  245. TEST_F(DORATest, selectingDoNotRequestAddress) {
  246. Dhcp4Client client(Dhcp4Client::SELECTING);
  247. // Configure DHCP server.
  248. configure(DORA_CONFIGS[0], *client.getServer());
  249. // Perform 4-way exchange with the server but to not request any
  250. // specific address in the DHCPDISCOVER message.
  251. ASSERT_NO_THROW(client.doDORA());
  252. // Make sure that the server responded.
  253. ASSERT_TRUE(client.getContext().response_);
  254. Pkt4Ptr resp = client.getContext().response_;
  255. // Make sure that the server has responded with DHCPACK.
  256. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  257. // Response must not be relayed.
  258. EXPECT_FALSE(resp->isRelayed());
  259. // Make sure that the server id is present.
  260. EXPECT_EQ("10.0.0.1", client.config_.serverid_.toText());
  261. // Make sure that the client has got the lease with the requested address.
  262. ASSERT_NE(client.config_.lease_.addr_.toText(), "0.0.0.0");
  263. }
  264. /// This test verifies that multiple clients may use the DHCPv4 server
  265. /// and obtain unique leases.
  266. TEST_F(DORATest, selectingMultipleClients) {
  267. Dhcp4Client client(Dhcp4Client::SELECTING);
  268. // Configure DHCP server.
  269. configure(DORA_CONFIGS[0], *client.getServer());
  270. // Get the first lease.
  271. ASSERT_NO_THROW(client.doDORA());
  272. // Make sure that the server responded.
  273. Pkt4Ptr resp = client.getContext().response_;
  274. ASSERT_TRUE(resp);
  275. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  276. // Store the lease.
  277. Lease4 lease1 = client.config_.lease_;
  278. // Get the lease for a different client.
  279. client.modifyHWAddr();
  280. ASSERT_NO_THROW(client.doDORA());
  281. // Make sure that the server responded.
  282. resp = client.getContext().response_;
  283. ASSERT_TRUE(resp);
  284. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  285. // Store the lease.
  286. Lease4 lease2 = client.config_.lease_;
  287. // Get the lease for a different client.
  288. client.modifyHWAddr();
  289. ASSERT_NO_THROW(client.doDORA());
  290. // Make sure that the server responded.
  291. resp = client.getContext().response_;
  292. ASSERT_TRUE(resp);
  293. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  294. // Store the lease.
  295. Lease4 lease3 = client.config_.lease_;
  296. // Make sure that unique addresses have been assigned.
  297. EXPECT_NE(lease1.addr_, lease2.addr_);
  298. EXPECT_NE(lease2.addr_, lease3.addr_);
  299. EXPECT_NE(lease1.addr_, lease3.addr_);
  300. }
  301. // This test verifies that the client in a SELECTING state can request
  302. // a specific address and that this address will be assigned when
  303. // available. It also tests that if the client requests an address which
  304. // is in use the client will get a different address.
  305. TEST_F(DORATest, selectingRequestAddress) {
  306. Dhcp4Client client(Dhcp4Client::SELECTING);
  307. // Configure DHCP server.
  308. configure(DORA_CONFIGS[0], *client.getServer());
  309. // Perform 4-way exchange with the server.
  310. ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
  311. IOAddress>(new IOAddress("10.0.0.50"))));
  312. // Make sure that the server responded.
  313. ASSERT_TRUE(client.getContext().response_);
  314. Pkt4Ptr resp = client.getContext().response_;
  315. // Make sure that the server has responded with DHCPACK.
  316. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  317. // Response must not be relayed.
  318. EXPECT_FALSE(resp->isRelayed());
  319. // Make sure that the server id is present.
  320. EXPECT_EQ("10.0.0.1", client.config_.serverid_.toText());
  321. // Make sure that the client has got the lease with the requested address.
  322. ASSERT_EQ("10.0.0.50", client.config_.lease_.addr_.toText());
  323. // Simulate different client requesting the same address.
  324. client.modifyHWAddr();
  325. ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
  326. IOAddress>(new IOAddress("10.0.0.50"))));
  327. resp = client.getContext().response_;
  328. // Make sure that the server responded.
  329. ASSERT_TRUE(resp);
  330. // Make sure that the server has responded with DHCPACK.
  331. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  332. // Response must not be relayed.
  333. EXPECT_FALSE(resp->isRelayed());
  334. // Make sure that the server id is present.
  335. EXPECT_EQ("10.0.0.1", client.config_.serverid_.toText());
  336. // Make sure that the client has got some address.
  337. EXPECT_NE(client.config_.lease_.addr_.toText(), "0.0.0.0");
  338. // Make sure that the client has got a different address than requested
  339. // as the requested one is already in use.
  340. EXPECT_NE(client.config_.lease_.addr_.toText(), "10.0.0.50");
  341. }
  342. // This test verifies that the client will get the address that it has
  343. // been allocated when the client requests a different address.
  344. TEST_F(DORATest, selectingRequestNonMatchingAddress) {
  345. Dhcp4Client client(Dhcp4Client::SELECTING);
  346. // Configure DHCP server.
  347. configure(DORA_CONFIGS[0], *client.getServer());
  348. // Perform 4-way exchange with the server.
  349. ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
  350. IOAddress>(new IOAddress("10.0.0.50"))));
  351. // Make sure that the server responded.
  352. ASSERT_TRUE(client.getContext().response_);
  353. Pkt4Ptr resp = client.getContext().response_;
  354. // Make sure that the server has responded with DHCPACK.
  355. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  356. // Response must not be relayed.
  357. EXPECT_FALSE(resp->isRelayed());
  358. // Make sure that the server id is present.
  359. EXPECT_EQ("10.0.0.1", client.config_.serverid_.toText());
  360. // Make sure that the client has got the lease with the requested address.
  361. ASSERT_EQ("10.0.0.50", client.config_.lease_.addr_.toText());
  362. // Let's request a different address. The server should respond with
  363. // the one that the client already has allocated.
  364. ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
  365. IOAddress>(new IOAddress("10.0.0.80"))));
  366. // Make sure that the server responded.
  367. ASSERT_TRUE(client.getContext().response_);
  368. resp = client.getContext().response_;
  369. // Make sure that the server has responded with DHCPACK.
  370. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  371. // Response must not be relayed.
  372. EXPECT_FALSE(resp->isRelayed());
  373. // Make sure that the server id is present.
  374. EXPECT_EQ("10.0.0.1", client.config_.serverid_.toText());
  375. // Make sure that the client has got the lease with the address that
  376. // the client has recorded in the lease database.
  377. EXPECT_EQ("10.0.0.50", client.config_.lease_.addr_.toText());
  378. }
  379. // Test that the client in the INIT-REBOOT state can request the IP
  380. // address it has and the address is returned. Also, check that if
  381. // if the client requests invalid address the server sends a DHCPNAK.
  382. TEST_F(DORATest, initRebootRequest) {
  383. Dhcp4Client client(Dhcp4Client::SELECTING);
  384. // Configure DHCP server.
  385. configure(DORA_CONFIGS[0], *client.getServer());
  386. // Obtain a lease from the server using the 4-way exchange.
  387. ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
  388. IOAddress>(new IOAddress("10.0.0.50"))));
  389. // Make sure that the server responded.
  390. ASSERT_TRUE(client.getContext().response_);
  391. Pkt4Ptr resp = client.getContext().response_;
  392. // Make sure that the server has responded with DHCPACK.
  393. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  394. // Response must not be relayed.
  395. EXPECT_FALSE(resp->isRelayed());
  396. // Make sure that the server id is present.
  397. EXPECT_EQ("10.0.0.1", client.config_.serverid_.toText());
  398. // Make sure that the client has got the lease with the requested address.
  399. ASSERT_EQ("10.0.0.50", client.config_.lease_.addr_.toText());
  400. // Client has a lease in the database. Let's transition the client
  401. // to the INIT_REBOOT state so as the client can request the cached
  402. // lease using the DHCPREQUEST message.
  403. client.setState(Dhcp4Client::INIT_REBOOT);
  404. ASSERT_NO_THROW(client.doRequest());
  405. // Make sure that the server responded.
  406. ASSERT_TRUE(client.getContext().response_);
  407. resp = client.getContext().response_;
  408. // Make sure that the server has responded with DHCPACK.
  409. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  410. // Response must not be relayed.
  411. EXPECT_FALSE(resp->isRelayed());
  412. // Make sure that the server id is present.
  413. EXPECT_EQ("10.0.0.1", client.config_.serverid_.toText());
  414. // Make sure that the client has got the lease with the requested address.
  415. ASSERT_EQ("10.0.0.50", client.config_.lease_.addr_.toText());
  416. // Try to request a different address than the client has. The server
  417. // should respond with DHCPNAK.
  418. client.config_.lease_.addr_ = IOAddress("10.0.0.30");
  419. ASSERT_NO_THROW(client.doRequest());
  420. // Make sure that the server responded.
  421. ASSERT_TRUE(client.getContext().response_);
  422. resp = client.getContext().response_;
  423. EXPECT_EQ(DHCPNAK, static_cast<int>(resp->getType()));
  424. // Try to request from a different client.
  425. client.modifyHWAddr();
  426. ASSERT_NO_THROW(client.doRequest());
  427. // The server should not respond.
  428. EXPECT_FALSE(client.getContext().response_);
  429. }
  430. // Check that the ciaddr returned by the server is correct for DHCPOFFER and
  431. // DHCPNAK according to RFC2131, section 4.3.1.
  432. TEST_F(DORATest, ciaddr) {
  433. Dhcp4Client client(Dhcp4Client::SELECTING);
  434. // Configure DHCP server.
  435. configure(DORA_CONFIGS[0], *client.getServer());
  436. // Force ciaddr of Discover message to be non-zero.
  437. client.ciaddr_.specify(IOAddress("10.0.0.50"));
  438. // Obtain a lease from the server using the 4-way exchange.
  439. ASSERT_NO_THROW(client.doDiscover(boost::shared_ptr<
  440. IOAddress>(new IOAddress("10.0.0.50"))));
  441. // Make sure that the server responded.
  442. ASSERT_TRUE(client.getContext().response_);
  443. Pkt4Ptr resp = client.getContext().response_;
  444. // Make sure that the server has responded with DHCPOFFER.
  445. ASSERT_EQ(DHCPOFFER, static_cast<int>(resp->getType()));
  446. // Make sure ciaddr is not set for DHCPOFFER.
  447. EXPECT_EQ("0.0.0.0", resp->getCiaddr().toText());
  448. // Obtain a lease from the server using the 4-way exchange.
  449. ASSERT_NO_THROW(client.doRequest());
  450. // Make sure that the server responded.
  451. ASSERT_TRUE(client.getContext().response_);
  452. resp = client.getContext().response_;
  453. // Make sure that the server has responded with DHCPACK.
  454. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  455. // Let's transition the client to Renewing state.
  456. client.setState(Dhcp4Client::RENEWING);
  457. // Set the unicast destination address to indicate that it is a renewal.
  458. client.setDestAddress(IOAddress("10.0.0.1"));
  459. ASSERT_NO_THROW(client.doRequest());
  460. // The client is sending invalid ciaddr so the server should send a NAK.
  461. resp = client.getContext().response_;
  462. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  463. // For DHCPACK the ciaddr may be 0 or may be set to the ciaddr value
  464. // from the client's message. Kea sets it to the latter.
  465. EXPECT_EQ("10.0.0.50", resp->getCiaddr().toText());
  466. // Replace the address held by the client. The client will request
  467. // the assignment of this address but the server has a different
  468. // address for this client.
  469. client.ciaddr_.specify(IOAddress("192.168.0.30"));
  470. ASSERT_NO_THROW(client.doRequest());
  471. // The client is sending invalid ciaddr so the server should send a NAK.
  472. resp = client.getContext().response_;
  473. ASSERT_EQ(DHCPNAK, static_cast<int>(resp->getType()));
  474. // For DHCPNAK the ciaddr is always 0 (should not be copied) from the
  475. // client's message.
  476. EXPECT_EQ("0.0.0.0", resp->getCiaddr().toText());
  477. }
  478. void
  479. DORATest::twoAllocationsOverlapTest(const std::string& hwaddr_a,
  480. const std::string& clientid_a,
  481. const std::string& hwaddr_b,
  482. const std::string& clientid_b) {
  483. // Allocate a lease by client A using the 4-way exchange.
  484. Dhcp4Client client_a(Dhcp4Client::SELECTING);
  485. client_a.includeClientId(clientid_a);
  486. client_a.setHWAddress(hwaddr_a);
  487. configure(DORA_CONFIGS[0], *client_a.getServer());
  488. ASSERT_NO_THROW(client_a.doDORA());
  489. // Make sure that the server responded.
  490. ASSERT_TRUE(client_a.getContext().response_);
  491. Pkt4Ptr resp_a = client_a.getContext().response_;
  492. // Make sure that the server has responded with DHCPACK.
  493. ASSERT_EQ(DHCPACK, static_cast<int>(resp_a->getType()));
  494. // Make sure that the lease has been recorded by the server.
  495. Lease4Ptr lease_a = LeaseMgrFactory::instance().getLease4(client_a.config_.lease_.addr_);
  496. ASSERT_TRUE(lease_a);
  497. // Create client B.
  498. Dhcp4Client client_b(client_a.getServer(), Dhcp4Client::SELECTING);
  499. client_b.setHWAddress(hwaddr_b);
  500. client_b.includeClientId(clientid_b);
  501. // Send DHCPDISCOVER and expect the response.
  502. ASSERT_NO_THROW(client_b.doDiscover());
  503. Pkt4Ptr resp_b = client_b.getContext().response_;
  504. // Make sure that the server has responded with DHCPOFFER.
  505. ASSERT_EQ(DHCPOFFER, static_cast<int>(resp_b->getType()));
  506. // The offered address should be different than the address which
  507. // was obtained by the client A.
  508. ASSERT_NE(resp_b->getYiaddr(), client_a.config_.lease_.addr_);
  509. // Make sure that the client A lease hasn't been modified.
  510. lease_a = LeaseMgrFactory::instance().getLease4(client_a.config_.lease_.addr_);
  511. ASSERT_TRUE(lease_a);
  512. // Now that we know that the server will avoid assigning the same
  513. // address that the client A has, use the 4-way exchange to actually
  514. // allocate some address.
  515. ASSERT_NO_THROW(client_b.doDORA());
  516. // Make sure that the server responded.
  517. ASSERT_TRUE(client_b.getContext().response_);
  518. resp_b = client_b.getContext().response_;
  519. // Make sure that the server has responded with DHCPACK.
  520. ASSERT_EQ(DHCPACK, static_cast<int>(resp_b->getType()));
  521. // Again, make sure the assigned addresses are different.
  522. ASSERT_NE(client_b.config_.lease_.addr_, client_a.config_.lease_.addr_);
  523. // Make sure that the client A still has a lease.
  524. lease_a = LeaseMgrFactory::instance().getLease4(client_a.config_.lease_.addr_);
  525. ASSERT_TRUE(lease_a);
  526. // Make sure that the client B has a lease.
  527. Lease4Ptr lease_b = LeaseMgrFactory::instance().getLease4(client_b.config_.lease_.addr_);
  528. ASSERT_TRUE(lease_b);
  529. // Client B should be able to renew its address.
  530. client_b.setState(Dhcp4Client::RENEWING);
  531. ASSERT_NO_THROW(client_b.doRequest());
  532. ASSERT_TRUE(client_b.getContext().response_);
  533. resp_b = client_b.getContext().response_;
  534. ASSERT_EQ(DHCPACK, static_cast<int>(resp_b->getType()));
  535. ASSERT_NE(client_b.config_.lease_.addr_, client_a.config_.lease_.addr_);
  536. // Client A should also be able to renew its address.
  537. client_a.setState(Dhcp4Client::RENEWING);
  538. ASSERT_NO_THROW(client_a.doRequest());
  539. ASSERT_TRUE(client_a.getContext().response_);
  540. resp_b = client_a.getContext().response_;
  541. ASSERT_EQ(DHCPACK, static_cast<int>(resp_b->getType()));
  542. ASSERT_NE(client_a.config_.lease_.addr_, client_b.config_.lease_.addr_);
  543. }
  544. void
  545. DORATest::oneAllocationOverlapTest(const std::string& hwaddr_a,
  546. const std::string& clientid_a,
  547. const std::string& hwaddr_b,
  548. const std::string& clientid_b) {
  549. // Allocate a lease by client A using the 4-way exchange.
  550. Dhcp4Client client_a(Dhcp4Client::SELECTING);
  551. client_a.includeClientId(clientid_a);
  552. client_a.setHWAddress(hwaddr_a);
  553. configure(DORA_CONFIGS[0], *client_a.getServer());
  554. ASSERT_NO_THROW(client_a.doDORA());
  555. // Make sure that the server responded.
  556. ASSERT_TRUE(client_a.getContext().response_);
  557. Pkt4Ptr resp_a = client_a.getContext().response_;
  558. // Make sure that the server has responded with DHCPACK.
  559. ASSERT_EQ(DHCPACK, static_cast<int>(resp_a->getType()));
  560. Lease4Ptr lease_a = LeaseMgrFactory::instance().getLease4(client_a.config_.lease_.addr_);
  561. ASSERT_TRUE(lease_a);
  562. // Client B sends a DHCPDISCOVER.
  563. Dhcp4Client client_b(client_a.getServer(), Dhcp4Client::SELECTING);
  564. client_b.setHWAddress(hwaddr_b);
  565. client_b.includeClientId(clientid_b);
  566. // Client A and Client B have one common identifier (HW address
  567. // or client identifier) and one of them is missing the other
  568. // identifier. The allocation engine can't offer an address for
  569. // the client which has the same identifier as the other client and
  570. // which doesn't have any other (unique) identifier. It should
  571. // discard the DHCPDISCOVER.
  572. ASSERT_NO_THROW(client_b.doDiscover());
  573. Pkt4Ptr resp_b = client_b.getContext().response_;
  574. ASSERT_FALSE(resp_b);
  575. // Now repeat the same test but send the DHCPREQUEST. This time the
  576. // server should send the DHCPNAK.
  577. client_b.config_.lease_.addr_ = IOAddress::IPV4_ZERO_ADDRESS();
  578. client_b.setState(Dhcp4Client::INIT_REBOOT);
  579. ASSERT_NO_THROW(client_b.doRequest());
  580. resp_b = client_b.getContext().response_;
  581. ASSERT_TRUE(resp_b);
  582. ASSERT_EQ(DHCPNAK, static_cast<int>(resp_b->getType()));
  583. // Client A should also be able to renew its address.
  584. client_a.setState(Dhcp4Client::RENEWING);
  585. ASSERT_NO_THROW(client_a.doRequest());
  586. ASSERT_TRUE(client_a.getContext().response_);
  587. resp_b = client_a.getContext().response_;
  588. ASSERT_EQ(DHCPACK, static_cast<int>(resp_b->getType()));
  589. ASSERT_NE(client_a.config_.lease_.addr_, client_b.config_.lease_.addr_);
  590. }
  591. // This test checks the server behavior in the following situation:
  592. // - Client A identifies itself to the server using client identifier
  593. // and the hardware address and requests allocation of the new lease.
  594. // - Server allocates the lease to the client.
  595. // - Client B has a different hardware address but is using the same
  596. // client identifier as Client A.
  597. // - Client B sends DHCPDISCOVER.
  598. // - Server should determine that the client B is not client A, because
  599. // it is using a different hadrware address, even though they use the
  600. // same client identifier. As a consequence, the server should offer
  601. // a different address to the client B.
  602. // - The client B performs the 4-way exchange again and the server
  603. // allocates a new address to the client, which should be different
  604. // than the address used by the client A.
  605. // - Client B is in the renewing state and it successfully renews its
  606. // address.
  607. // - Client A also renews its address successfully.
  608. TEST_F(DORATest, twoAllocationsOverlap1) {
  609. twoAllocationsOverlapTest("01:02:03:04:05:06", "12:34",
  610. "02:02:03:03:04:04", "12:34");
  611. }
  612. // This test is similar to twoAllocationsOverlap1, but the
  613. // clients differ by client identifier.
  614. TEST_F(DORATest, twoAllocationsOverlap2) {
  615. twoAllocationsOverlapTest("01:02:03:04:05:06", "12:34",
  616. "01:02:03:04:05:06", "22:34");
  617. }
  618. // This test checks the server behavior in the following situation:
  619. // - Client A identifies itself to the server using the hardware address
  620. // and client identifier.
  621. // - Client A performs the 4-way exchange and obtains a lease from the server.
  622. // - Client B uses the same HW address as the client A, but it doesn't use
  623. // the client identifier.
  624. // - Client B sends the DHCPDISCOVER to the server.
  625. // The server determines that there is a lease for the client A using the
  626. // same HW address as the client B. Server discards the client's message and
  627. // doesn't offer the lease for the client B to prevent allocation of the
  628. // lease without a unique identifier.
  629. // - The client sends the DHCPREQUEST and the server sends the DHCPNAK for the
  630. // same reason.
  631. // - Client A renews its address successfully.
  632. TEST_F(DORATest, oneAllocationOverlap1) {
  633. oneAllocationOverlapTest("01:02:03:04:05:06", "12:34",
  634. "01:02:03:04:05:06", "");
  635. }
  636. // This test is similar to oneAllocationOverlap2 but this time the client A
  637. // uses no client identifier, and the client B uses the HW address and the
  638. // client identifier. The server behaves as previously.
  639. TEST_F(DORATest, oneAllocationOverlap2) {
  640. oneAllocationOverlapTest("01:02:03:04:05:06", "",
  641. "01:02:03:04:05:06", "12:34");
  642. }
  643. // This is a simple test for the host reservation. It creates a reservation
  644. // for an address for a single client, identified by the HW address. The
  645. // test verifies that the client using this HW address will obtain a
  646. // lease for the reserved address. It also checks that the client using
  647. // a different HW address will obtain an address from the dynamic pool.
  648. TEST_F(DORATest, reservation) {
  649. // Client A is a one which will have a reservation.
  650. Dhcp4Client clientA(Dhcp4Client::SELECTING);
  651. // Set explicit HW address so as it matches the reservation in the
  652. // configuration used below.
  653. clientA.setHWAddress("aa:bb:cc:dd:ee:ff");
  654. // Configure DHCP server.
  655. configure(DORA_CONFIGS[2], *clientA.getServer());
  656. // Client A performs 4-way exchange and should obtain a reserved
  657. // address.
  658. ASSERT_NO_THROW(clientA.doDORA(boost::shared_ptr<
  659. IOAddress>(new IOAddress("0.0.0.0"))));
  660. // Make sure that the server responded.
  661. ASSERT_TRUE(clientA.getContext().response_);
  662. Pkt4Ptr resp = clientA.getContext().response_;
  663. // Make sure that the server has responded with DHCPACK.
  664. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  665. // Make sure that the client has got the lease for the reserved address.
  666. ASSERT_EQ("10.0.0.7", clientA.config_.lease_.addr_.toText());
  667. // Client B uses the same server as Client A.
  668. Dhcp4Client clientB(clientA.getServer(), Dhcp4Client::SELECTING);
  669. // Client B has no reservation so it should get the lease from
  670. // the dynamic pool.
  671. ASSERT_NO_THROW(clientB.doDORA(boost::shared_ptr<
  672. IOAddress>(new IOAddress("0.0.0.0"))));
  673. // Make sure that the server responded.
  674. ASSERT_TRUE(clientB.getContext().response_);
  675. resp = clientB.getContext().response_;
  676. // Make sure that the server has responded with DHCPACK.
  677. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  678. // Obtain the subnet to which the returned address belongs.
  679. Subnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->
  680. selectSubnet(clientB.config_.lease_.addr_);
  681. ASSERT_TRUE(subnet);
  682. // Make sure that the address has been allocated from the dynamic pool.
  683. ASSERT_TRUE(subnet->inPool(Lease::TYPE_V4, clientB.config_.lease_.addr_));
  684. }
  685. // This test checks the following scenario:
  686. // 1. Client A performs 4-way exchange and obtains a lease from the dynamic pool.
  687. // 2. Reservation is created for the client A using an address out of the dynamic
  688. // pool.
  689. // 3. Client A renews the lease.
  690. // 4. Server responds with DHCPNAK to indicate that the client should stop using
  691. // an address for which it has a lease. Server doesn't want to renew an
  692. // address for which the client doesn't have a reservation, while it has
  693. // a reservation for a different address.
  694. // 5. Client A receives a DHCPNAK and returns to the DHCP server discovery.
  695. // 6. Client A performs a 4-way exchange with a server and the server allocates
  696. // a reserved address to the Client A.
  697. // 7. Client A renews the allocated address and the server returns a DHCPACK.
  698. // 8. Reservation for the Client A is removed.
  699. // 9. Client A renews the (previously reserved) lease and the server returns
  700. // DHCPNAK because the address in use is neither reserved nor belongs to
  701. // the dynamic pool.
  702. // 10. Client A returns to the DHCP server discovery.
  703. // 11. Client A uses 4-way exchange to obtain a lease from the dynamic pool.
  704. // 12. The new address that the Client A is using is reserved for Client B.
  705. // Client A still holds this address.
  706. // 13. Client B uses 4-way exchange to obtain a new lease.
  707. // 14. The server determines that the Client B has a reservation for the
  708. // address which is in use by Client A and offers an address different
  709. // than reserved.
  710. // 15. Client B requests the allocation of the offered address and the server
  711. // allocates this address.
  712. // 16. Client A renews the lease.
  713. // 17. The server determines that the address that Client A is using is reserved
  714. // for Client B. The server returns DHCPNAK to the Client A.
  715. // 18. Client B uses 4-way exchange to obtain the reserved lease but the lease
  716. // for the Client A hasn't been removed yet. Client B is assigned the same
  717. // address it has been using.
  718. // 19. Client A uses 4-way exchange to allocate a new lease.
  719. // 20. The server allocates a new lease from the dynamic pool but it avoids
  720. // allocating the address reserved for the Client B.
  721. // 21. Client B uses 4-way exchange to obtain a new lease.
  722. // 22. The server finally allocates a reserved address to the Client B.
  723. TEST_F(DORATest, reservationsWithConflicts) {
  724. Dhcp4Client client(Dhcp4Client::SELECTING);
  725. // Configure DHCP server.
  726. configure(DORA_CONFIGS[0], *client.getServer());
  727. // Client A performs 4-way exchange and obtains a lease from the
  728. // dynamic pool.
  729. ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
  730. IOAddress>(new IOAddress("10.0.0.50"))));
  731. // Make sure that the server responded.
  732. ASSERT_TRUE(client.getContext().response_);
  733. Pkt4Ptr resp = client.getContext().response_;
  734. // Make sure that the server has responded with DHCPACK.
  735. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  736. // Make sure that the client has got the lease with the requested address.
  737. ASSERT_EQ("10.0.0.50", client.config_.lease_.addr_.toText());
  738. configure(DORA_CONFIGS[0], false);
  739. // Reservation is created for the client A using an address out of the
  740. // dynamic pool.
  741. HostPtr host(new Host(&client.getHWAddress()->hwaddr_[0],
  742. client.getHWAddress()->hwaddr_.size(),
  743. Host::IDENT_HWADDR, SubnetID(1),
  744. SubnetID(0), IOAddress("10.0.0.9")));
  745. CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
  746. CfgMgr::instance().commit();
  747. // Let's transition the client to Renewing state.
  748. client.setState(Dhcp4Client::RENEWING);
  749. // Set the unicast destination address to indicate that it is a renewal.
  750. client.setDestAddress(IOAddress("10.0.0.1"));
  751. ASSERT_NO_THROW(client.doRequest());
  752. // Client should get the DHCPNAK from the server because the client has
  753. // a reservation for a different address that it is trying to renew.
  754. resp = client.getContext().response_;
  755. ASSERT_EQ(DHCPNAK, static_cast<int>(resp->getType()));
  756. // A conforming client would go back to the server discovery.
  757. client.setState(Dhcp4Client::SELECTING);
  758. // Obtain a lease from the server using the 4-way exchange.
  759. ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
  760. IOAddress>(new IOAddress("0.0.0.0"))));
  761. // Make sure that the server responded.
  762. ASSERT_TRUE(client.getContext().response_);
  763. resp = client.getContext().response_;
  764. // Make sure that the server has responded with DHCPACK with a reserved
  765. // address
  766. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  767. ASSERT_EQ("10.0.0.9", client.config_.lease_.addr_.toText());
  768. // Client A renews the allocated address.
  769. client.setState(Dhcp4Client::RENEWING);
  770. // Set the unicast destination address to indicate that it is a renewal.
  771. client.setDestAddress(IOAddress("10.0.0.1"));
  772. ASSERT_NO_THROW(client.doRequest());
  773. // Make sure the server responded and renewed the client's address.
  774. resp = client.getContext().response_;
  775. ASSERT_EQ("10.0.0.9", client.config_.lease_.addr_.toText());
  776. // By reconfiguring the server, we remove the existing reservations.
  777. configure(DORA_CONFIGS[0]);
  778. // Try to renew the existing lease again.
  779. ASSERT_NO_THROW(client.doRequest());
  780. // The reservation has been removed, so the server should respond with
  781. // a DHCPNAK because the address that the client is using doesn't belong
  782. // to a dynamic pool.
  783. resp = client.getContext().response_;
  784. ASSERT_EQ(DHCPNAK, static_cast<int>(resp->getType()));
  785. // A conforming client would go back to the server discovery.
  786. client.setState(Dhcp4Client::SELECTING);
  787. // Obtain a lease from the server using the 4-way exchange.
  788. ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
  789. IOAddress>(new IOAddress("0.0.0.0"))));
  790. // Make sure that the server responded.
  791. ASSERT_TRUE(client.getContext().response_);
  792. resp = client.getContext().response_;
  793. // Make sure that the server has responded with DHCPACK.
  794. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  795. // Obtain the subnet to which the returned address belongs.
  796. Subnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->
  797. selectSubnet(client.config_.lease_.addr_);
  798. ASSERT_TRUE(subnet);
  799. // Make sure that the address has been allocated from the dynamic pool.
  800. ASSERT_TRUE(subnet->inPool(Lease::TYPE_V4, client.config_.lease_.addr_));
  801. // Remember the address allocated in the dynamic pool.
  802. IOAddress in_pool_addr = client.config_.lease_.addr_;
  803. // Create Client B.
  804. Dhcp4Client clientB(client.getServer());
  805. clientB.modifyHWAddr();
  806. // Create reservation for the Client B, for the address that the
  807. // Client A is using.
  808. configure(DORA_CONFIGS[0], false);
  809. host.reset(new Host(&clientB.getHWAddress()->hwaddr_[0],
  810. clientB.getHWAddress()->hwaddr_.size(),
  811. Host::IDENT_HWADDR, SubnetID(1),
  812. SubnetID(0), in_pool_addr));
  813. CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
  814. CfgMgr::instance().commit();
  815. // Client B performs a DHCPDISCOVER.
  816. clientB.setState(Dhcp4Client::SELECTING);
  817. // The server determines that the address reserved for Client B is
  818. // in use by Client A so it offers a different address.
  819. ASSERT_NO_THROW(clientB.doDORA(boost::shared_ptr<
  820. IOAddress>(new IOAddress("0.0.0.0"))));
  821. ASSERT_TRUE(clientB.getContext().response_);
  822. ASSERT_EQ(DHCPACK, static_cast<int>(clientB.getContext().response_->getType()));
  823. IOAddress client_b_addr = clientB.config_.lease_.addr_;
  824. ASSERT_NE(client_b_addr, in_pool_addr);
  825. // Client A renews the lease.
  826. client.setState(Dhcp4Client::RENEWING);
  827. // Set the unicast destination address to indicate that it is a renewal.
  828. client.setDestAddress(IOAddress(in_pool_addr));
  829. ASSERT_NO_THROW(client.doRequest());
  830. // Client A should get a DHCPNAK because it is using an address reserved
  831. // for Client B.
  832. resp = client.getContext().response_;
  833. ASSERT_EQ(DHCPNAK, static_cast<int>(resp->getType()));
  834. // Client B performs 4-way exchange but still gets an address from the
  835. // dynamic pool, because Client A hasn't obtained a new lease, so it is
  836. // still using an address reserved for Client B.
  837. clientB.setState(Dhcp4Client::SELECTING);
  838. // Obtain a lease from the server using the 4-way exchange.
  839. ASSERT_NO_THROW(clientB.doDORA(boost::shared_ptr<
  840. IOAddress>(new IOAddress("0.0.0.0"))));
  841. // Make sure that the server responded.
  842. ASSERT_TRUE(clientB.getContext().response_);
  843. ASSERT_EQ(DHCPACK, static_cast<int>(clientB.getContext().response_->getType()));
  844. ASSERT_NE(clientB.config_.lease_.addr_, in_pool_addr);
  845. ASSERT_EQ(client_b_addr, clientB.config_.lease_.addr_);
  846. // Client B renews its lease.
  847. clientB.setState(Dhcp4Client::RENEWING);
  848. clientB.setDestAddress(IOAddress("10.0.0.1"));
  849. ASSERT_NO_THROW(clientB.doRequest());
  850. // The server should renew the client's B lease because the address
  851. // reserved for client B is still in use by the client A.
  852. ASSERT_TRUE(clientB.getContext().response_);
  853. EXPECT_EQ(DHCPACK, static_cast<int>(clientB.getContext().response_->getType()));
  854. ASSERT_NE(clientB.config_.lease_.addr_, in_pool_addr);
  855. ASSERT_EQ(client_b_addr, clientB.config_.lease_.addr_);
  856. // Client A performs 4-way exchange.
  857. client.setState(Dhcp4Client::SELECTING);
  858. // Revert to the broadcast address for the selcting client.
  859. client.setDestAddress(IOAddress::IPV4_BCAST_ADDRESS());
  860. // Obtain a lease from the server using the 4-way exchange.
  861. ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
  862. IOAddress>(new IOAddress("0.0.0.0"))));
  863. // Make sure that the server responded.
  864. ASSERT_TRUE(client.getContext().response_);
  865. resp = client.getContext().response_;
  866. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  867. // The server should have assigned a different address than the one
  868. // reserved for the Client B.
  869. ASSERT_NE(client.config_.lease_.addr_, in_pool_addr);
  870. subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->
  871. selectSubnet(client.config_.lease_.addr_);
  872. ASSERT_TRUE(subnet);
  873. ASSERT_TRUE(subnet->inPool(Lease::TYPE_V4, client.config_.lease_.addr_));
  874. // Client B renews again.
  875. ASSERT_NO_THROW(clientB.doRequest());
  876. // The client B should now receive the DHCPNAK from the server because
  877. // the reserved address is now available and the client should
  878. // revert to the DHCPDISCOVER to obtain it.
  879. ASSERT_TRUE(clientB.getContext().response_);
  880. EXPECT_EQ(DHCPNAK, static_cast<int>(clientB.getContext().response_->getType()));
  881. // Client B performs 4-way exchange and obtains a lease for the
  882. // reserved address.
  883. clientB.setState(Dhcp4Client::SELECTING);
  884. ASSERT_NO_THROW(clientB.doDORA(boost::shared_ptr<
  885. IOAddress>(new IOAddress("0.0.0.0"))));
  886. // Make sure that the server responded.
  887. ASSERT_TRUE(clientB.getContext().response_);
  888. resp = clientB.getContext().response_;
  889. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  890. ASSERT_EQ(in_pool_addr, clientB.config_.lease_.addr_);
  891. }
  892. /// This test verifies that after a client completes its DORA exchange,
  893. /// appropriate statistics are updated.
  894. TEST_F(DORATest, statisticsDORA) {
  895. Dhcp4Client client(Dhcp4Client::SELECTING);
  896. // Configure DHCP server.
  897. configure(DORA_CONFIGS[0], *client.getServer());
  898. // Perform 4-way exchange with the server but to not request any
  899. // specific address in the DHCPDISCOVER message.
  900. ASSERT_NO_THROW(client.doDORA());
  901. // Make sure that the server responded.
  902. ASSERT_TRUE(client.getContext().response_);
  903. Pkt4Ptr resp = client.getContext().response_;
  904. // Make sure that the server has responded with DHCPACK.
  905. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  906. // Ok, let's check the statistics.
  907. using namespace isc::stats;
  908. StatsMgr& mgr = StatsMgr::instance();
  909. ObservationPtr pkt4_received = mgr.getObservation("pkt4-received");
  910. ObservationPtr pkt4_discover_received = mgr.getObservation("pkt4-discover-received");
  911. ObservationPtr pkt4_offer_sent = mgr.getObservation("pkt4-offer-sent");
  912. ObservationPtr pkt4_request_received = mgr.getObservation("pkt4-request-received");
  913. ObservationPtr pkt4_ack_sent = mgr.getObservation("pkt4-ack-sent");
  914. ObservationPtr pkt4_sent = mgr.getObservation("pkt4-sent");
  915. // All expected statstics must be present.
  916. ASSERT_TRUE(pkt4_received);
  917. ASSERT_TRUE(pkt4_discover_received);
  918. ASSERT_TRUE(pkt4_offer_sent);
  919. ASSERT_TRUE(pkt4_request_received);
  920. ASSERT_TRUE(pkt4_ack_sent);
  921. ASSERT_TRUE(pkt4_sent);
  922. // They also must have expected values.
  923. EXPECT_EQ(2, pkt4_received->getInteger().first);
  924. EXPECT_EQ(1, pkt4_discover_received->getInteger().first);
  925. EXPECT_EQ(1, pkt4_offer_sent->getInteger().first);
  926. EXPECT_EQ(1, pkt4_request_received->getInteger().first);
  927. EXPECT_EQ(1, pkt4_ack_sent->getInteger().first);
  928. EXPECT_EQ(2, pkt4_sent->getInteger().first);
  929. // Let the client send request 3 times, which should make the server
  930. // to send 3 acks.
  931. client.setState(Dhcp4Client::RENEWING);
  932. ASSERT_NO_THROW(client.doRequest());
  933. ASSERT_NO_THROW(client.doRequest());
  934. ASSERT_NO_THROW(client.doRequest());
  935. // Let's see if the stats are properly updated.
  936. EXPECT_EQ(5, pkt4_received->getInteger().first);
  937. EXPECT_EQ(1, pkt4_discover_received->getInteger().first);
  938. EXPECT_EQ(1, pkt4_offer_sent->getInteger().first);
  939. EXPECT_EQ(4, pkt4_request_received->getInteger().first);
  940. EXPECT_EQ(4, pkt4_ack_sent->getInteger().first);
  941. EXPECT_EQ(5, pkt4_sent->getInteger().first);
  942. }
  943. // This test verifies that after a client completes an exchange that result
  944. // in NAK, appropriate statistics are updated.
  945. TEST_F(DORATest, statisticsNAK) {
  946. Dhcp4Client client(Dhcp4Client::SELECTING);
  947. // Configure DHCP server.
  948. configure(DORA_CONFIGS[0], *client.getServer());
  949. // Obtain a lease from the server using the 4-way exchange.
  950. // Get a lease.
  951. client.doDORA();
  952. // Wipe all stats.
  953. isc::stats::StatsMgr::instance().removeAll();
  954. client.setState(Dhcp4Client::INIT_REBOOT);
  955. client.config_.lease_.addr_ = IOAddress("10.0.0.30");
  956. ASSERT_NO_THROW(client.doRequest());
  957. // Make sure that the server responded.
  958. ASSERT_TRUE(client.getContext().response_);
  959. Pkt4Ptr resp = client.getContext().response_;
  960. EXPECT_EQ(DHCPNAK, static_cast<int>(resp->getType()));
  961. using namespace isc::stats;
  962. StatsMgr& mgr = StatsMgr::instance();
  963. ObservationPtr pkt4_received = mgr.getObservation("pkt4-received");
  964. ObservationPtr pkt4_request_received = mgr.getObservation("pkt4-request-received");
  965. ObservationPtr pkt4_ack_sent = mgr.getObservation("pkt4-ack-sent");
  966. ObservationPtr pkt4_nak_sent = mgr.getObservation("pkt4-nak-sent");
  967. ObservationPtr pkt4_sent = mgr.getObservation("pkt4-sent");
  968. // All expected statstics must be present.
  969. ASSERT_TRUE(pkt4_received);
  970. ASSERT_TRUE(pkt4_request_received);
  971. ASSERT_FALSE(pkt4_ack_sent); // No acks were sent, no such statistic expected.
  972. ASSERT_TRUE(pkt4_nak_sent);
  973. ASSERT_TRUE(pkt4_sent);
  974. // They also must have expected values.
  975. EXPECT_EQ(1, pkt4_received->getInteger().first);
  976. EXPECT_EQ(1, pkt4_request_received->getInteger().first);
  977. EXPECT_EQ(1, pkt4_nak_sent->getInteger().first);
  978. EXPECT_EQ(1, pkt4_sent->getInteger().first);
  979. }
  980. } // end of anonymous namespace