Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ISC Open Source Projects
Kea
Commits
46c03d26
Commit
46c03d26
authored
Oct 04, 2012
by
Tomek Mrugalski
🛰
Browse files
[2237] Support for Subnet4 implemented.
parent
574a6f88
Changes
7
Hide whitespace changes
Inline
Side-by-side
ChangeLog
View file @
46c03d26
4XX. [func] tomek
libdhcpsrv: The DHCP Configuration Manager is now able to store
information about IPv4 subnets and pool. It is still not possible
to configure that information. This will be implemented in a near
future.
484. [func] tomek
A new library (libb10-dhcpsrv) has been created. At present, it
only holds the code for the DHCP Configuration Manager. Currently
...
...
src/lib/dhcp/cfgmgr.cc
View file @
46c03d26
...
...
@@ -68,6 +68,39 @@ void CfgMgr::addSubnet6(const Subnet6Ptr& subnet) {
subnets6_
.
push_back
(
subnet
);
}
Subnet4Ptr
CfgMgr
::
getSubnet4
(
const
isc
::
asiolink
::
IOAddress
&
hint
)
{
// 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
// router that also runs DHCPv6 server. Users specifies a single pool and
// expects it to just work. Without this, the server would complain that it
// doesn't have IP address on its interfaces that matches that
// configuration. Such requirement makes sense in IPv4, but not in IPv6.
// The server does not need to have a global address (using just link-local
// is ok for DHCPv6 server) from the pool it serves.
if
(
subnets4_
.
size
()
==
1
)
{
return
(
subnets4_
[
0
]);
}
// If there is more than one, we need to choose the proper one
for
(
Subnet4Collection
::
iterator
subnet
=
subnets4_
.
begin
();
subnet
!=
subnets4_
.
end
();
++
subnet
)
{
if
((
*
subnet
)
->
inRange
(
hint
))
{
return
(
*
subnet
);
}
}
// sorry, we don't support that subnet
return
(
Subnet4Ptr
());
}
void
CfgMgr
::
addSubnet4
(
const
Subnet4Ptr
&
subnet
)
{
/// @todo: Check that this new subnet does not cross boundaries of any
/// other already defined subnet.
subnets4_
.
push_back
(
subnet
);
}
CfgMgr
::
CfgMgr
()
{
}
...
...
src/lib/dhcp/cfgmgr.h
View file @
46c03d26
...
...
@@ -72,7 +72,7 @@ public:
/// accessing it.
static
CfgMgr
&
instance
();
/// @brief get subnet by address
/// @brief get
IPv6
subnet by address
///
/// Finds a matching subnet, based on an address. This can be used
/// in two cases: when trying to find an appropriate lease based on
...
...
@@ -83,7 +83,7 @@ public:
/// @param hint an address that belongs to a searched subnet
Subnet6Ptr
getSubnet6
(
const
isc
::
asiolink
::
IOAddress
&
hint
);
/// @brief get subnet by interface-id
/// @brief get
IPv6
subnet by interface-id
///
/// Another possibility to find a subnet is based on interface-id.
///
...
...
@@ -91,13 +91,30 @@ public:
/// @todo This method is not currently supported.
Subnet6Ptr
getSubnet6
(
OptionPtr
interface_id
);
/// @brief adds a subnet
6
/// @brief adds a
n IPv6
subnet
void
addSubnet6
(
const
Subnet6Ptr
&
subnet
);
/// @todo: Add subnet6 removal routines. Currently it is not possible
/// to remove subnets. The only case where subnet6 removal would be
/// needed is a dynamic server reconfiguration - a use case that is not
/// planned to be supported any time soon.
/// @brief get IPv4 subnet by address
///
/// Finds a matching subnet, based on an address. This can be used
/// in two cases: when trying to find an appropriate lease based on
/// a) relay link address (that must be the address that is on link)
/// b) our global address on the interface the message was received on
/// (for directly connected clients)
///
/// @param hint an address that belongs to a searched subnet
Subnet4Ptr
getSubnet4
(
const
isc
::
asiolink
::
IOAddress
&
hint
);
/// @brief adds a subnet4
void
addSubnet4
(
const
Subnet4Ptr
&
subnet
);
/// @brief removes all IPv4 subnets
void
removeSubnets4
();
protected:
/// @brief Protected constructor.
...
...
@@ -111,13 +128,21 @@ protected:
/// @brief virtual desctructor
virtual
~
CfgMgr
();
/// @brief a container for
S
ubnet
6
/// @brief a container for
IPv6 s
ubnet
s.
///
/// That is a simple vector of pointers. It does not make much sense to
/// optimize access time (e.g. using a map), because typical search
/// pattern will use calling inRange() method on each subnet until
/// a match is found.
Subnet6Collection
subnets6_
;
/// @brief a container for IPv4 subnets.
///
/// That is a simple vector of pointers. It does not make much sense to
/// optimize access time (e.g. using a map), because typical search
/// pattern will use calling inRange() method on each subnet until
/// a match is found.
Subnet4Collection
subnets4_
;
};
}
// namespace isc::dhcp
...
...
src/lib/dhcp/subnet.cc
View file @
46c03d26
...
...
@@ -41,6 +41,50 @@ bool Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
return
((
first
<=
addr
)
&&
(
addr
<=
last
));
}
Subnet4
::
Subnet4
(
const
isc
::
asiolink
::
IOAddress
&
prefix
,
uint8_t
length
,
const
Triplet
<
uint32_t
>&
t1
,
const
Triplet
<
uint32_t
>&
t2
,
const
Triplet
<
uint32_t
>&
valid_lifetime
)
:
Subnet
(
prefix
,
length
,
t1
,
t2
,
valid_lifetime
)
{
if
(
prefix
.
getFamily
()
!=
AF_INET
)
{
isc_throw
(
BadValue
,
"Non IPv4 prefix "
<<
prefix
.
toText
()
<<
" specified in subnet4"
);
}
}
void
Subnet4
::
addPool4
(
const
Pool4Ptr
&
pool
)
{
IOAddress
first_addr
=
pool
->
getFirstAddress
();
IOAddress
last_addr
=
pool
->
getLastAddress
();
if
(
!
inRange
(
first_addr
)
||
!
inRange
(
last_addr
))
{
isc_throw
(
BadValue
,
"Pool4 ("
<<
first_addr
.
toText
()
<<
"-"
<<
last_addr
.
toText
()
<<
" does not belong in this ("
<<
prefix_
<<
"/"
<<
prefix_len_
<<
") subnet4"
);
}
/// @todo: Check that pools do not overlap
pools_
.
push_back
(
pool
);
}
Pool4Ptr
Subnet4
::
getPool4
(
const
isc
::
asiolink
::
IOAddress
&
hint
/* = IOAddress("::")*/
)
{
Pool4Ptr
candidate
;
for
(
Pool4Collection
::
iterator
pool
=
pools_
.
begin
();
pool
!=
pools_
.
end
();
++
pool
)
{
// if we won't find anything better, then let's just use the first pool
if
(
!
candidate
)
{
candidate
=
*
pool
;
}
// if the client provided a pool and there's a pool that hint is valid in,
// then let's use that pool
if
((
*
pool
)
->
inRange
(
hint
))
{
return
(
*
pool
);
}
}
return
(
candidate
);
}
Subnet6
::
Subnet6
(
const
isc
::
asiolink
::
IOAddress
&
prefix
,
uint8_t
length
,
const
Triplet
<
uint32_t
>&
t1
,
const
Triplet
<
uint32_t
>&
t2
,
...
...
src/lib/dhcp/subnet.h
View file @
46c03d26
...
...
@@ -93,6 +93,57 @@ protected:
Triplet
<
uint32_t
>
valid_
;
};
/// @brief A configuration holder for IPv4 subnet.
///
/// This class represents an IPv4 subnet.
class
Subnet4
:
public
Subnet
{
public:
/// @brief Constructor with all parameters
///
/// @param prefix Subnet4 prefix
/// @param length prefix length
/// @param t1 renewal timer (in seconds)
/// @param t2 rebind timer (in seconds)
/// @param valid_lifetime preferred lifetime of leases (in seconds)
Subnet4
(
const
isc
::
asiolink
::
IOAddress
&
prefix
,
uint8_t
length
,
const
Triplet
<
uint32_t
>&
t1
,
const
Triplet
<
uint32_t
>&
t2
,
const
Triplet
<
uint32_t
>&
valid_lifetime
);
/// @brief Returns a pool that specified address belongs to
///
/// @param hint address that the returned pool should cover (optional)
/// @return Pointer to found pool4 (or NULL)
Pool4Ptr
getPool4
(
const
isc
::
asiolink
::
IOAddress
&
hint
=
isc
::
asiolink
::
IOAddress
(
"0.0.0.0"
));
/// @brief Adds a new pool.
/// @param pool pool to be added
void
addPool4
(
const
Pool4Ptr
&
pool
);
/// @brief returns all pools
///
/// The reference is only valid as long as the object that
/// returned it.
///
/// @return a collection of all pools
const
Pool4Collection
&
getPools
()
const
{
return
pools_
;
}
protected:
/// @brief collection of pools in that list
Pool4Collection
pools_
;
};
/// @brief A pointer to a Subnet4 object
typedef
boost
::
shared_ptr
<
Subnet4
>
Subnet4Ptr
;
/// @brief A collection of Subnet6 objects
typedef
std
::
vector
<
Subnet4Ptr
>
Subnet4Collection
;
/// @brief A configuration holder for IPv6 subnet.
///
/// This class represents an IPv6 subnet.
...
...
src/lib/dhcp/tests/cfgmgr_unittest.cc
View file @
46c03d26
...
...
@@ -32,6 +32,33 @@ using boost::scoped_ptr;
namespace
{
// This test verifies if the configuration manager is able to hold and return
// valid leases
TEST
(
CfgMgrTest
,
subnet4
)
{
CfgMgr
&
cfg_mgr
=
CfgMgr
::
instance
();
ASSERT_TRUE
(
&
cfg_mgr
!=
0
);
Subnet4Ptr
subnet1
(
new
Subnet4
(
IOAddress
(
"192.0.2.0"
),
26
,
1
,
2
,
3
));
Subnet4Ptr
subnet2
(
new
Subnet4
(
IOAddress
(
"192.0.2.64"
),
26
,
1
,
2
,
3
));
Subnet4Ptr
subnet3
(
new
Subnet4
(
IOAddress
(
"192.0.2.128"
),
26
,
1
,
2
,
3
));
// there shouldn't be any subnet configured at this stage
EXPECT_EQ
(
Subnet4Ptr
(),
cfg_mgr
.
getSubnet4
(
IOAddress
(
"192.0.2.0"
)));
cfg_mgr
.
addSubnet4
(
subnet1
);
// Now we have only one subnet, any request will be served from it
EXPECT_EQ
(
subnet1
,
cfg_mgr
.
getSubnet4
(
IOAddress
(
"192.0.2.63"
)));
cfg_mgr
.
addSubnet4
(
subnet2
);
cfg_mgr
.
addSubnet4
(
subnet3
);
EXPECT_EQ
(
subnet3
,
cfg_mgr
.
getSubnet4
(
IOAddress
(
"192.0.2.191"
)));
EXPECT_EQ
(
subnet2
,
cfg_mgr
.
getSubnet4
(
IOAddress
(
"192.0.2.85"
)));
EXPECT_EQ
(
Subnet4Ptr
(),
cfg_mgr
.
getSubnet4
(
IOAddress
(
"192.0.2.192"
)));
}
// This test verifies if the configuration manager is able to hold and return
// valid leases
TEST
(
CfgMgrTest
,
subnet6
)
{
...
...
@@ -57,7 +84,6 @@ TEST(CfgMgrTest, subnet6) {
EXPECT_EQ
(
subnet3
,
cfg_mgr
.
getSubnet6
(
IOAddress
(
"4000::123"
)));
EXPECT_EQ
(
subnet2
,
cfg_mgr
.
getSubnet6
(
IOAddress
(
"3000::dead:beef"
)));
EXPECT_EQ
(
Subnet6Ptr
(),
cfg_mgr
.
getSubnet6
(
IOAddress
(
"5000::1"
)));
}
}
// end of anonymous namespace
src/lib/dhcp/tests/subnet_unittest.cc
View file @
46c03d26
...
...
@@ -29,6 +29,83 @@ using namespace isc::asiolink;
namespace
{
TEST
(
Subnet4Test
,
constructor
)
{
EXPECT_NO_THROW
(
Subnet4
subnet1
(
IOAddress
(
"192.0.2.2"
),
16
,
1
,
2
,
3
));
EXPECT_THROW
(
Subnet4
subnet2
(
IOAddress
(
"192.0.2.0"
),
33
,
1
,
2
,
3
),
BadValue
);
// invalid prefix length
EXPECT_THROW
(
Subnet4
subnet3
(
IOAddress
(
"2001:db8::1"
),
24
,
1
,
2
,
3
),
BadValue
);
// IPv6 addresses are not allowed in Subnet4
}
TEST
(
Subnet4Test
,
in_range
)
{
Subnet4
subnet
(
IOAddress
(
"192.0.2.1"
),
24
,
1000
,
2000
,
3000
);
EXPECT_EQ
(
1000
,
subnet
.
getT1
());
EXPECT_EQ
(
2000
,
subnet
.
getT2
());
EXPECT_EQ
(
3000
,
subnet
.
getValid
());
EXPECT_FALSE
(
subnet
.
inRange
(
IOAddress
(
"192.0.0.0"
)));
EXPECT_TRUE
(
subnet
.
inRange
(
IOAddress
(
"192.0.2.0"
)));
EXPECT_TRUE
(
subnet
.
inRange
(
IOAddress
(
"192.0.2.1"
)));
EXPECT_TRUE
(
subnet
.
inRange
(
IOAddress
(
"192.0.2.255"
)));
EXPECT_FALSE
(
subnet
.
inRange
(
IOAddress
(
"192.0.3.0"
)));
EXPECT_FALSE
(
subnet
.
inRange
(
IOAddress
(
"0.0.0.0"
)));
EXPECT_FALSE
(
subnet
.
inRange
(
IOAddress
(
"255.255.255.255"
)));
}
TEST
(
Subnet4Test
,
Pool4InSubnet4
)
{
Subnet4Ptr
subnet
(
new
Subnet4
(
IOAddress
(
"192.1.2.0"
),
24
,
1
,
2
,
3
));
Pool4Ptr
pool1
(
new
Pool4
(
IOAddress
(
"192.1.2.0"
),
25
));
Pool4Ptr
pool2
(
new
Pool4
(
IOAddress
(
"192.1.2.128"
),
26
));
Pool4Ptr
pool3
(
new
Pool4
(
IOAddress
(
"192.1.2.192"
),
30
));
subnet
->
addPool4
(
pool1
);
// If there's only one pool, get that pool
Pool4Ptr
mypool
=
subnet
->
getPool4
();
EXPECT_EQ
(
mypool
,
pool1
);
subnet
->
addPool4
(
pool2
);
subnet
->
addPool4
(
pool3
);
// If there are more than one pool and we didn't provide hint, we
// should get the first pool
mypool
=
subnet
->
getPool4
();
EXPECT_EQ
(
mypool
,
pool1
);
// If we provide a hint, we should get a pool that this hint belongs to
mypool
=
subnet
->
getPool4
(
IOAddress
(
"192.1.2.195"
));
EXPECT_EQ
(
mypool
,
pool3
);
}
TEST
(
Subnet4Test
,
Subnet4_Pool4_checks
)
{
Subnet4Ptr
subnet
(
new
Subnet4
(
IOAddress
(
"192.0.2.0"
),
8
,
1
,
2
,
3
));
// this one is in subnet
Pool4Ptr
pool1
(
new
Pool4
(
IOAddress
(
"192.255.0.0"
),
16
));
subnet
->
addPool4
(
pool1
);
// this one is larger than the subnet!
Pool4Ptr
pool2
(
new
Pool4
(
IOAddress
(
"193.0.0.0"
),
24
));
EXPECT_THROW
(
subnet
->
addPool4
(
pool2
),
BadValue
);
// this one is totally out of blue
Pool4Ptr
pool3
(
new
Pool4
(
IOAddress
(
"1.2.3.4"
),
16
));
EXPECT_THROW
(
subnet
->
addPool4
(
pool3
),
BadValue
);
}
// Tests for Subnet6
TEST
(
Subnet6Test
,
constructor
)
{
EXPECT_NO_THROW
(
Subnet6
subnet1
(
IOAddress
(
"2001:db8:1::"
),
64
,
...
...
@@ -48,7 +125,6 @@ TEST(Subnet6Test, in_range) {
EXPECT_EQ
(
3000
,
subnet
.
getPreferred
());
EXPECT_EQ
(
4000
,
subnet
.
getValid
());
EXPECT_FALSE
(
subnet
.
inRange
(
IOAddress
(
"2001:db8:0:ffff:ffff:ffff:ffff:ffff"
)));
EXPECT_TRUE
(
subnet
.
inRange
(
IOAddress
(
"2001:db8:1::0"
)));
EXPECT_TRUE
(
subnet
.
inRange
(
IOAddress
(
"2001:db8:1::1"
)));
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment