callout_handle.getArgument("subnet6", callback_subnet6_);
callout_handle.getArgument("subnet6collection", callback_subnet6collection_);
- if (callback_subnet6_) {
- cout << "#### subnet6_select: subnet6=" << callback_subnet6_->toText()
- << ", subnet6collection.size=" << callback_subnet6collection_.size()
- << endl;
- } else {
- cout << "#### subnet6 empty!" << endl;
- }
+ callback_argument_names_ = callout_handle.getArgumentNames();
+ return (0);
+ }
+ // Callback that picks the other subnet if possible.
+ static int
+ subnet6_select_different_subnet_callout(CalloutHandle& callout_handle) {
+
+ // Call the basic calllout to record all passed values
+ subnet6_select_callout(callout_handle);
+
+ Subnet6Collection subnets;
+ Subnet6Ptr subnet;
+ callout_handle.getArgument("subnet6", subnet);
+ callout_handle.getArgument("subnet6collection", subnets);
+
+ // Let's change to a different subnet
+ if (subnets.size() > 1) {
+ subnet = subnets[1]; // Let's pick the other subnet
+ callout_handle.setArgument("subnet6", subnet);
+ }
- callback_argument_names_ = callout_handle.getArgumentNames();
return (0);
}
ASSERT_EQ(0, srv_->fake_sent_.size());
}
-
-// This test checks if Option Request Option (ORO) is parsed correctly
-// and the requested options are actually assigned.
-TEST_F(HooksDhcpv6SrvTest, subnet_select) {
+// This test checks if subnet6_select callout is triggered and reports
+// valid parameters
+TEST_F(HooksDhcpv6SrvTest, subnet6_select) {
// Install pkt6_receive_callout
EXPECT_NO_THROW(HooksManager::getCalloutManager()->registerCallout("subnet6_select",
// Compare that the available subnets are reported as expected
EXPECT_TRUE(exp_subnets[0].get() == callback_subnet6collection_[0].get());
EXPECT_TRUE(exp_subnets[1].get() == callback_subnet6collection_[1].get());
+}
+
+// This test checks if callout installed on subnet6_select hook point can pick
+// a different subnet.
+TEST_F(HooksDhcpv6SrvTest, subnet_select_change) {
+
+ // Install pkt6_receive_callout
+ EXPECT_NO_THROW(HooksManager::getCalloutManager()->registerCallout("subnet6_select",
+ subnet6_select_different_subnet_callout));
+
+ // Configure 2 subnets, both directly reachable over local interface
+ // (let's not complicate the matter with relays)
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pool\": [ \"2001:db8:1::/64\" ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"" + valid_iface_ + "\" "
+ " }, {"
+ " \"pool\": [ \"2001:db8:2::/64\" ],"
+ " \"subnet\": \"2001:db8:2::/48\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ ElementPtr json = Element::fromJSON(config);
+ ConstElementPtr status;
+
+ // Configure the server and make sure the config is accepted
+ EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
+ ASSERT_TRUE(status);
+ comment_ = parseAnswer(rcode_, status);
+ ASSERT_EQ(0, rcode_);
+
+ // Prepare solicit packet. Server should select first subnet for it
+ Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+ sol->setRemoteAddr(IOAddress("fe80::abcd"));
+ sol->setIface(valid_iface_);
+ sol->addOption(generateIA(234, 1500, 3000));
+ OptionPtr clientid = generateClientId();
+ sol->addOption(clientid);
+
+ // Pass it to the server and get an advertise
+ Pkt6Ptr adv = srv_->processSolicit(sol);
+
+ // check if we get response at all
+ ASSERT_TRUE(adv);
+
+ // The response should have an address from second pool, so let's check it
+ OptionPtr tmp = adv->getOption(D6O_IA_NA);
+ ASSERT_TRUE(tmp);
+ boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
+ ASSERT_TRUE(ia);
+ tmp = ia->getOption(D6O_IAADDR);
+ ASSERT_TRUE(tmp);
+ boost::shared_ptr<Option6IAAddr> addr_opt =
+ boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
+ ASSERT_TRUE(addr_opt);
+
+ // Get all subnets and use second subnet for verification
+ Subnet6Collection subnets = CfgMgr::instance().getSubnets6();
+ ASSERT_EQ(2, subnets.size());
+ // Advertised address must belong to the second pool (in subnet's range,
+ // in dynamic pool)
+ EXPECT_TRUE(subnets[1]->inRange(addr_opt->getAddress()));
+ EXPECT_TRUE(subnets[1]->inPool(addr_opt->getAddress()));
}