cfg_subnets6_unittest.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. // Copyright (C) 2014-2015,2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <dhcp/classify.h>
  8. #include <dhcp/dhcp6.h>
  9. #include <dhcp/option.h>
  10. #include <dhcpsrv/cfg_subnets6.h>
  11. #include <dhcpsrv/subnet.h>
  12. #include <dhcpsrv/subnet_id.h>
  13. #include <dhcpsrv/subnet_selector.h>
  14. #include <testutils/test_to_element.h>
  15. #include <gtest/gtest.h>
  16. #include <string>
  17. using namespace isc;
  18. using namespace isc::asiolink;
  19. using namespace isc::dhcp;
  20. using namespace isc::test;
  21. namespace {
  22. /// @brief Generates interface id option.
  23. ///
  24. /// @param text Interface id in a textual format.
  25. OptionPtr
  26. generateInterfaceId(const std::string& text) {
  27. OptionBuffer buffer(text.begin(), text.end());
  28. return OptionPtr(new Option(Option::V6, D6O_INTERFACE_ID, buffer));
  29. }
  30. // This test verifies that specific subnet can be retrieved by specifying
  31. // subnet identifier or subnet prefix.
  32. TEST(CfgSubnets6Test, getSpecificSubnet) {
  33. CfgSubnets6 cfg;
  34. // Create 3 subnets.
  35. Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4,
  36. SubnetID(5)));
  37. Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4,
  38. SubnetID(8)));
  39. Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 48, 1, 2, 3, 4,
  40. SubnetID(10)));
  41. // Store the subnets in a vector to make it possible to loop over
  42. // all configured subnets.
  43. std::vector<Subnet6Ptr> subnets;
  44. subnets.push_back(subnet1);
  45. subnets.push_back(subnet2);
  46. subnets.push_back(subnet3);
  47. // Add all subnets to the configuration.
  48. for (auto subnet = subnets.cbegin(); subnet != subnets.cend(); ++subnet) {
  49. ASSERT_NO_THROW(cfg.add(*subnet)) << "failed to add subnet with id: "
  50. << (*subnet)->getID();
  51. }
  52. // Iterate over all subnets and make sure they can be retrieved by
  53. // subnet identifier.
  54. for (auto subnet = subnets.rbegin(); subnet != subnets.rend(); ++subnet) {
  55. ConstSubnet6Ptr subnet_returned = cfg.getBySubnetId((*subnet)->getID());
  56. ASSERT_TRUE(subnet_returned) << "failed to return subnet with id: "
  57. << (*subnet)->getID();
  58. EXPECT_EQ((*subnet)->getID(), subnet_returned->getID());
  59. EXPECT_EQ((*subnet)->toText(), subnet_returned->toText());
  60. }
  61. // Repeat the previous test, but this time retrieve subnets by their
  62. // prefixes.
  63. for (auto subnet = subnets.rbegin(); subnet != subnets.rend(); ++subnet) {
  64. ConstSubnet6Ptr subnet_returned = cfg.getByPrefix((*subnet)->toText());
  65. ASSERT_TRUE(subnet_returned) << "failed to return subnet with id: "
  66. << (*subnet)->getID();
  67. EXPECT_EQ((*subnet)->getID(), subnet_returned->getID());
  68. EXPECT_EQ((*subnet)->toText(), subnet_returned->toText());
  69. }
  70. // Make sure that null pointers are returned for non-existing subnets.
  71. EXPECT_FALSE(cfg.getBySubnetId(SubnetID(123)));
  72. EXPECT_FALSE(cfg.getByPrefix("3000::/16"));
  73. }
  74. // This test checks that the subnet can be selected using a relay agent's
  75. // link address.
  76. TEST(CfgSubnets6Test, selectSubnetByRelayAddress) {
  77. CfgSubnets6 cfg;
  78. // Let's configure 3 subnets
  79. Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4));
  80. Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4));
  81. Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 48, 1, 2, 3, 4));
  82. cfg.add(subnet1);
  83. cfg.add(subnet2);
  84. cfg.add(subnet3);
  85. // Make sure that none of the subnets is selected when there is no relay
  86. // information configured for them.
  87. SubnetSelector selector;
  88. selector.first_relay_linkaddr_ = IOAddress("2001:db8:ff::1");
  89. EXPECT_FALSE(cfg.selectSubnet(selector));
  90. selector.first_relay_linkaddr_ = IOAddress("2001:db8:ff::2");
  91. EXPECT_FALSE(cfg.selectSubnet(selector));
  92. selector.first_relay_linkaddr_ = IOAddress("2001:db8:ff::3");
  93. EXPECT_FALSE(cfg.selectSubnet(selector));
  94. // Now specify relay information.
  95. subnet1->setRelayInfo(IOAddress("2001:db8:ff::1"));
  96. subnet2->setRelayInfo(IOAddress("2001:db8:ff::2"));
  97. subnet3->setRelayInfo(IOAddress("2001:db8:ff::3"));
  98. // And try again. This time relay-info is there and should match.
  99. selector.first_relay_linkaddr_ = IOAddress("2001:db8:ff::1");
  100. EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
  101. selector.first_relay_linkaddr_ = IOAddress("2001:db8:ff::2");
  102. EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
  103. selector.first_relay_linkaddr_ = IOAddress("2001:db8:ff::3");
  104. EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
  105. }
  106. // This test checks that the subnet can be selected using an interface
  107. // name associated with a asubnet.
  108. TEST(CfgSubnets6Test, selectSubnetByInterfaceName) {
  109. CfgSubnets6 cfg;
  110. // Let's create 3 subnets.
  111. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  112. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  113. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  114. subnet1->setIface("foo");
  115. subnet2->setIface("bar");
  116. subnet3->setIface("foobar");
  117. // Until subnets are added to the configuration, there should be nothing
  118. // returned.
  119. SubnetSelector selector;
  120. selector.iface_name_ = "foo";
  121. EXPECT_FALSE(cfg.selectSubnet(selector));
  122. // Add one of the subnets.
  123. cfg.add(subnet1);
  124. // The subnet should be now selected for the interface name "foo".
  125. EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
  126. // Check that the interface name is checked even when there is
  127. // only one subnet defined: there should be nothing returned when
  128. // other interface name is specified.
  129. selector.iface_name_ = "bar";
  130. EXPECT_FALSE(cfg.selectSubnet(selector));
  131. // Add other subnets.
  132. cfg.add(subnet2);
  133. cfg.add(subnet3);
  134. // When we specify correct interface names, the subnets should be returned.
  135. selector.iface_name_ = "foobar";
  136. EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
  137. selector.iface_name_ = "bar";
  138. EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
  139. // When specifying a non-existing interface the subnet should not be
  140. // returned.
  141. selector.iface_name_ = "xyzzy";
  142. EXPECT_FALSE(cfg.selectSubnet(selector));
  143. }
  144. // This test checks that the subnet can be selected using an Interface ID
  145. // option inserted by a relay.
  146. TEST(CfgSubnets6Test, selectSubnetByInterfaceId) {
  147. CfgSubnets6 cfg;
  148. // Create 3 subnets.
  149. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  150. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  151. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  152. // Create Interface-id options used in subnets 1,2, and 3
  153. OptionPtr ifaceid1 = generateInterfaceId("relay1.eth0");
  154. OptionPtr ifaceid2 = generateInterfaceId("VL32");
  155. // That's a strange interface-id, but this is a real life example
  156. OptionPtr ifaceid3 = generateInterfaceId("ISAM144|299|ipv6|nt:vp:1:110");
  157. // Bogus interface-id.
  158. OptionPtr ifaceid_bogus = generateInterfaceId("non-existent");
  159. // Assign interface ids to the respective subnets.
  160. subnet1->setInterfaceId(ifaceid1);
  161. subnet2->setInterfaceId(ifaceid2);
  162. subnet3->setInterfaceId(ifaceid3);
  163. // There shouldn't be any subnet configured at this stage.
  164. SubnetSelector selector;
  165. selector.interface_id_ = ifaceid1;
  166. // Note that some link address must be specified to indicate that it is
  167. // a relayed message!
  168. selector.first_relay_linkaddr_ = IOAddress("5000::1");
  169. EXPECT_FALSE(cfg.selectSubnet(selector));
  170. // Add one of the subnets.
  171. cfg.add(subnet1);
  172. // If only one subnet has been specified, it should be returned when the
  173. // interface id matches. But, for a different interface id there should be
  174. // no match.
  175. EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
  176. selector.interface_id_ = ifaceid2;
  177. EXPECT_FALSE(cfg.selectSubnet(selector));
  178. // Add other subnets.
  179. cfg.add(subnet2);
  180. cfg.add(subnet3);
  181. // Now that we have all subnets added. we should be able to retrieve them
  182. // using appropriate interface ids.
  183. selector.interface_id_ = ifaceid3;
  184. EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
  185. selector.interface_id_ = ifaceid2;
  186. EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
  187. // For invalid interface id, there should be nothing returned.
  188. selector.interface_id_ = ifaceid_bogus;
  189. EXPECT_FALSE(cfg.selectSubnet(selector));
  190. }
  191. // Test that the client classes are considered when the subnet is selected by
  192. // the relay link address.
  193. TEST(CfgSubnets6Test, selectSubnetByRelayAddressAndClassify) {
  194. CfgSubnets6 cfg;
  195. // Let's configure 3 subnets
  196. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  197. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  198. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  199. cfg.add(subnet1);
  200. cfg.add(subnet2);
  201. cfg.add(subnet3);
  202. // Let's sanity check that we can use that configuration.
  203. SubnetSelector selector;
  204. selector.first_relay_linkaddr_ = IOAddress("2000::123");
  205. EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
  206. selector.first_relay_linkaddr_ = IOAddress("3000::345");
  207. EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
  208. selector.first_relay_linkaddr_ = IOAddress("4000::567");
  209. EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
  210. // Client now belongs to bar class.
  211. selector.client_classes_.insert("bar");
  212. // There are no class restrictions defined, so everything should work
  213. // as before.
  214. selector.first_relay_linkaddr_ = IOAddress("2000::123");
  215. EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
  216. selector.first_relay_linkaddr_ = IOAddress("3000::345");
  217. EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
  218. selector.first_relay_linkaddr_ = IOAddress("4000::567");
  219. EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
  220. // Now let's add client class restrictions.
  221. subnet1->allowClientClass("foo"); // Serve here only clients from foo class
  222. subnet2->allowClientClass("bar"); // Serve here only clients from bar class
  223. subnet3->allowClientClass("baz"); // Serve here only clients from baz class
  224. // The same check as above should result in client being served only in
  225. // bar class, i.e. subnet2
  226. selector.first_relay_linkaddr_ = IOAddress("2000::123");
  227. EXPECT_FALSE(cfg.selectSubnet(selector));
  228. selector.first_relay_linkaddr_ = IOAddress("3000::345");
  229. EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
  230. selector.first_relay_linkaddr_ = IOAddress("4000::567");
  231. EXPECT_FALSE(cfg.selectSubnet(selector));
  232. // Now let's check that client with wrong class is not supported
  233. selector.client_classes_.clear();
  234. selector.client_classes_.insert("some_other_class");
  235. selector.first_relay_linkaddr_ = IOAddress("2000::123");
  236. EXPECT_FALSE(cfg.selectSubnet(selector));
  237. selector.first_relay_linkaddr_ = IOAddress("3000::345");
  238. EXPECT_FALSE(cfg.selectSubnet(selector));
  239. selector.first_relay_linkaddr_ = IOAddress("4000::567");
  240. EXPECT_FALSE(cfg.selectSubnet(selector));
  241. // Finally, let's check that client without any classes is not supported
  242. selector.client_classes_.clear();
  243. selector.first_relay_linkaddr_ = IOAddress("2000::123");
  244. EXPECT_FALSE(cfg.selectSubnet(selector));
  245. selector.first_relay_linkaddr_ = IOAddress("3000::345");
  246. EXPECT_FALSE(cfg.selectSubnet(selector));
  247. selector.first_relay_linkaddr_ = IOAddress("4000::567");
  248. EXPECT_FALSE(cfg.selectSubnet(selector));
  249. }
  250. // Test that client classes are considered when the subnet is selected by the
  251. // interface name.
  252. TEST(CfgSubnets6Test, selectSubnetByInterfaceNameAndClaassify) {
  253. CfgSubnets6 cfg;
  254. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  255. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  256. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  257. subnet1->setIface("foo");
  258. subnet2->setIface("bar");
  259. subnet3->setIface("foobar");
  260. cfg.add(subnet1);
  261. cfg.add(subnet2);
  262. cfg.add(subnet3);
  263. // Now we have only one subnet, any request will be served from it
  264. SubnetSelector selector;
  265. selector.client_classes_.insert("bar");
  266. selector.iface_name_ = "foo";
  267. EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
  268. selector.iface_name_ = "bar";
  269. EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
  270. selector.iface_name_ = "foobar";
  271. EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
  272. subnet1->allowClientClass("foo"); // Serve here only clients from foo class
  273. subnet2->allowClientClass("bar"); // Serve here only clients from bar class
  274. subnet3->allowClientClass("baz"); // Serve here only clients from baz class
  275. selector.iface_name_ = "foo";
  276. EXPECT_FALSE(cfg.selectSubnet(selector));
  277. selector.iface_name_ = "bar";
  278. EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
  279. selector.iface_name_ = "foobar";
  280. EXPECT_FALSE(cfg.selectSubnet(selector));
  281. }
  282. // Test that client classes are considered when the interface is selected by
  283. // the interface id.
  284. TEST(CfgSubnets6Test, selectSubnetByInterfaceIdAndClassify) {
  285. CfgSubnets6 cfg;
  286. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  287. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  288. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  289. // interface-id options used in subnets 1,2, and 3
  290. OptionPtr ifaceid1 = generateInterfaceId("relay1.eth0");
  291. OptionPtr ifaceid2 = generateInterfaceId("VL32");
  292. // That's a strange interface-id, but this is a real life example
  293. OptionPtr ifaceid3 = generateInterfaceId("ISAM144|299|ipv6|nt:vp:1:110");
  294. // bogus interface-id
  295. OptionPtr ifaceid_bogus = generateInterfaceId("non-existent");
  296. subnet1->setInterfaceId(ifaceid1);
  297. subnet2->setInterfaceId(ifaceid2);
  298. subnet3->setInterfaceId(ifaceid3);
  299. cfg.add(subnet1);
  300. cfg.add(subnet2);
  301. cfg.add(subnet3);
  302. // If we have only a single subnet and the request came from a local
  303. // address, let's use that subnet
  304. SubnetSelector selector;
  305. selector.first_relay_linkaddr_ = IOAddress("5000::1");
  306. selector.client_classes_.insert("bar");
  307. selector.interface_id_ = ifaceid1;
  308. EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
  309. selector.interface_id_ = ifaceid2;
  310. EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
  311. selector.interface_id_ = ifaceid3;
  312. EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
  313. subnet1->allowClientClass("foo"); // Serve here only clients from foo class
  314. subnet2->allowClientClass("bar"); // Serve here only clients from bar class
  315. subnet3->allowClientClass("baz"); // Serve here only clients from baz class
  316. EXPECT_FALSE(cfg.selectSubnet(selector));
  317. selector.interface_id_ = ifaceid2;
  318. EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
  319. selector.interface_id_ = ifaceid3;
  320. EXPECT_FALSE(cfg.selectSubnet(selector));
  321. }
  322. // Checks that detection of duplicated subnet IDs works as expected. It should
  323. // not be possible to add two IPv6 subnets holding the same ID.
  324. TEST(CfgSubnets6Test, duplication) {
  325. CfgSubnets6 cfg;
  326. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4, 123));
  327. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4, 124));
  328. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4, 123));
  329. ASSERT_NO_THROW(cfg.add(subnet1));
  330. EXPECT_NO_THROW(cfg.add(subnet2));
  331. // Subnet 3 has the same ID as subnet 1. It shouldn't be able to add it.
  332. EXPECT_THROW(cfg.add(subnet3), isc::dhcp::DuplicateSubnetID);
  333. }
  334. // This test check if IPv6 subnets can be unparsed in a predictable way,
  335. TEST(CfgSubnets6Test, unparseSubnet) {
  336. CfgSubnets6 cfg;
  337. // Add some subnets.
  338. Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"),
  339. 48, 1, 2, 3, 4, 123));
  340. Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"),
  341. 48, 1, 2, 3, 4, 124));
  342. Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"),
  343. 48, 1, 2, 3, 4, 125));
  344. OptionPtr ifaceid = generateInterfaceId("relay.eth0");
  345. subnet1->setInterfaceId(ifaceid);
  346. subnet1->allowClientClass("foo");
  347. subnet2->setIface("lo");
  348. subnet2->setRelayInfo(IOAddress("2001:db8:ff::2"));
  349. subnet3->setIface("eth1");
  350. cfg.add(subnet1);
  351. cfg.add(subnet2);
  352. cfg.add(subnet3);
  353. // Unparse
  354. std::string expected = "[\n"
  355. "{\n"
  356. " \"id\": 123,\n"
  357. " \"subnet\": \"2001:db8:1::/48\",\n"
  358. " \"relay\": { \"ip-address\": \"::\" },\n"
  359. " \"interface-id\": \"relay.eth0\",\n"
  360. " \"renew-timer\": 1,\n"
  361. " \"rebind-timer\": 2,\n"
  362. " \"preferred-lifetime\": 3,\n"
  363. " \"valid-lifetime\": 4,\n"
  364. " \"rapid-commit\": false,\n"
  365. " \"reservation-mode\": \"all\",\n"
  366. " \"client-class\": \"foo\",\n"
  367. " \"pools\": [ ],\n"
  368. " \"pd-pools\": [ ],\n"
  369. " \"option-data\": [ ]\n"
  370. "},{\n"
  371. " \"id\": 124,\n"
  372. " \"subnet\": \"2001:db8:2::/48\",\n"
  373. " \"relay\": { \"ip-address\": \"2001:db8:ff::2\" },\n"
  374. " \"interface\": \"lo\",\n"
  375. " \"renew-timer\": 1,\n"
  376. " \"rebind-timer\": 2,\n"
  377. " \"preferred-lifetime\": 3,\n"
  378. " \"valid-lifetime\": 4,\n"
  379. " \"rapid-commit\": false,\n"
  380. " \"reservation-mode\": \"all\",\n"
  381. " \"pools\": [ ],\n"
  382. " \"pd-pools\": [ ],\n"
  383. " \"option-data\": [ ]\n"
  384. "},{\n"
  385. " \"id\": 125,\n"
  386. " \"subnet\": \"2001:db8:3::/48\",\n"
  387. " \"relay\": { \"ip-address\": \"::\" },\n"
  388. " \"interface\": \"eth1\",\n"
  389. " \"renew-timer\": 1,\n"
  390. " \"rebind-timer\": 2,\n"
  391. " \"preferred-lifetime\": 3,\n"
  392. " \"valid-lifetime\": 4,\n"
  393. " \"rapid-commit\": false,\n"
  394. " \"reservation-mode\": \"all\",\n"
  395. " \"pools\": [ ],\n"
  396. " \"pd-pools\": [ ],\n"
  397. " \"option-data\": [ ]\n"
  398. "} ]\n";
  399. runToElementTest<CfgSubnets6>(expected, cfg);
  400. }
  401. // This test check if IPv6 pools can be unparsed in a predictable way,
  402. TEST(CfgSubnets6Test, unparsePool) {
  403. CfgSubnets6 cfg;
  404. // Add a subnet with pools
  405. Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"),
  406. 48, 1, 2, 3, 4, 123));
  407. Pool6Ptr pool1(new Pool6(Lease::TYPE_NA,
  408. IOAddress("2001:db8:1::100"),
  409. IOAddress("2001:db8:1::199")));
  410. Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:1::"), 64));
  411. subnet->addPool(pool1);
  412. subnet->addPool(pool2);
  413. cfg.add(subnet);
  414. // Unparse
  415. std::string expected = "[\n"
  416. "{\n"
  417. " \"id\": 123,\n"
  418. " \"subnet\": \"2001:db8:1::/48\",\n"
  419. " \"relay\": { \"ip-address\": \"::\" },\n"
  420. " \"renew-timer\": 1,\n"
  421. " \"rebind-timer\": 2,\n"
  422. " \"preferred-lifetime\": 3,\n"
  423. " \"valid-lifetime\": 4,\n"
  424. " \"rapid-commit\": false,\n"
  425. " \"reservation-mode\": \"all\",\n"
  426. " \"pools\": [\n"
  427. " {\n"
  428. " \"pool\": \"2001:db8:1::100-2001:db8:1::199\",\n"
  429. " \"option-data\": [ ]\n"
  430. " },{\n"
  431. " \"pool\": \"2001:db8:1:1::/64\",\n"
  432. " \"option-data\": [ ]\n"
  433. " }\n"
  434. " ],\n"
  435. " \"pd-pools\": [ ],\n"
  436. " \"option-data\": [ ]\n"
  437. "} ]\n";
  438. runToElementTest<CfgSubnets6>(expected, cfg);
  439. }
  440. // This test check if IPv6 prefix delegation pools can be unparsed
  441. // in a predictable way,
  442. TEST(CfgSubnets6Test, unparsePdPool) {
  443. CfgSubnets6 cfg;
  444. // Add a subnet with pd-pools
  445. Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"),
  446. 48, 1, 2, 3, 4, 123));
  447. Pool6Ptr pdpool1(new Pool6(Lease::TYPE_PD,
  448. IOAddress("2001:db8:2::"), 48, 64));
  449. Pool6Ptr pdpool2(new Pool6(IOAddress("2001:db8:3::"), 48, 56,
  450. IOAddress("2001:db8:3::"), 64));
  451. subnet->addPool(pdpool1);
  452. subnet->addPool(pdpool2);
  453. cfg.add(subnet);
  454. // Unparse
  455. std::string expected = "[\n"
  456. "{\n"
  457. " \"id\": 123,\n"
  458. " \"subnet\": \"2001:db8:1::/48\",\n"
  459. " \"relay\": { \"ip-address\": \"::\" },\n"
  460. " \"renew-timer\": 1,\n"
  461. " \"rebind-timer\": 2,\n"
  462. " \"preferred-lifetime\": 3,\n"
  463. " \"valid-lifetime\": 4,\n"
  464. " \"rapid-commit\": false,\n"
  465. " \"reservation-mode\": \"all\",\n"
  466. " \"pools\": [ ],\n"
  467. " \"pd-pools\": [\n"
  468. " {\n"
  469. " \"prefix\": \"2001:db8:2::\",\n"
  470. " \"prefix-len\": 48,\n"
  471. " \"delegated-len\": 64,\n"
  472. " \"option-data\": [ ]\n"
  473. " },{\n"
  474. " \"prefix\": \"2001:db8:3::\",\n"
  475. " \"prefix-len\": 48,\n"
  476. " \"delegated-len\": 56,\n"
  477. " \"excluded-prefix\": \"2001:db8:3::\",\n"
  478. " \"excluded-prefix-len\": 64,\n"
  479. " \"option-data\": [ ]\n"
  480. " }\n"
  481. " ],\n"
  482. " \"option-data\": [ ]\n"
  483. "} ]\n";
  484. runToElementTest<CfgSubnets6>(expected, cfg);
  485. }
  486. } // end of anonymous namespace