From: Francis Dupont Date: Sat, 19 Sep 2015 19:55:50 +0000 (+0200) Subject: [4058] Added Subnet Selection option support X-Git-Tag: fdfb_base~14^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=27241065098a18c5fe7ebb1d92cb7665d2b7d1bb;p=thirdparty%2Fkea.git [4058] Added Subnet Selection option support --- diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index e286e49a86..beb61d61cc 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -292,6 +292,7 @@ Dhcpv4Srv::selectSubnet(const Pkt4Ptr& query) const { selector.client_classes_ = query->classes_; selector.iface_name_ = query->getIface(); + // Try first Relay Agent Link Selection sub-option OptionPtr rai = query->getOption(DHO_DHCP_AGENT_OPTIONS); if (rai) { OptionCustomPtr oc = boost::dynamic_pointer_cast(rai); @@ -305,6 +306,16 @@ Dhcpv4Srv::selectSubnet(const Pkt4Ptr& query) const { } } } + } else { + // Or Subnet Selection option + OptionPtr sbnsel = query->getOption(DHO_SUBNET_SELECTION); + if (sbnsel) { + OptionCustomPtr oc = + boost::dynamic_pointer_cast(sbnsel); + if (oc) { + selector.option_select_ = oc->readAddress(); + } + } } CfgMgr& cfgmgr = CfgMgr::instance(); diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc index 022440d72e..af2175329e 100644 --- a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc +++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc @@ -3310,6 +3310,17 @@ TEST_F(Dhcpv4SrvTest, relayLinkSelect) { dis->addOption(rai); EXPECT_TRUE(subnet2 == srv_.selectSubnet(dis)); + // Subnet select option has a lower precedence + OptionDefinitionPtr sbnsel_def = LibDHCP::getOptionDef(Option::V4, + DHO_SUBNET_SELECTION); + ASSERT_TRUE(sbnsel_def); + OptionCustomPtr sbnsel(new OptionCustom(*sbnsel_def, Option::V4)); + ASSERT_TRUE(sbnsel); + sbnsel->writeAddress(IOAddress("192.0.2.3")); + dis->addOption(sbnsel); + EXPECT_TRUE(subnet2 == srv_.selectSubnet(dis)); + dis->delOption(DHO_SUBNET_SELECTION); + // Check client-classification still applies IOAddress addr_foo("192.0.4.2"); ols.reset(new Option(Option::V4, RAI_OPTION_LINK_SELECTION, @@ -3333,7 +3344,88 @@ TEST_F(Dhcpv4SrvTest, relayLinkSelect) { rai->addOption(ols); dis->addOption(rai); EXPECT_FALSE(srv_.selectSubnet(dis)); +} +// Checks if a subnet selection option works as expected +TEST_F(Dhcpv4SrvTest, subnetSelect) { + + // We have 3 subnets defined. + string config = "{ \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "}," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet4\": [ " + "{ \"pools\": [ { \"pool\": \"192.0.2.2 - 192.0.2.100\" } ]," + " \"relay\": { " + " \"ip-address\": \"192.0.5.1\"" + " }," + " \"subnet\": \"192.0.2.0/24\" }, " + "{ \"pools\": [ { \"pool\": \"192.0.3.1 - 192.0.3.100\" } ]," + " \"subnet\": \"192.0.3.0/24\" }, " + "{ \"pools\": [ { \"pool\": \"192.0.4.1 - 192.0.4.100\" } ]," + " \"client-class\": \"foo\", " + " \"subnet\": \"192.0.4.0/24\" } " + "]," + "\"valid-lifetime\": 4000 }"; + + // Use this config to set up the server + ASSERT_NO_THROW(configure(config)); + + // Let's get the subnet configuration objects + const Subnet4Collection* subnets = + CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll(); + ASSERT_EQ(3, subnets->size()); + + // Let's get them for easy reference + Subnet4Ptr subnet1 = (*subnets)[0]; + Subnet4Ptr subnet2 = (*subnets)[1]; + Subnet4Ptr subnet3 = (*subnets)[2]; + ASSERT_TRUE(subnet1); + ASSERT_TRUE(subnet2); + ASSERT_TRUE(subnet3); + + // Let's create a packet. + Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234)); + dis->setRemoteAddr(IOAddress("192.0.2.1")); + dis->setIface("eth0"); + dis->setHops(1); + OptionPtr clientid = generateClientId(); + dis->addOption(clientid); + + // Let's create a Subnet Selection option + OptionDefinitionPtr sbnsel_def = LibDHCP::getOptionDef(Option::V4, + DHO_SUBNET_SELECTION); + ASSERT_TRUE(sbnsel_def); + OptionCustomPtr sbnsel(new OptionCustom(*sbnsel_def, Option::V4)); + ASSERT_TRUE(sbnsel); + sbnsel->writeAddress(IOAddress("192.0.3.2")); + + // This is just a sanity check, we're using regular method: ciaddr 192.0.3.1 + // belongs to the second subnet, so it is selected + dis->setGiaddr(IOAddress("192.0.3.1")); + EXPECT_TRUE(subnet2 == srv_.selectSubnet(dis)); + + // Setup a relay override for the first subnet as it has a high precedence + dis->setGiaddr(IOAddress("192.0.5.1")); + EXPECT_TRUE(subnet1 == srv_.selectSubnet(dis)); + + // Put a subnet select option to select back the second subnet as + // it has the second highest precedence + dis->addOption(sbnsel); + EXPECT_TRUE(subnet2 == srv_.selectSubnet(dis)); + + // Check client-classification still applies + sbnsel->writeAddress(IOAddress("192.0.4.2")); + // Note it shall fail (vs. try the next criterion). + EXPECT_FALSE(srv_.selectSubnet(dis)); + // Add the packet to the class and check again: now it shall succeed + dis->addClass("foo"); + EXPECT_TRUE(subnet3 == srv_.selectSubnet(dis)); + + // Check it fails with a bad address in the sub-option + sbnsel->writeAddress(IOAddress("10.0.0.1")); + EXPECT_FALSE(srv_.selectSubnet(dis)); } // This test verifies that the direct message is dropped when it has been