Browse Source

[3274] Client classification for v6 implemented in CfgMgr

Tomek Mrugalski 11 years ago
parent
commit
290530e1c7
2 changed files with 171 additions and 4 deletions
  1. 20 3
      src/lib/dhcpsrv/cfgmgr.cc
  2. 151 1
      src/lib/dhcpsrv/tests/cfgmgr_unittest.cc

+ 20 - 3
src/lib/dhcpsrv/cfgmgr.cc

@@ -123,7 +123,7 @@ CfgMgr::getOptionDef(const std::string& option_space,
 
 Subnet6Ptr
 CfgMgr::getSubnet6(const std::string& iface,
-                   const isc::dhcp::ClientClasses& /*classes*/) {
+                   const isc::dhcp::ClientClasses& classes) {
 
     if (!iface.length()) {
         return (Subnet6Ptr());
@@ -132,6 +132,12 @@ CfgMgr::getSubnet6(const std::string& iface,
     // If there is more than one, we need to choose the proper one
     for (Subnet6Collection::iterator subnet = subnets6_.begin();
          subnet != subnets6_.end(); ++subnet) {
+
+        // If client is rejected because of not meeting client class criteria...
+        if (!(*subnet)->clientSupported(classes)) {
+            continue;
+        }
+
         if (iface == (*subnet)->getIface()) {
             LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
                       DHCPSRV_CFGMGR_SUBNET6_IFACE)
@@ -144,7 +150,7 @@ CfgMgr::getSubnet6(const std::string& iface,
 
 Subnet6Ptr
 CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint,
-                   const isc::dhcp::ClientClasses& /*classes*/) {
+                   const isc::dhcp::ClientClasses& classes) {
 
     // If there's only one subnet configured, let's just use it
     // The idea is to keep small deployments easy. In a small network - one
@@ -165,6 +171,11 @@ CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint,
     for (Subnet6Collection::iterator subnet = subnets6_.begin();
          subnet != subnets6_.end(); ++subnet) {
 
+        // If client is rejected because of not meeting client class criteria...
+        if (!(*subnet)->clientSupported(classes)) {
+            continue;
+        }
+
         if ((*subnet)->inRange(hint)) {
             LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
                       DHCPSRV_CFGMGR_SUBNET6)
@@ -180,7 +191,7 @@ CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint,
 }
 
 Subnet6Ptr CfgMgr::getSubnet6(OptionPtr iface_id_option,
-                              const isc::dhcp::ClientClasses& /*classes*/) {
+                              const isc::dhcp::ClientClasses& classes) {
     if (!iface_id_option) {
         return (Subnet6Ptr());
     }
@@ -189,6 +200,12 @@ Subnet6Ptr CfgMgr::getSubnet6(OptionPtr iface_id_option,
     // defined, check if the interface-id is equal to what we are looking for
     for (Subnet6Collection::iterator subnet = subnets6_.begin();
          subnet != subnets6_.end(); ++subnet) {
+
+        // If client is rejected because of not meeting client class criteria...
+        if (!(*subnet)->clientSupported(classes)) {
+            continue;
+        }
+
         if ( (*subnet)->getInterfaceId() &&
              ((*subnet)->getInterfaceId()->equal(iface_id_option))) {
             LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,

+ 151 - 1
src/lib/dhcpsrv/tests/cfgmgr_unittest.cc

@@ -427,6 +427,156 @@ TEST_F(CfgMgrTest, classifySubnet4) {
     EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.5"), classify_));
     EXPECT_EQ(subnet2, cfg_mgr.getSubnet4(IOAddress("192.0.2.70"), classify_));
     EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.130"), classify_));
+
+    // Now let's check that client with wrong class is not supported
+    classify_.clear();
+    classify_.insert("some_other_class");
+    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.5"), classify_));
+    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.70"), classify_));
+    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.130"), classify_));
+
+    // Finally, let's check that client without any classes is not supported
+    classify_.clear();
+    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.5"), classify_));
+    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.70"), classify_));
+    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.130"), classify_));
+}
+
+// This test verifies if the configuration manager is able to hold and return
+// valid leases
+TEST_F(CfgMgrTest, classifySubnet6) {
+    CfgMgr& cfg_mgr = CfgMgr::instance();
+
+    // Let's configure 3 subnets
+    Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
+    Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
+    Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
+
+    cfg_mgr.addSubnet6(subnet1);
+    cfg_mgr.addSubnet6(subnet2);
+    cfg_mgr.addSubnet6(subnet3);
+
+    // Let's sanity check that we can use that configuration.
+    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
+    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
+    EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
+
+    // Client now belongs to bar class.
+    classify_.insert("bar");
+
+    // There are no class restrictions defined, so everything should work
+    // as before
+    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
+    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
+    EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
+
+    // Now let's add client class restrictions.
+    subnet1->allowClientClass("foo"); // Serve here only clients from foo class
+    subnet2->allowClientClass("bar"); // Serve here only clients from bar class
+    subnet3->allowClientClass("baz"); // Serve here only clients from baz class
+
+    // The same check as above should result in client being served only in
+    // bar class, i.e. subnet2
+    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
+    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
+    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
+
+    // Now let's check that client with wrong class is not supported
+    classify_.clear();
+    classify_.insert("some_other_class");
+    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
+    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
+    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
+
+    // Finally, let's check that client without any classes is not supported
+    classify_.clear();
+    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
+    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
+    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
+}
+
+// This test verifies if the configuration manager is able to hold, select
+// and return valid subnets, based on interface names along with client
+// classification.
+TEST_F(CfgMgrTest, classifySubnet6Interface) {
+    CfgMgr& cfg_mgr = CfgMgr::instance();
+
+    // Let's have an odd configuration: 3 shared subnets available on the
+    // same direct link.
+    Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
+    Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
+    Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
+    subnet1->setIface("foo");
+    subnet2->setIface("foo");
+    subnet3->setIface("foo");
+    cfg_mgr.addSubnet6(subnet1);
+    cfg_mgr.addSubnet6(subnet2);
+    cfg_mgr.addSubnet6(subnet3);
+
+
+    // Regular client should get the first subnet, because it meets all
+    // criteria (matching interface name, no class restrictions.
+    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6("foo", classify_));
+
+    // Now let's add class requirements for subnet1
+    subnet1->allowClientClass("alpha");
+
+    // Client should now get the subnet2, because he no longer meets
+    // requirements for subnet1 (belongs to wrong class)
+    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6("foo", classify_));
+
+    // Now let's add (not matching) classes to the other two subnets
+    subnet2->allowClientClass("beta");
+    subnet3->allowClientClass("gamma");
+
+    // No subnets are suitable, so nothing will be selected
+    EXPECT_FALSE(cfg_mgr.getSubnet6("foo", classify_));
+
+    // Ok, let's add the client to gamme class, so he'll get a subnet
+    classify_.insert("gamma");
+    EXPECT_EQ(subnet3, cfg_mgr.getSubnet6("foo", classify_));
+}
+
+// This test verifies if the configuration manager is able to hold, select
+// and return valid subnets, based on interface-id option inserted by relay,
+// along with client classification.
+TEST_F(CfgMgrTest, classifySubnet6InterfaceId) {
+    CfgMgr& cfg_mgr = CfgMgr::instance();
+
+    // Let's have an odd configuration: 3 shared subnets available via the
+    // same remote relay with the same interface-id.
+    Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
+    Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
+    Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
+    OptionPtr ifaceid = generateInterfaceId("relay1.eth0");
+    subnet1->setInterfaceId(ifaceid);
+    subnet2->setInterfaceId(ifaceid);
+    subnet3->setInterfaceId(ifaceid);
+    cfg_mgr.addSubnet6(subnet1);
+    cfg_mgr.addSubnet6(subnet2);
+    cfg_mgr.addSubnet6(subnet3);
+
+    // Regular client should get the first subnet, because it meets all
+    // criteria (matching interface name, no class restrictions.
+    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(ifaceid, classify_));
+
+    // Now let's add class requirements for subnet1
+    subnet1->allowClientClass("alpha");
+
+    // Client should now get the subnet2, because he no longer meets
+    // requirements for subnet1 (belongs to wrong class)
+    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(ifaceid, classify_));
+
+    // Now let's add (not matching) classes to the other two subnets
+    subnet2->allowClientClass("beta");
+    subnet3->allowClientClass("gamma");
+
+    // No subnets are suitable, so nothing will be selected
+    EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid, classify_));
+
+    // Ok, let's add the client to gamme class, so he'll get a subnet
+    classify_.insert("gamma");
+    EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(ifaceid, classify_));
 }
 
 // This test verifies if the configuration manager is able to hold and return
@@ -461,7 +611,7 @@ TEST_F(CfgMgrTest, subnet6) {
 
     // Check that deletion of the subnets works.
     cfg_mgr.deleteSubnets6();
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("200::123"), classify_));
+    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
     EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::123"), classify_));
     EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::123"), classify_));
 }