Commit c27b6b24 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[5306] Client classification for subnets added to allocation engine.

parent 253936cc
......@@ -2181,6 +2181,7 @@ hasAddressReservation(const AllocEngine::ClientContext4& ctx) {
void findClientLease(AllocEngine::ClientContext4& ctx, Lease4Ptr& client_lease) {
LeaseMgr& lease_mgr = LeaseMgrFactory::instance();
Subnet4Ptr original_subnet = ctx.subnet_;
Subnet4Ptr subnet = ctx.subnet_;
SharedNetwork4Ptr network;
......@@ -2188,6 +2189,15 @@ void findClientLease(AllocEngine::ClientContext4& ctx, Lease4Ptr& client_lease)
while (subnet) {
// Some of the subnets within a shared network may not be allowed
// for the client if classification restrictions have been applied.
if (!subnet->clientSupported(ctx.query_->getClasses())) {
if (network) {
subnet = network->getNextSubnet(original_subnet, subnet);
}
continue;
}
// If client identifier has been supplied, use it to lookup the lease. This
// search will return no lease if the client doesn't have any lease in the
// database or if the client didn't use client identifier to allocate the
......@@ -2225,7 +2235,7 @@ void findClientLease(AllocEngine::ClientContext4& ctx, Lease4Ptr& client_lease)
subnet.reset();
} else {
subnet = network->getNextSubnet(ctx.subnet_, subnet);
subnet = network->getNextSubnet(original_subnet, subnet);
}
}
}
......@@ -2245,26 +2255,31 @@ bool
inAllowedPool(AllocEngine::ClientContext4& ctx, const IOAddress& address) {
SharedNetwork4Ptr network;
ctx.subnet_->getSharedNetwork(network);
if (!network) {
// If there is no shared network associated with this subnet, we
// simply check if the address is within the pool in this subnet.
return (ctx.subnet_->inPool(Lease::TYPE_V4, address));
}
// If the subnet belongs to a shared network we will be iterating
// over the subnets that belong to this shared network.
Subnet4Ptr current_subnet = ctx.subnet_;
while (current_subnet) {
if (current_subnet->inPool(Lease::TYPE_V4, address)) {
// We found a subnet that this address belongs to, so it
// seems that this subnet is the good candidate for allocation.
// Let's update the selected subnet.
ctx.subnet_ = current_subnet;
return (true);
if (current_subnet->clientSupported(ctx.query_->getClasses())) {
if (current_subnet->inPool(Lease::TYPE_V4, address)) {
// We found a subnet that this address belongs to, so it
// seems that this subnet is the good candidate for allocation.
// Let's update the selected subnet.
ctx.subnet_ = current_subnet;
return (true);
}
}
if (network) {
// Address is not within pools or client class not supported, so
// let's proceed to the next subnet.
current_subnet = network->getNextSubnet(ctx.subnet_, current_subnet);
} else {
// No shared network, so there are no more subnets to try.
current_subnet.reset();
}
// Address is not within pools in this subnet, so let's proceed
// to the next subnet.
current_subnet = network->getNextSubnet(ctx.subnet_, current_subnet);
}
return (false);
......@@ -2947,6 +2962,16 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) {
subnet->getSharedNetwork(network);
uint64_t total_attempts = 0;
while (subnet) {
// Some of the subnets within a shared network may not be allowed
// for the client if classification restrictions have been applied.
if (!subnet->clientSupported(ctx.query_->getClasses())) {
if (network) {
subnet = network->getNextSubnet(original_subnet, subnet);
}
continue;
}
const uint64_t max_attempts = (attempts_ > 0 ? attempts_ :
subnet->getPoolCapacity(Lease::TYPE_V4));
for (uint64_t i = 0; i < max_attempts; ++i) {
......@@ -2976,6 +3001,7 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) {
// subnets in the same shared network.
if (network) {
subnet = network->getNextSubnet(original_subnet, subnet);
if (subnet) {
ctx.subnet_ = subnet;
}
......
......@@ -546,6 +546,61 @@ TEST_F(AllocEngine4Test, discoverSharedNetwork) {
EXPECT_EQ("192.0.2.17", lease2->addr_.toText());
}
// This test verifies that the server can offer an address from a
// different subnet than orginally selected, when the address pool in
// the first subnet is exhausted.
TEST_F(AllocEngine4Test, discoverSharedNetworkClassification) {
AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 100, false);
// Create two subnets, each with a single address pool. The first subnet
// has only one address in its address pool to make it easier to simulate
// address exhaustion.
Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3, SubnetID(1)));
Subnet4Ptr subnet2(new Subnet4(IOAddress("10.1.2.0"), 24, 1, 2, 3, SubnetID(2)));
Pool4Ptr pool1(new Pool4(IOAddress("192.0.2.17"), IOAddress("192.0.2.17")));
Pool4Ptr pool2(new Pool4(IOAddress("10.1.2.5"), IOAddress("10.1.2.100")));
subnet1->addPool(pool1);
subnet2->addPool(pool2);
// Both subnets belong to the same network so they can be used
// interchangeably.
SharedNetwork4Ptr network(new SharedNetwork4("test_network"));
network->add(subnet1);
network->add(subnet2);
// Try to offer address from subnet1. There is one address available
// so it should be offerred.
AllocEngine::ClientContext4
ctx(subnet1, ClientIdPtr(), hwaddr_, IOAddress::IPV4_ZERO_ADDRESS(),
false, false, "host.example.com.", true);
ctx.query_.reset(new Pkt4(DHCPDISCOVER, 1234));
Lease4Ptr lease = engine.allocateLease4(ctx);
ASSERT_TRUE(lease);
EXPECT_TRUE(subnet1->inPool(Lease::TYPE_V4, lease->addr_));
// Apply restrictions on the subnet1. This should be only assigned
// to clients belonging to cable-modem class.
subnet1->allowClientClass("cable-modem");
// The allocation engine should determine that the subnet1 is not
// available for the client not belonging to the cable-modem class.
// Instead, it should offer an address from subnet2 that belongs
// to the same shared network.
ctx.subnet_ = subnet1;
lease = engine.allocateLease4(ctx);
ASSERT_TRUE(lease);
EXPECT_TRUE(subnet2->inPool(Lease::TYPE_V4, lease->addr_));
// Assign cable-modem class and try again. This time, we should
// offer an address from the subnet1.
ctx.query_->addClass(ClientClass("cable-modem"));
ctx.subnet_ = subnet1;
lease = engine.allocateLease4(ctx);
ASSERT_TRUE(lease);
EXPECT_TRUE(subnet1->inPool(Lease::TYPE_V4, lease->addr_));
}
// This test verifies that the server can allocate an address from a
// different subnet than orginally selected, when the address pool in
// the first subnet is exhausted.
......@@ -619,6 +674,76 @@ TEST_F(AllocEngine4Test, reuqestSharedNetwork) {
EXPECT_EQ("192.0.2.17", lease2->addr_.toText());
}
// This test verifies that the server can assign an address from a
// different subnet than orginally selected, when the address pool in
// the first subnet is exhausted.
TEST_F(AllocEngine4Test, requestSharedNetworkClassification) {
AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 100, false);
// Create two subnets, each with a single address pool. The first subnet
// has only one address in its address pool to make it easier to simulate
// address exhaustion.
Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3, SubnetID(1)));
Subnet4Ptr subnet2(new Subnet4(IOAddress("10.1.2.0"), 24, 1, 2, 3, SubnetID(2)));
Pool4Ptr pool1(new Pool4(IOAddress("192.0.2.17"), IOAddress("192.0.2.17")));
Pool4Ptr pool2(new Pool4(IOAddress("10.1.2.5"), IOAddress("10.1.2.100")));
subnet1->addPool(pool1);
subnet2->addPool(pool2);
// Both subnets belong to the same network so they can be used
// interchangeably.
SharedNetwork4Ptr network(new SharedNetwork4("test_network"));
network->add(subnet1);
network->add(subnet2);
// Try to offer address from subnet1. There is one address available
// so it should be offerred.
AllocEngine::ClientContext4
ctx(subnet1, ClientIdPtr(), hwaddr_, IOAddress::IPV4_ZERO_ADDRESS(),
false, false, "host.example.com.", false);
ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
Lease4Ptr lease = engine.allocateLease4(ctx);
ASSERT_TRUE(lease);
EXPECT_TRUE(subnet1->inPool(Lease::TYPE_V4, lease->addr_));
// Remove the lease so as we can start over.
LeaseMgrFactory::instance().deleteLease(lease->addr_);
// Apply restrictions on the subnet1. This should be only assigned
// to clients belonging to cable-modem class.
subnet1->allowClientClass("cable-modem");
// The allocation engine should determine that the subnet1 is not
// available for the client not belonging to the cable-modem class.
// Instead, it should assign an address from subnet2 that belongs
// to the same shared network.
ctx.subnet_ = subnet1;
lease = engine.allocateLease4(ctx);
ASSERT_TRUE(lease);
EXPECT_TRUE(subnet2->inPool(Lease::TYPE_V4, lease->addr_));
// Remove the lease so as we can start over.
LeaseMgrFactory::instance().deleteLease(lease->addr_);
// Assign cable-modem class and try again. This time, we should
// offer an address from the subnet1.
ctx.query_->addClass(ClientClass("cable-modem"));
ctx.subnet_ = subnet1;
lease = engine.allocateLease4(ctx);
ASSERT_TRUE(lease);
EXPECT_TRUE(subnet1->inPool(Lease::TYPE_V4, lease->addr_));
// Let's now remove the client from the cable-modem class and try
// to renew the address. The engine should determine that the
// client doesn't have access to the subnet1 pools anymore and
// assign an address from unrestricted subnet.
ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
ctx.subnet_ = subnet1;
lease = engine.allocateLease4(ctx);
ASSERT_TRUE(lease);
EXPECT_TRUE(subnet2->inPool(Lease::TYPE_V4, lease->addr_));
}
// This test checks if an expired lease can be reused in DHCPDISCOVER (fake
// allocation)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment