cfgmgr_unittest.cc 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923
  1. // Copyright (C) 2012-2014 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 <dhcpsrv/cfgmgr.h>
  16. #include <dhcpsrv/dhcp_parsers.h>
  17. #include <exceptions/exceptions.h>
  18. #include <dhcp/dhcp6.h>
  19. #include <dhcp/tests/iface_mgr_test_config.h>
  20. #include <gtest/gtest.h>
  21. #include <iostream>
  22. #include <sstream>
  23. #include <arpa/inet.h>
  24. using namespace std;
  25. using namespace isc::asiolink;
  26. using namespace isc::data;
  27. using namespace isc::dhcp;
  28. using namespace isc::dhcp::test;
  29. using namespace isc::util;
  30. using namespace isc;
  31. // don't import the entire boost namespace. It will unexpectedly hide uint8_t
  32. // for some systems.
  33. using boost::scoped_ptr;
  34. namespace {
  35. template <typename Storage>
  36. bool isZeroPosition(const Storage& storage, const std::string& param_name) {
  37. Element::Position position = storage.getPosition(param_name);
  38. return ((position.line_ == 0) && (position.pos_ == 0) &&
  39. (position.file_.empty()));
  40. }
  41. // This test verifies that BooleanStorage functions properly.
  42. TEST(ValueStorageTest, BooleanTesting) {
  43. BooleanStorage testStore;
  44. // Verify that we can add and retrieve parameters.
  45. testStore.setParam("firstBool", false, Element::Position("kea.conf", 123, 234));
  46. testStore.setParam("secondBool", true, Element::Position("keax.conf", 10, 20));
  47. EXPECT_FALSE(testStore.getParam("firstBool"));
  48. EXPECT_TRUE(testStore.getParam("secondBool"));
  49. EXPECT_EQ(123, testStore.getPosition("firstBool").line_);
  50. EXPECT_EQ(234, testStore.getPosition("firstBool").pos_);
  51. EXPECT_EQ("kea.conf", testStore.getPosition("firstBool").file_);
  52. EXPECT_EQ(10, testStore.getPosition("secondBool").line_);
  53. EXPECT_EQ(20, testStore.getPosition("secondBool").pos_);
  54. EXPECT_EQ("keax.conf", testStore.getPosition("secondBool").file_);
  55. // Verify that we can update parameters.
  56. testStore.setParam("firstBool", true, Element::Position("keax.conf", 555, 111));
  57. testStore.setParam("secondBool", false, Element::Position("kea.conf", 1, 3));
  58. EXPECT_TRUE(testStore.getParam("firstBool"));
  59. EXPECT_FALSE(testStore.getParam("secondBool"));
  60. EXPECT_EQ(555, testStore.getPosition("firstBool").line_);
  61. EXPECT_EQ(111, testStore.getPosition("firstBool").pos_);
  62. EXPECT_EQ("keax.conf", testStore.getPosition("firstBool").file_);
  63. EXPECT_EQ(1, testStore.getPosition("secondBool").line_);
  64. EXPECT_EQ(3, testStore.getPosition("secondBool").pos_);
  65. EXPECT_EQ("kea.conf", testStore.getPosition("secondBool").file_);
  66. // Verify that we can delete a parameter and it will no longer be found.
  67. testStore.delParam("firstBool");
  68. EXPECT_THROW(testStore.getParam("firstBool"), isc::dhcp::DhcpConfigError);
  69. // Verify that the "zero" position is returned when parameter doesn't exist.
  70. EXPECT_TRUE(isZeroPosition(testStore, "firstBool"));
  71. // Verify that the delete was safe and the store still operates.
  72. EXPECT_FALSE(testStore.getParam("secondBool"));
  73. EXPECT_EQ(1, testStore.getPosition("secondBool").line_);
  74. EXPECT_EQ(3, testStore.getPosition("secondBool").pos_);
  75. EXPECT_EQ("kea.conf", testStore.getPosition("secondBool").file_);
  76. // Verify that looking for a parameter that never existed throws.
  77. ASSERT_THROW(testStore.getParam("bogusBool"), isc::dhcp::DhcpConfigError);
  78. // Verify that the "zero" position is returned when parameter doesn't exist.
  79. EXPECT_TRUE(isZeroPosition(testStore, "bogusBool"));
  80. // Verify that attempting to delete a parameter that never existed does not throw.
  81. EXPECT_NO_THROW(testStore.delParam("bogusBool"));
  82. // Verify that we can empty the list.
  83. testStore.clear();
  84. EXPECT_THROW(testStore.getParam("secondBool"), isc::dhcp::DhcpConfigError);
  85. // Verify that the "zero" position is returned when parameter doesn't exist.
  86. EXPECT_TRUE(isZeroPosition(testStore, "secondBool"));
  87. }
  88. // This test verifies that Uint32Storage functions properly.
  89. TEST(ValueStorageTest, Uint32Testing) {
  90. Uint32Storage testStore;
  91. uint32_t int_one = 77;
  92. uint32_t int_two = 33;
  93. // Verify that we can add and retrieve parameters.
  94. testStore.setParam("firstInt", int_one, Element::Position("kea.conf", 123, 234));
  95. testStore.setParam("secondInt", int_two, Element::Position("keax.conf", 10, 20));
  96. EXPECT_EQ(testStore.getParam("firstInt"), int_one);
  97. EXPECT_EQ(testStore.getParam("secondInt"), int_two);
  98. EXPECT_EQ(123, testStore.getPosition("firstInt").line_);
  99. EXPECT_EQ(234, testStore.getPosition("firstInt").pos_);
  100. EXPECT_EQ("kea.conf", testStore.getPosition("firstInt").file_);
  101. EXPECT_EQ(10, testStore.getPosition("secondInt").line_);
  102. EXPECT_EQ(20, testStore.getPosition("secondInt").pos_);
  103. EXPECT_EQ("keax.conf", testStore.getPosition("secondInt").file_);
  104. // Verify that we can update parameters.
  105. testStore.setParam("firstInt", --int_one, Element::Position("keax.conf", 555, 111));
  106. testStore.setParam("secondInt", ++int_two, Element::Position("kea.conf", 1, 3));
  107. EXPECT_EQ(testStore.getParam("firstInt"), int_one);
  108. EXPECT_EQ(testStore.getParam("secondInt"), int_two);
  109. EXPECT_EQ(555, testStore.getPosition("firstInt").line_);
  110. EXPECT_EQ(111, testStore.getPosition("firstInt").pos_);
  111. EXPECT_EQ("keax.conf", testStore.getPosition("firstInt").file_);
  112. EXPECT_EQ(1, testStore.getPosition("secondInt").line_);
  113. EXPECT_EQ(3, testStore.getPosition("secondInt").pos_);
  114. EXPECT_EQ("kea.conf", testStore.getPosition("secondInt").file_);
  115. // Verify that we can delete a parameter and it will no longer be found.
  116. testStore.delParam("firstInt");
  117. EXPECT_THROW(testStore.getParam("firstInt"), isc::dhcp::DhcpConfigError);
  118. // Verify that the "zero" position is returned when parameter doesn't exist.
  119. EXPECT_TRUE(isZeroPosition(testStore, "firstInt"));
  120. // Verify that the delete was safe and the store still operates.
  121. EXPECT_EQ(testStore.getParam("secondInt"), int_two);
  122. EXPECT_EQ(1, testStore.getPosition("secondInt").line_);
  123. EXPECT_EQ(3, testStore.getPosition("secondInt").pos_);
  124. EXPECT_EQ("kea.conf", testStore.getPosition("secondInt").file_);
  125. // Verify that looking for a parameter that never existed throws.
  126. ASSERT_THROW(testStore.getParam("bogusInt"), isc::dhcp::DhcpConfigError);
  127. // Verify that attempting to delete a parameter that never existed does not throw.
  128. EXPECT_NO_THROW(testStore.delParam("bogusInt"));
  129. // Verify that the "zero" position is returned when parameter doesn't exist.
  130. EXPECT_TRUE(isZeroPosition(testStore, "bogusInt"));
  131. // Verify that we can empty the list.
  132. testStore.clear();
  133. EXPECT_THROW(testStore.getParam("secondInt"), isc::dhcp::DhcpConfigError);
  134. // Verify that the "zero" position is returned when parameter doesn't exist.
  135. EXPECT_TRUE(isZeroPosition(testStore, "secondInt"));
  136. }
  137. // This test verifies that StringStorage functions properly.
  138. TEST(ValueStorageTest, StringTesting) {
  139. StringStorage testStore;
  140. std::string string_one = "seventy-seven";
  141. std::string string_two = "thirty-three";
  142. // Verify that we can add and retrieve parameters.
  143. testStore.setParam("firstString", string_one,
  144. Element::Position("kea.conf", 123, 234));
  145. testStore.setParam("secondString", string_two,
  146. Element::Position("keax.conf", 10, 20));
  147. EXPECT_EQ(testStore.getParam("firstString"), string_one);
  148. EXPECT_EQ(testStore.getParam("secondString"), string_two);
  149. EXPECT_EQ(123, testStore.getPosition("firstString").line_);
  150. EXPECT_EQ(234, testStore.getPosition("firstString").pos_);
  151. EXPECT_EQ("kea.conf", testStore.getPosition("firstString").file_);
  152. EXPECT_EQ(10, testStore.getPosition("secondString").line_);
  153. EXPECT_EQ(20, testStore.getPosition("secondString").pos_);
  154. EXPECT_EQ("keax.conf", testStore.getPosition("secondString").file_);
  155. // Verify that we can update parameters.
  156. string_one.append("-boo");
  157. string_two.append("-boo");
  158. testStore.setParam("firstString", string_one,
  159. Element::Position("kea.conf", 555, 111));
  160. testStore.setParam("secondString", string_two,
  161. Element::Position("keax.conf", 1, 3));
  162. EXPECT_EQ(testStore.getParam("firstString"), string_one);
  163. EXPECT_EQ(testStore.getParam("secondString"), string_two);
  164. EXPECT_EQ(555, testStore.getPosition("firstString").line_);
  165. EXPECT_EQ(111, testStore.getPosition("firstString").pos_);
  166. EXPECT_EQ("kea.conf", testStore.getPosition("firstString").file_);
  167. EXPECT_EQ(1, testStore.getPosition("secondString").line_);
  168. EXPECT_EQ(3, testStore.getPosition("secondString").pos_);
  169. EXPECT_EQ("keax.conf", testStore.getPosition("secondString").file_);
  170. // Verify that we can delete a parameter and it will no longer be found.
  171. testStore.delParam("firstString");
  172. EXPECT_THROW(testStore.getParam("firstString"), isc::dhcp::DhcpConfigError);
  173. // Verify that the "zero" position is returned when parameter doesn't exist.
  174. EXPECT_TRUE(isZeroPosition(testStore, "firstString"));
  175. // Verify that the delete was safe and the store still operates.
  176. EXPECT_EQ(testStore.getParam("secondString"), string_two);
  177. EXPECT_EQ(1, testStore.getPosition("secondString").line_);
  178. EXPECT_EQ(3, testStore.getPosition("secondString").pos_);
  179. EXPECT_EQ("keax.conf", testStore.getPosition("secondString").file_);
  180. // Verify that looking for a parameter that never existed throws.
  181. ASSERT_THROW(testStore.getParam("bogusString"), isc::dhcp::DhcpConfigError);
  182. // Verify that attempting to delete a parameter that never existed does not throw.
  183. EXPECT_NO_THROW(testStore.delParam("bogusString"));
  184. // Verify that the "zero" position is returned when parameter doesn't exist.
  185. EXPECT_TRUE(isZeroPosition(testStore, "bogusString"));
  186. // Verify that we can empty the list.
  187. testStore.clear();
  188. EXPECT_THROW(testStore.getParam("secondString"), isc::dhcp::DhcpConfigError);
  189. // Verify that the "zero" position is returned when parameter doesn't exist.
  190. EXPECT_TRUE(isZeroPosition(testStore, "secondString"));
  191. }
  192. class CfgMgrTest : public ::testing::Test {
  193. public:
  194. CfgMgrTest() {
  195. // make sure we start with a clean configuration
  196. clear();
  197. }
  198. /// @brief generates interface-id option based on provided text
  199. ///
  200. /// @param text content of the option to be created
  201. ///
  202. /// @return pointer to the option object created
  203. OptionPtr generateInterfaceId(const string& text) {
  204. OptionBuffer buffer(text.begin(), text.end());
  205. return OptionPtr(new Option(Option::V6, D6O_INTERFACE_ID, buffer));
  206. }
  207. ~CfgMgrTest() {
  208. // clean up after the test
  209. clear();
  210. }
  211. void clear() {
  212. CfgMgr::instance().setVerbose(false);
  213. CfgMgr::instance().deleteSubnets6();
  214. CfgMgr::instance().clear();
  215. }
  216. /// used in client classification (or just empty container for other tests)
  217. isc::dhcp::ClientClasses classify_;
  218. };
  219. // Checks that there is a configuration structure available and that
  220. // it is empty by default.
  221. TEST_F(CfgMgrTest, configuration) {
  222. ConstSrvConfigPtr configuration = CfgMgr::instance().getCurrentCfg();
  223. ASSERT_TRUE(configuration);
  224. EXPECT_TRUE(configuration->getLoggingInfo().empty());
  225. configuration = CfgMgr::instance().getStagingCfg();
  226. ASSERT_TRUE(configuration);
  227. EXPECT_TRUE(configuration->getLoggingInfo().empty());
  228. }
  229. // This test verifies if the configuration manager is able to hold v6 subnets
  230. // with their relay address information and return proper subnets, based on
  231. // those addresses.
  232. TEST_F(CfgMgrTest, subnet6RelayOverride) {
  233. CfgMgr& cfg_mgr = CfgMgr::instance();
  234. // Let's configure 3 subnets
  235. Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4));
  236. Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4));
  237. Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 48, 1, 2, 3, 4));
  238. cfg_mgr.addSubnet6(subnet1);
  239. cfg_mgr.addSubnet6(subnet2);
  240. cfg_mgr.addSubnet6(subnet3);
  241. // Check that without relay-info specified, subnets are not selected
  242. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::1"), classify_, true));
  243. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::2"), classify_, true));
  244. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::3"), classify_, true));
  245. // Now specify relay info
  246. subnet1->setRelayInfo(IOAddress("2001:db8:ff::1"));
  247. subnet2->setRelayInfo(IOAddress("2001:db8:ff::2"));
  248. subnet3->setRelayInfo(IOAddress("2001:db8:ff::3"));
  249. // And try again. This time relay-info is there and should match.
  250. EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::1"), classify_, true));
  251. EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::2"), classify_, true));
  252. EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::3"), classify_, true));
  253. // Finally, check that the relay works only if hint provided is relay address
  254. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::1"), classify_, false));
  255. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::2"), classify_, false));
  256. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::3"), classify_, false));
  257. }
  258. // This test verifies if the configuration manager is able to hold and return
  259. // valid leases
  260. TEST_F(CfgMgrTest, classifySubnet6) {
  261. CfgMgr& cfg_mgr = CfgMgr::instance();
  262. // Let's configure 3 subnets
  263. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  264. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  265. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  266. cfg_mgr.addSubnet6(subnet1);
  267. cfg_mgr.addSubnet6(subnet2);
  268. cfg_mgr.addSubnet6(subnet3);
  269. // Let's sanity check that we can use that configuration.
  270. EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
  271. EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
  272. EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
  273. // Client now belongs to bar class.
  274. classify_.insert("bar");
  275. // There are no class restrictions defined, so everything should work
  276. // as before
  277. EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
  278. EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
  279. EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
  280. // Now let's add client class restrictions.
  281. subnet1->allowClientClass("foo"); // Serve here only clients from foo class
  282. subnet2->allowClientClass("bar"); // Serve here only clients from bar class
  283. subnet3->allowClientClass("baz"); // Serve here only clients from baz class
  284. // The same check as above should result in client being served only in
  285. // bar class, i.e. subnet2
  286. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
  287. EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
  288. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
  289. // Now let's check that client with wrong class is not supported
  290. classify_.clear();
  291. classify_.insert("some_other_class");
  292. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
  293. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
  294. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
  295. // Finally, let's check that client without any classes is not supported
  296. classify_.clear();
  297. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
  298. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
  299. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
  300. }
  301. // This test verifies if the configuration manager is able to hold, select
  302. // and return valid subnets, based on interface names along with client
  303. // classification.
  304. TEST_F(CfgMgrTest, classifySubnet6Interface) {
  305. CfgMgr& cfg_mgr = CfgMgr::instance();
  306. // Let's have an odd configuration: 3 shared subnets available on the
  307. // same direct link.
  308. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  309. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  310. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  311. subnet1->setIface("foo");
  312. subnet2->setIface("foo");
  313. subnet3->setIface("foo");
  314. cfg_mgr.addSubnet6(subnet1);
  315. cfg_mgr.addSubnet6(subnet2);
  316. cfg_mgr.addSubnet6(subnet3);
  317. // Regular client should get the first subnet, because it meets all
  318. // criteria (matching interface name, no class restrictions.
  319. EXPECT_EQ(subnet1, cfg_mgr.getSubnet6("foo", classify_));
  320. // Now let's add class requirements for subnet1
  321. subnet1->allowClientClass("alpha");
  322. // Client should now get the subnet2, because he no longer meets
  323. // requirements for subnet1 (belongs to wrong class)
  324. EXPECT_EQ(subnet2, cfg_mgr.getSubnet6("foo", classify_));
  325. // Now let's add (not matching) classes to the other two subnets
  326. subnet2->allowClientClass("beta");
  327. subnet3->allowClientClass("gamma");
  328. // No subnets are suitable, so nothing will be selected
  329. EXPECT_FALSE(cfg_mgr.getSubnet6("foo", classify_));
  330. // Ok, let's add the client to gamme class, so he'll get a subnet
  331. classify_.insert("gamma");
  332. EXPECT_EQ(subnet3, cfg_mgr.getSubnet6("foo", classify_));
  333. }
  334. // This test verifies if the configuration manager is able to hold, select
  335. // and return valid subnets, based on interface-id option inserted by relay,
  336. // along with client classification.
  337. TEST_F(CfgMgrTest, classifySubnet6InterfaceId) {
  338. CfgMgr& cfg_mgr = CfgMgr::instance();
  339. // Let's have an odd configuration: 3 shared subnets available via the
  340. // same remote relay with the same interface-id.
  341. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  342. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  343. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  344. OptionPtr ifaceid = generateInterfaceId("relay1.eth0");
  345. subnet1->setInterfaceId(ifaceid);
  346. subnet2->setInterfaceId(ifaceid);
  347. subnet3->setInterfaceId(ifaceid);
  348. cfg_mgr.addSubnet6(subnet1);
  349. cfg_mgr.addSubnet6(subnet2);
  350. cfg_mgr.addSubnet6(subnet3);
  351. // Regular client should get the first subnet, because it meets all
  352. // criteria (matching interface name, no class restrictions.
  353. EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(ifaceid, classify_));
  354. // Now let's add class requirements for subnet1
  355. subnet1->allowClientClass("alpha");
  356. // Client should now get the subnet2, because he no longer meets
  357. // requirements for subnet1 (belongs to wrong class)
  358. EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(ifaceid, classify_));
  359. // Now let's add (not matching) classes to the other two subnets
  360. subnet2->allowClientClass("beta");
  361. subnet3->allowClientClass("gamma");
  362. // No subnets are suitable, so nothing will be selected
  363. EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid, classify_));
  364. // Ok, let's add the client to gamme class, so he'll get a subnet
  365. classify_.insert("gamma");
  366. EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(ifaceid, classify_));
  367. }
  368. // This test verifies if the configuration manager is able to hold and return
  369. // valid leases
  370. TEST_F(CfgMgrTest, subnet6) {
  371. CfgMgr& cfg_mgr = CfgMgr::instance();
  372. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  373. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  374. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  375. // There shouldn't be any subnet configured at this stage
  376. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::1"), classify_));
  377. cfg_mgr.addSubnet6(subnet1);
  378. // Now we have only one subnet, any request will be served from it
  379. EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::1"), classify_));
  380. // We used to allow getting a sole subnet if there was only one subnet
  381. // configured. That is no longer true. The code should not return
  382. // a subnet.
  383. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef"), classify_));
  384. cfg_mgr.addSubnet6(subnet2);
  385. cfg_mgr.addSubnet6(subnet3);
  386. EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::123"), classify_));
  387. EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::dead:beef"),
  388. classify_));
  389. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("5000::1"), classify_));
  390. // Check that deletion of the subnets works.
  391. cfg_mgr.deleteSubnets6();
  392. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
  393. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::123"), classify_));
  394. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::123"), classify_));
  395. }
  396. // This test verifies if the configuration manager is able to hold, select
  397. // and return valid subnets, based on interface names.
  398. TEST_F(CfgMgrTest, subnet6Interface) {
  399. CfgMgr& cfg_mgr = CfgMgr::instance();
  400. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  401. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  402. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  403. subnet1->setIface("foo");
  404. subnet2->setIface("bar");
  405. subnet3->setIface("foobar");
  406. // There shouldn't be any subnet configured at this stage
  407. EXPECT_FALSE(cfg_mgr.getSubnet6("foo", classify_));
  408. cfg_mgr.addSubnet6(subnet1);
  409. // Now we have only one subnet, any request will be served from it
  410. EXPECT_EQ(subnet1, cfg_mgr.getSubnet6("foo", classify_));
  411. // Check that the interface name is checked even when there is
  412. // only one subnet defined.
  413. EXPECT_FALSE(cfg_mgr.getSubnet6("bar", classify_));
  414. // We used to allow getting a sole subnet if there was only one subnet
  415. // configured. That is no longer true. The code should not return
  416. // a subnet.
  417. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef"), classify_));
  418. cfg_mgr.addSubnet6(subnet2);
  419. cfg_mgr.addSubnet6(subnet3);
  420. EXPECT_EQ(subnet3, cfg_mgr.getSubnet6("foobar", classify_));
  421. EXPECT_EQ(subnet2, cfg_mgr.getSubnet6("bar", classify_));
  422. EXPECT_FALSE(cfg_mgr.getSubnet6("xyzzy", classify_)); // no such interface
  423. // Check that deletion of the subnets works.
  424. cfg_mgr.deleteSubnets6();
  425. EXPECT_FALSE(cfg_mgr.getSubnet6("foo", classify_));
  426. EXPECT_FALSE(cfg_mgr.getSubnet6("bar", classify_));
  427. EXPECT_FALSE(cfg_mgr.getSubnet6("foobar", classify_));
  428. }
  429. // This test verifies if the configuration manager is able to hold, select
  430. // and return valid leases, based on interface-id option values
  431. TEST_F(CfgMgrTest, subnet6InterfaceId) {
  432. CfgMgr& cfg_mgr = CfgMgr::instance();
  433. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  434. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  435. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  436. // interface-id options used in subnets 1,2, and 3
  437. OptionPtr ifaceid1 = generateInterfaceId("relay1.eth0");
  438. OptionPtr ifaceid2 = generateInterfaceId("VL32");
  439. // That's a strange interface-id, but this is a real life example
  440. OptionPtr ifaceid3 = generateInterfaceId("ISAM144|299|ipv6|nt:vp:1:110");
  441. // bogus interface-id
  442. OptionPtr ifaceid_bogus = generateInterfaceId("non-existent");
  443. subnet1->setInterfaceId(ifaceid1);
  444. subnet2->setInterfaceId(ifaceid2);
  445. subnet3->setInterfaceId(ifaceid3);
  446. // There shouldn't be any subnet configured at this stage
  447. EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid1, classify_));
  448. cfg_mgr.addSubnet6(subnet1);
  449. // If we have only a single subnet and the request came from a local
  450. // address, let's use that subnet
  451. EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(ifaceid1, classify_));
  452. EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid2, classify_));
  453. cfg_mgr.addSubnet6(subnet2);
  454. cfg_mgr.addSubnet6(subnet3);
  455. EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(ifaceid3, classify_));
  456. EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(ifaceid2, classify_));
  457. EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid_bogus, classify_));
  458. // Check that deletion of the subnets works.
  459. cfg_mgr.deleteSubnets6();
  460. EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid1, classify_));
  461. EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid2, classify_));
  462. EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid3, classify_));
  463. }
  464. // This test verifies that new DHCPv4 option spaces can be added to
  465. // the configuration manager and that duplicated option space is
  466. // rejected.
  467. TEST_F(CfgMgrTest, optionSpace4) {
  468. CfgMgr& cfg_mgr = CfgMgr::instance();
  469. // Create some option spaces.
  470. OptionSpacePtr space1(new OptionSpace("isc", false));
  471. OptionSpacePtr space2(new OptionSpace("xyz", true));
  472. // Add option spaces with different names and expect they
  473. // are accepted.
  474. ASSERT_NO_THROW(cfg_mgr.addOptionSpace4(space1));
  475. ASSERT_NO_THROW(cfg_mgr.addOptionSpace4(space2));
  476. // Validate that the option spaces have been added correctly.
  477. const OptionSpaceCollection& spaces = cfg_mgr.getOptionSpaces4();
  478. ASSERT_EQ(2, spaces.size());
  479. EXPECT_FALSE(spaces.find("isc") == spaces.end());
  480. EXPECT_FALSE(spaces.find("xyz") == spaces.end());
  481. // Create another option space with the name that duplicates
  482. // the existing option space.
  483. OptionSpacePtr space3(new OptionSpace("isc", true));
  484. // Expect that the duplicate option space is rejected.
  485. ASSERT_THROW(
  486. cfg_mgr.addOptionSpace4(space3), isc::dhcp::InvalidOptionSpace
  487. );
  488. /// @todo decode if a duplicate vendor space is allowed.
  489. }
  490. // This test verifies that new DHCPv6 option spaces can be added to
  491. // the configuration manager and that duplicated option space is
  492. // rejected.
  493. TEST_F(CfgMgrTest, optionSpace6) {
  494. CfgMgr& cfg_mgr = CfgMgr::instance();
  495. // Create some option spaces.
  496. OptionSpacePtr space1(new OptionSpace("isc", false));
  497. OptionSpacePtr space2(new OptionSpace("xyz", true));
  498. // Add option spaces with different names and expect they
  499. // are accepted.
  500. ASSERT_NO_THROW(cfg_mgr.addOptionSpace6(space1));
  501. ASSERT_NO_THROW(cfg_mgr.addOptionSpace6(space2));
  502. // Validate that the option spaces have been added correctly.
  503. const OptionSpaceCollection& spaces = cfg_mgr.getOptionSpaces6();
  504. ASSERT_EQ(2, spaces.size());
  505. EXPECT_FALSE(spaces.find("isc") == spaces.end());
  506. EXPECT_FALSE(spaces.find("xyz") == spaces.end());
  507. // Create another option space with the name that duplicates
  508. // the existing option space.
  509. OptionSpacePtr space3(new OptionSpace("isc", true));
  510. // Expect that the duplicate option space is rejected.
  511. ASSERT_THROW(
  512. cfg_mgr.addOptionSpace6(space3), isc::dhcp::InvalidOptionSpace
  513. );
  514. /// @todo decide if a duplicate vendor space is allowed.
  515. }
  516. // This test verifies that RFC6842 (echo client-id) compatibility may be
  517. // configured.
  518. TEST_F(CfgMgrTest, echoClientId) {
  519. CfgMgr& cfg_mgr = CfgMgr::instance();
  520. // Check that the default is true
  521. EXPECT_TRUE(cfg_mgr.echoClientId());
  522. // Check that it can be modified to false
  523. cfg_mgr.echoClientId(false);
  524. EXPECT_FALSE(cfg_mgr.echoClientId());
  525. // Check that the default value can be restored
  526. cfg_mgr.echoClientId(true);
  527. EXPECT_TRUE(cfg_mgr.echoClientId());
  528. }
  529. // This test checks the D2ClientMgr wrapper methods.
  530. TEST_F(CfgMgrTest, d2ClientConfig) {
  531. // After CfgMgr construction, D2ClientMgr member should be initialized
  532. // with a D2 configuration that is disabled.
  533. // Verify we can Fetch the mgr.
  534. D2ClientMgr& d2_mgr = CfgMgr::instance().getD2ClientMgr();
  535. EXPECT_FALSE(d2_mgr.ddnsEnabled());
  536. // Make sure the convenience method fetches the config correctly.
  537. D2ClientConfigPtr original_config = CfgMgr::instance().getD2ClientConfig();
  538. ASSERT_TRUE(original_config);
  539. EXPECT_FALSE(original_config->getEnableUpdates());
  540. // Verify that we cannot set the configuration to an empty pointer.
  541. D2ClientConfigPtr new_cfg;
  542. ASSERT_THROW(CfgMgr::instance().setD2ClientConfig(new_cfg), D2ClientError);
  543. // Create a new, enabled configuration.
  544. ASSERT_NO_THROW(new_cfg.reset(new D2ClientConfig(true,
  545. isc::asiolink::IOAddress("127.0.0.1"), 477,
  546. isc::asiolink::IOAddress("127.0.0.1"), 478,
  547. 1024,
  548. dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
  549. true, true, true, true,
  550. "pre-fix", "suf-fix")));
  551. // Verify that we can assign a new, non-empty configuration.
  552. ASSERT_NO_THROW(CfgMgr::instance().setD2ClientConfig(new_cfg));
  553. // Verify that we can fetch the newly assigned configuration.
  554. D2ClientConfigPtr updated_config = CfgMgr::instance().getD2ClientConfig();
  555. ASSERT_TRUE(updated_config);
  556. EXPECT_TRUE(updated_config->getEnableUpdates());
  557. // Make sure convenience method agrees with updated configuration.
  558. EXPECT_TRUE(CfgMgr::instance().ddnsEnabled());
  559. // Make sure the configuration we fetched is the one we assigned,
  560. // and not the original configuration.
  561. EXPECT_EQ(*new_cfg, *updated_config);
  562. EXPECT_NE(*original_config, *updated_config);
  563. }
  564. // Checks that detection of duplicated subnet IDs works as expected. It should
  565. // not be possible to add two IPv6 subnets holding the same ID to the config
  566. // manager.
  567. TEST_F(CfgMgrTest, subnet6Duplication) {
  568. CfgMgr& cfg_mgr = CfgMgr::instance();
  569. Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 64, 1, 2, 3,
  570. 4, 123));
  571. Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 64, 1, 2, 3,
  572. 4, 124));
  573. Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 64, 1, 2, 3,
  574. 4, 123));
  575. ASSERT_NO_THROW(cfg_mgr.addSubnet6(subnet1));
  576. EXPECT_NO_THROW(cfg_mgr.addSubnet6(subnet2));
  577. // Subnet 3 has the same ID as subnet 1. It shouldn't be able to add it.
  578. EXPECT_THROW(cfg_mgr.addSubnet6(subnet3), isc::dhcp::DuplicateSubnetID);
  579. }
  580. // This test verifies that the configuration staging, commit and rollback works
  581. // as expected.
  582. TEST_F(CfgMgrTest, staging) {
  583. CfgMgr& cfg_mgr = CfgMgr::instance();
  584. // Initially, the current configuration is a default one. We are going
  585. // to get the current configuration a couple of times and make sure
  586. // that always the same instance is returned.
  587. ConstSrvConfigPtr const_config;
  588. for (int i = 0; i < 5; ++i) {
  589. const_config = cfg_mgr.getCurrentCfg();
  590. ASSERT_TRUE(const_config) << "Returned NULL current configuration"
  591. " for iteration " << i;
  592. EXPECT_EQ(0, const_config->getSequence())
  593. << "Returned invalid sequence number "
  594. << const_config->getSequence() << " for iteration " << i;
  595. }
  596. // Try to get the new staging configuration. When getStagingCfg() is called
  597. // for the first time the new instance of the staging configuration is
  598. // returned. This instance is returned for every call to getStagingCfg()
  599. // until commit is called.
  600. SrvConfigPtr config;
  601. for (int i = 0; i < 5; ++i) {
  602. config = cfg_mgr.getStagingCfg();
  603. ASSERT_TRUE(config) << "Returned NULL staging configuration for"
  604. " iteration " << i;
  605. // The sequence id is 1 for staging because it is ahead of current
  606. // configuration having sequence number 0.
  607. EXPECT_EQ(1, config->getSequence()) << "Returned invalid sequence"
  608. " number " << config->getSequence() << " for iteration " << i;
  609. }
  610. // This should change the staging configuration so as it becomes a current
  611. // one.
  612. cfg_mgr.commit();
  613. const_config = cfg_mgr.getCurrentCfg();
  614. ASSERT_TRUE(const_config);
  615. // Sequence id equal to 1 indicates that the current configuration points
  616. // to the configuration that used to be a staging configuration previously.
  617. EXPECT_EQ(1, const_config->getSequence());
  618. // Create a new staging configuration. It should be assigned a new
  619. // sequence id.
  620. config = cfg_mgr.getStagingCfg();
  621. ASSERT_TRUE(config);
  622. EXPECT_EQ(2, config->getSequence());
  623. // Let's execute commit a couple of times. The first invocation to commit
  624. // changes the configuration having sequence 2 to current configuration.
  625. // Other commits are no-op.
  626. for (int i = 0; i < 5; ++i) {
  627. cfg_mgr.commit();
  628. }
  629. // The current configuration now have sequence number 2.
  630. const_config = cfg_mgr.getCurrentCfg();
  631. ASSERT_TRUE(const_config);
  632. EXPECT_EQ(2, const_config->getSequence());
  633. // Clear configuration along with a history.
  634. cfg_mgr.clear();
  635. // After clearing configuration we should successfully get the
  636. // new staging configuration.
  637. config = cfg_mgr.getStagingCfg();
  638. ASSERT_TRUE(config);
  639. EXPECT_EQ(1, config->getSequence());
  640. // Modify the staging configuration.
  641. config->addLoggingInfo(LoggingInfo());
  642. ASSERT_TRUE(config);
  643. // The modified staging configuration should have one logger configured.
  644. ASSERT_EQ(1, config->getLoggingInfo().size());
  645. // Rollback should remove a staging configuration, including the logger.
  646. ASSERT_NO_THROW(cfg_mgr.rollback());
  647. // Make sure that the logger is not set. This is an indication that the
  648. // rollback worked.
  649. config = cfg_mgr.getStagingCfg();
  650. ASSERT_TRUE(config);
  651. EXPECT_EQ(0, config->getLoggingInfo().size());
  652. }
  653. // This test verifies that it is possible to revert to an old configuration.
  654. TEST_F(CfgMgrTest, revert) {
  655. CfgMgr& cfg_mgr = CfgMgr::instance();
  656. // Let's create 5 unique configurations: differing by a debug level in the
  657. // range of 10 to 14.
  658. for (int i = 0; i < 5; ++i) {
  659. SrvConfigPtr config = cfg_mgr.getStagingCfg();
  660. LoggingInfo logging_info;
  661. logging_info.debuglevel_ = i + 10;
  662. config->addLoggingInfo(logging_info);
  663. cfg_mgr.commit();
  664. }
  665. // Now we have 6 configurations with:
  666. // - debuglevel = 99 (a default one)
  667. // - debuglevel = 10
  668. // - debuglevel = 11
  669. // - debuglevel = 12
  670. // - debuglevel = 13
  671. // - debuglevel = 14 (current)
  672. // Hence, the maximum index of the configuration to revert is 5 (which
  673. // points to the configuration with debuglevel = 99). For the index greater
  674. // than 5 we should get an exception.
  675. ASSERT_THROW(cfg_mgr.revert(6), isc::OutOfRange);
  676. // Value of 0 also doesn't make sense.
  677. ASSERT_THROW(cfg_mgr.revert(0), isc::OutOfRange);
  678. // We should be able to revert to configuration with debuglevel = 10.
  679. ASSERT_NO_THROW(cfg_mgr.revert(4));
  680. // And this configuration should be now the current one and the debuglevel
  681. // of this configuration is 10.
  682. EXPECT_EQ(10, cfg_mgr.getCurrentCfg()->getLoggingInfo()[0].debuglevel_);
  683. EXPECT_NE(cfg_mgr.getCurrentCfg()->getSequence(), 1);
  684. // The new set of configuration is now as follows:
  685. // - debuglevel = 99
  686. // - debuglevel = 10
  687. // - debuglevel = 11
  688. // - debuglevel = 12
  689. // - debuglevel = 13
  690. // - debuglevel = 14
  691. // - debuglevel = 10 (current)
  692. // So, reverting to configuration having index 3 means that the debug level
  693. // of the current configuration will become 12.
  694. ASSERT_NO_THROW(cfg_mgr.revert(3));
  695. EXPECT_EQ(12, cfg_mgr.getCurrentCfg()->getLoggingInfo()[0].debuglevel_);
  696. }
  697. // This test verifies that the verbosity can be set and obtained from the
  698. // configuration manager.
  699. TEST_F(CfgMgrTest, verbosity) {
  700. ASSERT_FALSE(CfgMgr::instance().isVerbose());
  701. CfgMgr::instance().setVerbose(true);
  702. ASSERT_TRUE(CfgMgr::instance().isVerbose());
  703. CfgMgr::instance().setVerbose(false);
  704. EXPECT_FALSE(CfgMgr::instance().isVerbose());
  705. }
  706. /// @todo Add unit-tests for testing:
  707. /// - addActiveIface() with invalid interface name
  708. /// - addActiveIface() with the same interface twice
  709. /// - addActiveIface() with a bogus address
  710. ///
  711. /// This is somewhat tricky. Care should be taken here, because it is rather
  712. /// difficult to decide if interface name is valid or not. Some servers, e.g.
  713. /// dibbler, allow to specify interface names that are not currently present in
  714. /// the system. The server accepts them, but upon discovering that they are
  715. /// yet available (for different definitions of not being available), adds
  716. /// the to to-be-activated list.
  717. ///
  718. /// Cases covered by dibbler are:
  719. /// - missing interface (e.g. PPP connection that is not established yet)
  720. /// - downed interface (no link local address, no way to open sockets)
  721. /// - up, but not running interface (wifi up, but not associated)
  722. /// - tentative addresses (interface up and running, but DAD procedure is
  723. /// still in progress)
  724. /// - weird interfaces without link-local addresses (don't ask, 6rd tunnels
  725. /// look weird to me as well)
  726. // No specific tests for getSubnet6. That method (2 overloaded versions) is tested
  727. // in Dhcpv6SrvTest.selectSubnetAddr and Dhcpv6SrvTest.selectSubnetIface
  728. // (see src/bin/dhcp6/tests/dhcp6_srv_unittest.cc)
  729. } // end of anonymous namespace