mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-29 04:57:52 +00:00
[master] Merged trac5425a (class in pools)
This commit is contained in:
commit
3d6bb5b1d4
@ -76,18 +76,19 @@
|
||||
// everyone is allowed. When a class is specified, only packets belonging
|
||||
// to that class are allowed for that subnet.
|
||||
"subnet4": [
|
||||
// This one is for VoIP devices only.
|
||||
{
|
||||
// This one is for VoIP devices only.
|
||||
"pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ],
|
||||
"subnet": "192.0.2.0/24",
|
||||
"client-class": "VoIP",
|
||||
"interface": "ethX"
|
||||
},
|
||||
// This one doesn't have any client-class specified, so everyone
|
||||
// is allowed in. The normal subnet selection rules still apply,
|
||||
// though. There is also a static class reservation for a client
|
||||
// using MAC address 1a:1b:1c:1d:1e:1f. This client will always
|
||||
// be assigned to this class.
|
||||
|
||||
// This one doesn't have any client-class specified, so everyone
|
||||
// is allowed in. The normal subnet selection rules still apply,
|
||||
// though. There is also a static class reservation for a client
|
||||
// using MAC address 1a:1b:1c:1d:1e:1f. This client will always
|
||||
// be assigned to this class.
|
||||
{
|
||||
"pools": [ { "pool": "192.0.3.1 - 192.0.3.200" } ],
|
||||
"subnet": "192.0.3.0/24",
|
||||
@ -97,6 +98,28 @@
|
||||
"client-classes": [ "VoIP" ]
|
||||
} ],
|
||||
"interface": "ethX"
|
||||
},
|
||||
|
||||
// The following list defines a subnet with pools. For some pools
|
||||
// we defined a class that is allowed in that pool. If not specified
|
||||
// everyone is allowed. When a class is specified, only packets belonging
|
||||
// to that class are allowed for that pool.
|
||||
{
|
||||
"pools": [
|
||||
// This one is for VoIP devices only.
|
||||
{
|
||||
"pool": "192.0.4.1 - 192.0.4.200",
|
||||
"client-class": "VoIP"
|
||||
},
|
||||
|
||||
// This one doesn't have any client-class specified,
|
||||
// so everyone is allowed in.
|
||||
{
|
||||
"pool": "192.0.5.1 - 192.0.5.200"
|
||||
} ],
|
||||
|
||||
"subnet": "192.0.4.0/23",
|
||||
"interface": "ethY"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -61,9 +61,10 @@
|
||||
"client-class": "cable-modems",
|
||||
"interface": "ethX"
|
||||
},
|
||||
// The following subnet contains a class reservation for a client using
|
||||
// DUID 01:02:03:04:05:0A:0B:0C:0D:0E. This client will always be assigned
|
||||
// to this class.
|
||||
|
||||
// The following subnet contains a class reservation for a client using
|
||||
// DUID 01:02:03:04:05:0A:0B:0C:0D:0E. This client will always be assigned
|
||||
// to this class.
|
||||
{
|
||||
"pools": [ { "pool": "2001:db8:2::/80" } ],
|
||||
"subnet": "2001:db8:2::/64",
|
||||
@ -73,7 +74,20 @@
|
||||
"client-classes": [ "cable-modems" ]
|
||||
} ],
|
||||
"interface": "ethX"
|
||||
},
|
||||
|
||||
// The following subnet contains a pool with a class constraint: only
|
||||
// clients which belong to the class are allowed to use this pool.
|
||||
{
|
||||
"pools": [
|
||||
{
|
||||
"pool": "2001:db8:3::/80",
|
||||
"client-class": "cable-modems"
|
||||
} ],
|
||||
"subnet": "2001:db8:4::/64",
|
||||
"interface": "ethY"
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
|
||||
|
@ -801,6 +801,96 @@ concatenation of the strings</entry></row>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="classification-pools">
|
||||
<title>Configuring Pools With Class Information</title>
|
||||
<para>
|
||||
Similar to the subnets, it is possible to restrict access to the certain address
|
||||
or prefix pools to the clients belonging to a specific class, using
|
||||
the "client-class" parameter when defining the pool.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Let's assume that the server is connected to a network segment using
|
||||
the 192.0.2.0/24 prefix. The Administrator of that network has decided
|
||||
that addresses from the range of 192.0.2.10 to 192.0.2.20 are going to be
|
||||
managed by the DHCP4 server. Only the clients belonging to the client class
|
||||
Client_foo are allowed to use this pool. Such a configuration can be
|
||||
achieved in the following way:
|
||||
<screen>
|
||||
"Dhcp4": {
|
||||
"client-classes": [
|
||||
{
|
||||
"name": "Client_foo",
|
||||
"test": "substring(option[61].hex,0,3) == 'foo'",
|
||||
"option-data": [
|
||||
{
|
||||
"name": "domain-name-servers",
|
||||
"code": 6,
|
||||
"space": "dhcp4",
|
||||
"csv-format": true,
|
||||
"data": "192.0.2.1, 192.0.2.2"
|
||||
}
|
||||
]
|
||||
},
|
||||
...
|
||||
],
|
||||
"subnet4": [
|
||||
{
|
||||
"subnet": "192.0.2.0/24",
|
||||
<userinput>
|
||||
"pools": [
|
||||
{
|
||||
"pool": "192.0.2.10 - 192.0.2.20",
|
||||
"client-class": "Client_foo"
|
||||
}
|
||||
]</userinput>
|
||||
},
|
||||
...
|
||||
],
|
||||
...
|
||||
}</screen>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The following example shows restricting access to an address pool.
|
||||
This configuration will restrict use of the addresses 2001:db8:1::1
|
||||
to 2001:db8:1::FFFF to members of the "Client_enterprise" class.
|
||||
<screen>
|
||||
"Dhcp6": {
|
||||
"client-classes": [
|
||||
{
|
||||
"name": "Client_enterprise_",
|
||||
"test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'",
|
||||
"option-data": [
|
||||
{
|
||||
"name": "dns-servers",
|
||||
"code": 23,
|
||||
"space": "dhcp6",
|
||||
"csv-format": true,
|
||||
"data": "2001:db8:0::1, 2001:db8:2::1"
|
||||
}
|
||||
]
|
||||
},
|
||||
...
|
||||
],
|
||||
"subnet6": [
|
||||
{
|
||||
"subnet": "2001:db8:1::/64",
|
||||
<userinput>
|
||||
"pools": [
|
||||
{
|
||||
"pool": "2001:db8:1::-2001:db8:1::ffff",
|
||||
"client-class": "Client_foo"
|
||||
}
|
||||
]</userinput>
|
||||
},
|
||||
...
|
||||
],
|
||||
...
|
||||
}</screen>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Using Classes</title>
|
||||
<para>
|
||||
|
@ -2068,16 +2068,13 @@ It is merely echoed by the server
|
||||
discussion of the classification process see <xref linkend="classify"/>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In certain cases it is useful to differentiate between different types of
|
||||
clients and treat them accordingly. It is envisaged that client
|
||||
classification will be used for changing the behavior of almost any part of
|
||||
the DHCP message processing, including the assignment of leases from different
|
||||
pools, the assignment of different options (or different values of the same
|
||||
options) etc. In the current release of the software however, there are
|
||||
only three mechanisms that take advantage of client classification:
|
||||
subnet selection, assignment of different options, and, for cable modems, there
|
||||
are specific options for use with the TFTP server address and the boot file field.
|
||||
<para>In certain cases it is useful to configure the server to differentiate between
|
||||
DHCP clients types and treat them accordingly. It is envisaged that client
|
||||
classification will be used for modifying the behavior of almost any part of
|
||||
the DHCP message processing. In the current release of Kea, there are four
|
||||
mechanisms that take advantage of the client classification in DHCPv4: subnet
|
||||
selection, address pool selection, DHCP options assignment, and, for cable modems,
|
||||
there are specific options for use with the TFTP server address and boot file field.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -2092,6 +2089,12 @@ It is merely echoed by the server
|
||||
class restrictions on subnets, see <xref linkend="classification-subnets"/>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Client classification can also be used to restrict access to specific
|
||||
pools within a subnet. This is useful when to segregate clients belonging
|
||||
to the same subnet into different address ranges.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The process of doing classification is conducted in three steps. The first step
|
||||
is to assess an incoming packet and assign it to zero or more classes. The
|
||||
|
@ -1927,6 +1927,14 @@ should include options from the isc option space:
|
||||
discussion of the classification process see <xref linkend="classify"/>.
|
||||
</para>
|
||||
|
||||
<para>In certain cases it is useful to configure the server to differentiate between
|
||||
DHCP clients types and treat them accordingly. It is envisaged that client
|
||||
classification will be used for modifying the behavior of almost any part of
|
||||
the DHCP message processing. In the current release of Kea, there are three
|
||||
mechanisms that take advantage of the client classification in DHCPv6: subnet
|
||||
selection, address pool selection and DHCP options assignment.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In certain cases it is useful to differentiate between different types
|
||||
of clients and treat them accordingly. It is envisaged that client
|
||||
@ -1950,6 +1958,12 @@ should include options from the isc option space:
|
||||
class restrictions on subnets, see <xref linkend="classification-subnets"/>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Client classification can also be used to restrict access to specific
|
||||
pools within a subnet. This is useful when to segregate clients belonging
|
||||
to the same subnet into different address or prefix ranges.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The process of doing classification is conducted in three steps. The first step
|
||||
is to assess an incoming packet and assign it to zero or more classes. The
|
||||
|
@ -1590,16 +1590,16 @@ static const flex_int16_t yy_rule_linenum[159] =
|
||||
466, 477, 486, 496, 505, 515, 530, 546, 555, 564,
|
||||
573, 582, 602, 622, 631, 641, 650, 659, 668, 678,
|
||||
687, 696, 705, 714, 724, 733, 742, 751, 760, 769,
|
||||
778, 787, 796, 805, 814, 824, 835, 845, 854, 864,
|
||||
874, 884, 894, 904, 913, 923, 932, 941, 950, 959,
|
||||
969, 979, 989, 998, 1007, 1016, 1025, 1034, 1043, 1052,
|
||||
778, 787, 796, 805, 814, 824, 836, 846, 855, 865,
|
||||
875, 885, 895, 905, 914, 924, 933, 942, 951, 960,
|
||||
970, 980, 990, 999, 1008, 1017, 1026, 1035, 1044, 1053,
|
||||
|
||||
1061, 1070, 1079, 1088, 1097, 1106, 1115, 1124, 1133, 1142,
|
||||
1151, 1160, 1169, 1178, 1187, 1196, 1205, 1214, 1223, 1232,
|
||||
1241, 1251, 1261, 1271, 1281, 1291, 1301, 1311, 1321, 1331,
|
||||
1340, 1349, 1358, 1367, 1376, 1385, 1394, 1405, 1418, 1431,
|
||||
1446, 1545, 1550, 1555, 1560, 1561, 1562, 1563, 1564, 1565,
|
||||
1567, 1585, 1598, 1603, 1607, 1609, 1611, 1613
|
||||
1062, 1071, 1080, 1089, 1098, 1107, 1116, 1125, 1134, 1143,
|
||||
1152, 1161, 1170, 1179, 1188, 1197, 1206, 1215, 1224, 1233,
|
||||
1242, 1252, 1262, 1272, 1282, 1292, 1302, 1312, 1322, 1332,
|
||||
1341, 1350, 1359, 1368, 1377, 1386, 1395, 1406, 1419, 1432,
|
||||
1447, 1546, 1551, 1556, 1561, 1562, 1563, 1564, 1565, 1566,
|
||||
1568, 1586, 1599, 1604, 1608, 1610, 1612, 1614
|
||||
} ;
|
||||
|
||||
/* The intent behind this definition is that it'll catch
|
||||
@ -3004,6 +3004,7 @@ YY_RULE_SETUP
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::SUBNET4:
|
||||
case isc::dhcp::Parser4Context::POOLS:
|
||||
case isc::dhcp::Parser4Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser4Context::CLIENT_CLASSES:
|
||||
return isc::dhcp::Dhcp4Parser::make_CLIENT_CLASS(driver.loc_);
|
||||
@ -3014,7 +3015,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 77:
|
||||
YY_RULE_SETUP
|
||||
#line 835 "dhcp4_lexer.ll"
|
||||
#line 836 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::CLIENT_CLASSES:
|
||||
@ -3027,7 +3028,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 78:
|
||||
YY_RULE_SETUP
|
||||
#line 845 "dhcp4_lexer.ll"
|
||||
#line 846 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::SUBNET4:
|
||||
@ -3039,7 +3040,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 79:
|
||||
YY_RULE_SETUP
|
||||
#line 854 "dhcp4_lexer.ll"
|
||||
#line 855 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::HOST_RESERVATION_IDENTIFIERS:
|
||||
@ -3052,7 +3053,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 80:
|
||||
YY_RULE_SETUP
|
||||
#line 864 "dhcp4_lexer.ll"
|
||||
#line 865 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::HOST_RESERVATION_IDENTIFIERS:
|
||||
@ -3065,7 +3066,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 81:
|
||||
YY_RULE_SETUP
|
||||
#line 874 "dhcp4_lexer.ll"
|
||||
#line 875 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::HOST_RESERVATION_IDENTIFIERS:
|
||||
@ -3078,7 +3079,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 82:
|
||||
YY_RULE_SETUP
|
||||
#line 884 "dhcp4_lexer.ll"
|
||||
#line 885 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::HOST_RESERVATION_IDENTIFIERS:
|
||||
@ -3091,7 +3092,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 83:
|
||||
YY_RULE_SETUP
|
||||
#line 894 "dhcp4_lexer.ll"
|
||||
#line 895 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::HOST_RESERVATION_IDENTIFIERS:
|
||||
@ -3104,7 +3105,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 84:
|
||||
YY_RULE_SETUP
|
||||
#line 904 "dhcp4_lexer.ll"
|
||||
#line 905 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::RESERVATIONS:
|
||||
@ -3116,7 +3117,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 85:
|
||||
YY_RULE_SETUP
|
||||
#line 913 "dhcp4_lexer.ll"
|
||||
#line 914 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::OPTION_DEF:
|
||||
@ -3129,7 +3130,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 86:
|
||||
YY_RULE_SETUP
|
||||
#line 923 "dhcp4_lexer.ll"
|
||||
#line 924 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::OPTION_DATA:
|
||||
@ -3141,7 +3142,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 87:
|
||||
YY_RULE_SETUP
|
||||
#line 932 "dhcp4_lexer.ll"
|
||||
#line 933 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::OPTION_DEF:
|
||||
@ -3153,7 +3154,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 88:
|
||||
YY_RULE_SETUP
|
||||
#line 941 "dhcp4_lexer.ll"
|
||||
#line 942 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::OPTION_DEF:
|
||||
@ -3165,7 +3166,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 89:
|
||||
YY_RULE_SETUP
|
||||
#line 950 "dhcp4_lexer.ll"
|
||||
#line 951 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::OPTION_DEF:
|
||||
@ -3177,7 +3178,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 90:
|
||||
YY_RULE_SETUP
|
||||
#line 959 "dhcp4_lexer.ll"
|
||||
#line 960 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::SUBNET4:
|
||||
@ -3190,7 +3191,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 91:
|
||||
YY_RULE_SETUP
|
||||
#line 969 "dhcp4_lexer.ll"
|
||||
#line 970 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::RELAY:
|
||||
@ -3203,7 +3204,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 92:
|
||||
YY_RULE_SETUP
|
||||
#line 979 "dhcp4_lexer.ll"
|
||||
#line 980 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP4:
|
||||
@ -3215,7 +3216,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 93:
|
||||
YY_RULE_SETUP
|
||||
#line 989 "dhcp4_lexer.ll"
|
||||
#line 990 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::HOOKS_LIBRARIES:
|
||||
@ -3227,7 +3228,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 94:
|
||||
YY_RULE_SETUP
|
||||
#line 998 "dhcp4_lexer.ll"
|
||||
#line 999 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::HOOKS_LIBRARIES:
|
||||
@ -3239,7 +3240,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 95:
|
||||
YY_RULE_SETUP
|
||||
#line 1007 "dhcp4_lexer.ll"
|
||||
#line 1008 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP4:
|
||||
@ -3251,7 +3252,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 96:
|
||||
YY_RULE_SETUP
|
||||
#line 1016 "dhcp4_lexer.ll"
|
||||
#line 1017 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::EXPIRED_LEASES_PROCESSING:
|
||||
@ -3263,7 +3264,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 97:
|
||||
YY_RULE_SETUP
|
||||
#line 1025 "dhcp4_lexer.ll"
|
||||
#line 1026 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::EXPIRED_LEASES_PROCESSING:
|
||||
@ -3275,7 +3276,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 98:
|
||||
YY_RULE_SETUP
|
||||
#line 1034 "dhcp4_lexer.ll"
|
||||
#line 1035 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::EXPIRED_LEASES_PROCESSING:
|
||||
@ -3287,7 +3288,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 99:
|
||||
YY_RULE_SETUP
|
||||
#line 1043 "dhcp4_lexer.ll"
|
||||
#line 1044 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::EXPIRED_LEASES_PROCESSING:
|
||||
@ -3299,7 +3300,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 100:
|
||||
YY_RULE_SETUP
|
||||
#line 1052 "dhcp4_lexer.ll"
|
||||
#line 1053 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::EXPIRED_LEASES_PROCESSING:
|
||||
@ -3311,7 +3312,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 101:
|
||||
YY_RULE_SETUP
|
||||
#line 1061 "dhcp4_lexer.ll"
|
||||
#line 1062 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::EXPIRED_LEASES_PROCESSING:
|
||||
@ -3323,7 +3324,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 102:
|
||||
YY_RULE_SETUP
|
||||
#line 1070 "dhcp4_lexer.ll"
|
||||
#line 1071 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP4:
|
||||
@ -3335,7 +3336,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 103:
|
||||
YY_RULE_SETUP
|
||||
#line 1079 "dhcp4_lexer.ll"
|
||||
#line 1080 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP4:
|
||||
@ -3347,7 +3348,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 104:
|
||||
YY_RULE_SETUP
|
||||
#line 1088 "dhcp4_lexer.ll"
|
||||
#line 1089 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::CONTROL_SOCKET:
|
||||
@ -3359,7 +3360,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 105:
|
||||
YY_RULE_SETUP
|
||||
#line 1097 "dhcp4_lexer.ll"
|
||||
#line 1098 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::CONTROL_SOCKET:
|
||||
@ -3371,7 +3372,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 106:
|
||||
YY_RULE_SETUP
|
||||
#line 1106 "dhcp4_lexer.ll"
|
||||
#line 1107 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP4:
|
||||
@ -3383,7 +3384,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 107:
|
||||
YY_RULE_SETUP
|
||||
#line 1115 "dhcp4_lexer.ll"
|
||||
#line 1116 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3395,7 +3396,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 108:
|
||||
YY_RULE_SETUP
|
||||
#line 1124 "dhcp4_lexer.ll"
|
||||
#line 1125 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3407,7 +3408,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 109:
|
||||
YY_RULE_SETUP
|
||||
#line 1133 "dhcp4_lexer.ll"
|
||||
#line 1134 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3419,7 +3420,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 110:
|
||||
YY_RULE_SETUP
|
||||
#line 1142 "dhcp4_lexer.ll"
|
||||
#line 1143 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3431,7 +3432,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 111:
|
||||
YY_RULE_SETUP
|
||||
#line 1151 "dhcp4_lexer.ll"
|
||||
#line 1152 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3443,7 +3444,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 112:
|
||||
YY_RULE_SETUP
|
||||
#line 1160 "dhcp4_lexer.ll"
|
||||
#line 1161 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3455,7 +3456,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 113:
|
||||
YY_RULE_SETUP
|
||||
#line 1169 "dhcp4_lexer.ll"
|
||||
#line 1170 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3467,7 +3468,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 114:
|
||||
YY_RULE_SETUP
|
||||
#line 1178 "dhcp4_lexer.ll"
|
||||
#line 1179 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3479,7 +3480,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 115:
|
||||
YY_RULE_SETUP
|
||||
#line 1187 "dhcp4_lexer.ll"
|
||||
#line 1188 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3491,7 +3492,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 116:
|
||||
YY_RULE_SETUP
|
||||
#line 1196 "dhcp4_lexer.ll"
|
||||
#line 1197 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3503,7 +3504,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 117:
|
||||
YY_RULE_SETUP
|
||||
#line 1205 "dhcp4_lexer.ll"
|
||||
#line 1206 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3515,7 +3516,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 118:
|
||||
YY_RULE_SETUP
|
||||
#line 1214 "dhcp4_lexer.ll"
|
||||
#line 1215 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3527,7 +3528,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 119:
|
||||
YY_RULE_SETUP
|
||||
#line 1223 "dhcp4_lexer.ll"
|
||||
#line 1224 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3539,7 +3540,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 120:
|
||||
YY_RULE_SETUP
|
||||
#line 1232 "dhcp4_lexer.ll"
|
||||
#line 1233 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP_DDNS:
|
||||
@ -3551,7 +3552,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 121:
|
||||
YY_RULE_SETUP
|
||||
#line 1241 "dhcp4_lexer.ll"
|
||||
#line 1242 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* dhcp-ddns value keywords are case insensitive */
|
||||
if (driver.ctx_ == isc::dhcp::Parser4Context::NCR_PROTOCOL) {
|
||||
@ -3564,7 +3565,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 122:
|
||||
YY_RULE_SETUP
|
||||
#line 1251 "dhcp4_lexer.ll"
|
||||
#line 1252 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* dhcp-ddns value keywords are case insensitive */
|
||||
if (driver.ctx_ == isc::dhcp::Parser4Context::NCR_PROTOCOL) {
|
||||
@ -3577,7 +3578,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 123:
|
||||
YY_RULE_SETUP
|
||||
#line 1261 "dhcp4_lexer.ll"
|
||||
#line 1262 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* dhcp-ddns value keywords are case insensitive */
|
||||
if (driver.ctx_ == isc::dhcp::Parser4Context::NCR_FORMAT) {
|
||||
@ -3590,7 +3591,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 124:
|
||||
YY_RULE_SETUP
|
||||
#line 1271 "dhcp4_lexer.ll"
|
||||
#line 1272 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* dhcp-ddns value keywords are case insensitive */
|
||||
if (driver.ctx_ == isc::dhcp::Parser4Context::REPLACE_CLIENT_NAME) {
|
||||
@ -3603,7 +3604,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 125:
|
||||
YY_RULE_SETUP
|
||||
#line 1281 "dhcp4_lexer.ll"
|
||||
#line 1282 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* dhcp-ddns value keywords are case insensitive */
|
||||
if (driver.ctx_ == isc::dhcp::Parser4Context::REPLACE_CLIENT_NAME) {
|
||||
@ -3616,7 +3617,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 126:
|
||||
YY_RULE_SETUP
|
||||
#line 1291 "dhcp4_lexer.ll"
|
||||
#line 1292 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* dhcp-ddns value keywords are case insensitive */
|
||||
if (driver.ctx_ == isc::dhcp::Parser4Context::REPLACE_CLIENT_NAME) {
|
||||
@ -3629,7 +3630,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 127:
|
||||
YY_RULE_SETUP
|
||||
#line 1301 "dhcp4_lexer.ll"
|
||||
#line 1302 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* dhcp-ddns value keywords are case insensitive */
|
||||
if (driver.ctx_ == isc::dhcp::Parser4Context::REPLACE_CLIENT_NAME) {
|
||||
@ -3642,7 +3643,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 128:
|
||||
YY_RULE_SETUP
|
||||
#line 1311 "dhcp4_lexer.ll"
|
||||
#line 1312 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* dhcp-ddns value keywords are case insensitive */
|
||||
if (driver.ctx_ == isc::dhcp::Parser4Context::REPLACE_CLIENT_NAME) {
|
||||
@ -3655,7 +3656,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 129:
|
||||
YY_RULE_SETUP
|
||||
#line 1321 "dhcp4_lexer.ll"
|
||||
#line 1322 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* dhcp-ddns value keywords are case insensitive */
|
||||
if (driver.ctx_ == isc::dhcp::Parser4Context::REPLACE_CLIENT_NAME) {
|
||||
@ -3668,7 +3669,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 130:
|
||||
YY_RULE_SETUP
|
||||
#line 1331 "dhcp4_lexer.ll"
|
||||
#line 1332 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::CONFIG:
|
||||
@ -3680,7 +3681,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 131:
|
||||
YY_RULE_SETUP
|
||||
#line 1340 "dhcp4_lexer.ll"
|
||||
#line 1341 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::CONFIG:
|
||||
@ -3692,7 +3693,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 132:
|
||||
YY_RULE_SETUP
|
||||
#line 1349 "dhcp4_lexer.ll"
|
||||
#line 1350 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::CONFIG:
|
||||
@ -3704,7 +3705,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 133:
|
||||
YY_RULE_SETUP
|
||||
#line 1358 "dhcp4_lexer.ll"
|
||||
#line 1359 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::SUBNET4:
|
||||
@ -3716,7 +3717,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 134:
|
||||
YY_RULE_SETUP
|
||||
#line 1367 "dhcp4_lexer.ll"
|
||||
#line 1368 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::SUBNET4:
|
||||
@ -3728,7 +3729,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 135:
|
||||
YY_RULE_SETUP
|
||||
#line 1376 "dhcp4_lexer.ll"
|
||||
#line 1377 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::SUBNET4:
|
||||
@ -3740,7 +3741,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 136:
|
||||
YY_RULE_SETUP
|
||||
#line 1385 "dhcp4_lexer.ll"
|
||||
#line 1386 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP4:
|
||||
@ -3752,7 +3753,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 137:
|
||||
YY_RULE_SETUP
|
||||
#line 1394 "dhcp4_lexer.ll"
|
||||
#line 1395 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP4:
|
||||
@ -3766,7 +3767,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 138:
|
||||
YY_RULE_SETUP
|
||||
#line 1405 "dhcp4_lexer.ll"
|
||||
#line 1406 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP4:
|
||||
@ -3782,7 +3783,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 139:
|
||||
YY_RULE_SETUP
|
||||
#line 1418 "dhcp4_lexer.ll"
|
||||
#line 1419 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP4:
|
||||
@ -3798,7 +3799,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 140:
|
||||
YY_RULE_SETUP
|
||||
#line 1431 "dhcp4_lexer.ll"
|
||||
#line 1432 "dhcp4_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP4:
|
||||
@ -3814,7 +3815,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 141:
|
||||
YY_RULE_SETUP
|
||||
#line 1446 "dhcp4_lexer.ll"
|
||||
#line 1447 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* A string has been matched. It contains the actual string and single quotes.
|
||||
We need to get those quotes out of the way and just use its content, e.g.
|
||||
@ -3917,7 +3918,7 @@ YY_RULE_SETUP
|
||||
case 142:
|
||||
/* rule 142 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 1545 "dhcp4_lexer.ll"
|
||||
#line 1546 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* Bad string with a forbidden control character inside */
|
||||
driver.error(driver.loc_, "Invalid control in " + std::string(yytext));
|
||||
@ -3926,7 +3927,7 @@ YY_RULE_SETUP
|
||||
case 143:
|
||||
/* rule 143 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 1550 "dhcp4_lexer.ll"
|
||||
#line 1551 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* Bad string with a bad escape inside */
|
||||
driver.error(driver.loc_, "Bad escape in " + std::string(yytext));
|
||||
@ -3934,7 +3935,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 144:
|
||||
YY_RULE_SETUP
|
||||
#line 1555 "dhcp4_lexer.ll"
|
||||
#line 1556 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* Bad string with an open escape at the end */
|
||||
driver.error(driver.loc_, "Overflow escape in " + std::string(yytext));
|
||||
@ -3942,37 +3943,37 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 145:
|
||||
YY_RULE_SETUP
|
||||
#line 1560 "dhcp4_lexer.ll"
|
||||
#line 1561 "dhcp4_lexer.ll"
|
||||
{ return isc::dhcp::Dhcp4Parser::make_LSQUARE_BRACKET(driver.loc_); }
|
||||
YY_BREAK
|
||||
case 146:
|
||||
YY_RULE_SETUP
|
||||
#line 1561 "dhcp4_lexer.ll"
|
||||
#line 1562 "dhcp4_lexer.ll"
|
||||
{ return isc::dhcp::Dhcp4Parser::make_RSQUARE_BRACKET(driver.loc_); }
|
||||
YY_BREAK
|
||||
case 147:
|
||||
YY_RULE_SETUP
|
||||
#line 1562 "dhcp4_lexer.ll"
|
||||
#line 1563 "dhcp4_lexer.ll"
|
||||
{ return isc::dhcp::Dhcp4Parser::make_LCURLY_BRACKET(driver.loc_); }
|
||||
YY_BREAK
|
||||
case 148:
|
||||
YY_RULE_SETUP
|
||||
#line 1563 "dhcp4_lexer.ll"
|
||||
#line 1564 "dhcp4_lexer.ll"
|
||||
{ return isc::dhcp::Dhcp4Parser::make_RCURLY_BRACKET(driver.loc_); }
|
||||
YY_BREAK
|
||||
case 149:
|
||||
YY_RULE_SETUP
|
||||
#line 1564 "dhcp4_lexer.ll"
|
||||
#line 1565 "dhcp4_lexer.ll"
|
||||
{ return isc::dhcp::Dhcp4Parser::make_COMMA(driver.loc_); }
|
||||
YY_BREAK
|
||||
case 150:
|
||||
YY_RULE_SETUP
|
||||
#line 1565 "dhcp4_lexer.ll"
|
||||
#line 1566 "dhcp4_lexer.ll"
|
||||
{ return isc::dhcp::Dhcp4Parser::make_COLON(driver.loc_); }
|
||||
YY_BREAK
|
||||
case 151:
|
||||
YY_RULE_SETUP
|
||||
#line 1567 "dhcp4_lexer.ll"
|
||||
#line 1568 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* An integer was found. */
|
||||
std::string tmp(yytext);
|
||||
@ -3993,7 +3994,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 152:
|
||||
YY_RULE_SETUP
|
||||
#line 1585 "dhcp4_lexer.ll"
|
||||
#line 1586 "dhcp4_lexer.ll"
|
||||
{
|
||||
/* A floating point was found. */
|
||||
std::string tmp(yytext);
|
||||
@ -4009,7 +4010,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 153:
|
||||
YY_RULE_SETUP
|
||||
#line 1598 "dhcp4_lexer.ll"
|
||||
#line 1599 "dhcp4_lexer.ll"
|
||||
{
|
||||
string tmp(yytext);
|
||||
return isc::dhcp::Dhcp4Parser::make_BOOLEAN(tmp == "true", driver.loc_);
|
||||
@ -4017,33 +4018,33 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 154:
|
||||
YY_RULE_SETUP
|
||||
#line 1603 "dhcp4_lexer.ll"
|
||||
#line 1604 "dhcp4_lexer.ll"
|
||||
{
|
||||
return isc::dhcp::Dhcp4Parser::make_NULL_TYPE(driver.loc_);
|
||||
}
|
||||
YY_BREAK
|
||||
case 155:
|
||||
YY_RULE_SETUP
|
||||
#line 1607 "dhcp4_lexer.ll"
|
||||
#line 1608 "dhcp4_lexer.ll"
|
||||
driver.error (driver.loc_, "JSON true reserved keyword is lower case only");
|
||||
YY_BREAK
|
||||
case 156:
|
||||
YY_RULE_SETUP
|
||||
#line 1609 "dhcp4_lexer.ll"
|
||||
#line 1610 "dhcp4_lexer.ll"
|
||||
driver.error (driver.loc_, "JSON false reserved keyword is lower case only");
|
||||
YY_BREAK
|
||||
case 157:
|
||||
YY_RULE_SETUP
|
||||
#line 1611 "dhcp4_lexer.ll"
|
||||
#line 1612 "dhcp4_lexer.ll"
|
||||
driver.error (driver.loc_, "JSON null reserved keyword is lower case only");
|
||||
YY_BREAK
|
||||
case 158:
|
||||
YY_RULE_SETUP
|
||||
#line 1613 "dhcp4_lexer.ll"
|
||||
#line 1614 "dhcp4_lexer.ll"
|
||||
driver.error (driver.loc_, "Invalid character: " + std::string(yytext));
|
||||
YY_BREAK
|
||||
case YY_STATE_EOF(INITIAL):
|
||||
#line 1615 "dhcp4_lexer.ll"
|
||||
#line 1616 "dhcp4_lexer.ll"
|
||||
{
|
||||
if (driver.states_.empty()) {
|
||||
return isc::dhcp::Dhcp4Parser::make_END(driver.loc_);
|
||||
@ -4069,10 +4070,10 @@ case YY_STATE_EOF(INITIAL):
|
||||
YY_BREAK
|
||||
case 159:
|
||||
YY_RULE_SETUP
|
||||
#line 1638 "dhcp4_lexer.ll"
|
||||
#line 1639 "dhcp4_lexer.ll"
|
||||
ECHO;
|
||||
YY_BREAK
|
||||
#line 4075 "dhcp4_lexer.cc"
|
||||
#line 4076 "dhcp4_lexer.cc"
|
||||
|
||||
case YY_END_OF_BUFFER:
|
||||
{
|
||||
@ -5177,7 +5178,7 @@ void yyfree (void * ptr )
|
||||
|
||||
/* %ok-for-header */
|
||||
|
||||
#line 1638 "dhcp4_lexer.ll"
|
||||
#line 1639 "dhcp4_lexer.ll"
|
||||
|
||||
|
||||
using namespace isc::dhcp;
|
||||
|
@ -823,6 +823,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
\"client-class\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::SUBNET4:
|
||||
case isc::dhcp::Parser4Context::POOLS:
|
||||
case isc::dhcp::Parser4Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser4Context::CLIENT_CLASSES:
|
||||
return isc::dhcp::Dhcp4Parser::make_CLIENT_CLASS(driver.loc_);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1416,8 +1416,8 @@ namespace isc { namespace dhcp {
|
||||
enum
|
||||
{
|
||||
yyeof_ = 0,
|
||||
yylast_ = 892, ///< Last index in yytable_.
|
||||
yynnts_ = 337, ///< Number of nonterminal symbols.
|
||||
yylast_ = 886, ///< Last index in yytable_.
|
||||
yynnts_ = 338, ///< Number of nonterminal symbols.
|
||||
yyfinal_ = 28, ///< Termination state number.
|
||||
yyterror_ = 1,
|
||||
yyerrcode_ = 256,
|
||||
@ -1519,8 +1519,8 @@ namespace isc { namespace dhcp {
|
||||
case 212: // outbound_interface_value
|
||||
case 222: // db_type
|
||||
case 299: // hr_mode
|
||||
case 444: // ncr_protocol_value
|
||||
case 452: // replace_client_name_value
|
||||
case 445: // ncr_protocol_value
|
||||
case 453: // replace_client_name_value
|
||||
value.copy< ElementPtr > (other.value);
|
||||
break;
|
||||
|
||||
@ -1563,8 +1563,8 @@ namespace isc { namespace dhcp {
|
||||
case 212: // outbound_interface_value
|
||||
case 222: // db_type
|
||||
case 299: // hr_mode
|
||||
case 444: // ncr_protocol_value
|
||||
case 452: // replace_client_name_value
|
||||
case 445: // ncr_protocol_value
|
||||
case 453: // replace_client_name_value
|
||||
value.copy< ElementPtr > (v);
|
||||
break;
|
||||
|
||||
@ -1666,8 +1666,8 @@ namespace isc { namespace dhcp {
|
||||
case 212: // outbound_interface_value
|
||||
case 222: // db_type
|
||||
case 299: // hr_mode
|
||||
case 444: // ncr_protocol_value
|
||||
case 452: // replace_client_name_value
|
||||
case 445: // ncr_protocol_value
|
||||
case 453: // replace_client_name_value
|
||||
value.template destroy< ElementPtr > ();
|
||||
break;
|
||||
|
||||
@ -1716,8 +1716,8 @@ namespace isc { namespace dhcp {
|
||||
case 212: // outbound_interface_value
|
||||
case 222: // db_type
|
||||
case 299: // hr_mode
|
||||
case 444: // ncr_protocol_value
|
||||
case 452: // replace_client_name_value
|
||||
case 445: // ncr_protocol_value
|
||||
case 453: // replace_client_name_value
|
||||
value.move< ElementPtr > (s.value);
|
||||
break;
|
||||
|
||||
|
@ -1344,6 +1344,7 @@ pool_params: pool_param
|
||||
|
||||
pool_param: pool_entry
|
||||
| option_data_list
|
||||
| client_class
|
||||
| user_context
|
||||
| comment
|
||||
| unknown_map_entry
|
||||
@ -1598,11 +1599,11 @@ client_classes: CLIENT_CLASSES {
|
||||
ctx.leave();
|
||||
};
|
||||
|
||||
client_classes_list: client_class
|
||||
| client_classes_list COMMA client_class
|
||||
client_classes_list: client_class_entry
|
||||
| client_classes_list COMMA client_class_entry
|
||||
;
|
||||
|
||||
client_class: LCURLY_BRACKET {
|
||||
client_class_entry: LCURLY_BRACKET {
|
||||
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
|
||||
ctx.stack_.back()->add(m);
|
||||
ctx.stack_.push_back(m);
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated 201712311009
|
||||
// Generated 201801182315
|
||||
// A Bison parser, made by GNU Bison 3.0.4.
|
||||
|
||||
// Locations for Bison parsers in C++
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated 201712311009
|
||||
// Generated 201801182315
|
||||
// A Bison parser, made by GNU Bison 3.0.4.
|
||||
|
||||
// Positions for Bison parsers in C++
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated 201712311009
|
||||
// Generated 201801182315
|
||||
// A Bison parser, made by GNU Bison 3.0.4.
|
||||
|
||||
// Stack handling for Bison parsers in C++
|
||||
|
@ -4100,6 +4100,7 @@ TEST_F(Dhcp4ParserTest, classifySubnets) {
|
||||
|
||||
ConstElementPtr json;
|
||||
ASSERT_NO_THROW(json = parseDHCP4(config));
|
||||
extractConfig(config);
|
||||
|
||||
EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
|
||||
checkResult(x, 0);
|
||||
@ -4157,6 +4158,95 @@ TEST_F(Dhcp4ParserTest, classifySubnets) {
|
||||
EXPECT_TRUE (subnets->at(3)->clientSupported(classes));
|
||||
}
|
||||
|
||||
// Goal of this test is to verify that multiple pools can be configured
|
||||
// with defined client classes.
|
||||
TEST_F(Dhcp4ParserTest, classifyPools) {
|
||||
ConstElementPtr x;
|
||||
string config = "{ " + genIfaceConfig() + "," +
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { "
|
||||
" \"pool\": \"192.0.2.1 - 192.0.2.100\", "
|
||||
" \"client-class\": \"alpha\" "
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"192.0.3.101 - 192.0.3.150\", "
|
||||
" \"client-class\": \"beta\" "
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"192.0.4.101 - 192.0.4.150\", "
|
||||
" \"client-class\": \"gamma\" "
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"192.0.5.101 - 192.0.5.150\" "
|
||||
" } ],"
|
||||
" \"subnet\": \"192.0.0.0/16\" "
|
||||
" } ],"
|
||||
"\"valid-lifetime\": 4000 }";
|
||||
|
||||
ConstElementPtr json;
|
||||
ASSERT_NO_THROW(json = parseDHCP4(config, true));
|
||||
extractConfig(config);
|
||||
|
||||
EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
const Subnet4Collection* subnets =
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll();
|
||||
ASSERT_TRUE(subnets);
|
||||
ASSERT_EQ(1, subnets->size());
|
||||
const PoolCollection& pools = subnets->at(0)->getPools(Lease::TYPE_V4);
|
||||
ASSERT_EQ(4, pools.size()); // We expect 4 pools
|
||||
|
||||
// Let's check if client belonging to alpha class is supported in pool[0]
|
||||
// and not supported in any other pool (except pool[3], which allows
|
||||
// everyone).
|
||||
ClientClasses classes;
|
||||
classes.insert("alpha");
|
||||
EXPECT_TRUE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE(pools.at(3)->clientSupported(classes));
|
||||
|
||||
// Let's check if client belonging to beta class is supported in pool[1]
|
||||
// and not supported in any other pool (except pools[3], which allows
|
||||
// everyone).
|
||||
classes.clear();
|
||||
classes.insert("beta");
|
||||
EXPECT_FALSE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_TRUE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE(pools.at(3)->clientSupported(classes));
|
||||
|
||||
// Let's check if client belonging to gamma class is supported in pool[2]
|
||||
// and not supported in any other pool (except pool[3], which allows
|
||||
// everyone).
|
||||
classes.clear();
|
||||
classes.insert("gamma");
|
||||
EXPECT_FALSE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_TRUE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE(pools.at(3)->clientSupported(classes));
|
||||
|
||||
// Let's check if client belonging to some other class (not mentioned in
|
||||
// the config) is supported only in pool[3], which allows everyone.
|
||||
classes.clear();
|
||||
classes.insert("delta");
|
||||
EXPECT_FALSE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE(pools.at(3)->clientSupported(classes));
|
||||
|
||||
// Finally, let's check class-less client. He should be allowed only in
|
||||
// the last pool, which does not have any class restrictions.
|
||||
classes.clear();
|
||||
EXPECT_FALSE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE(pools.at(3)->clientSupported(classes));
|
||||
}
|
||||
|
||||
// This test verifies that the host reservations can be specified for
|
||||
// respective IPv4 subnets.
|
||||
TEST_F(Dhcp4ParserTest, reservations) {
|
||||
|
@ -2322,6 +2322,75 @@ TEST_F(Dhcpv4SrvTest, clientClassify) {
|
||||
EXPECT_FALSE(drop);
|
||||
}
|
||||
|
||||
// Checks if the client-class field is indeed used for pool selection.
|
||||
TEST_F(Dhcpv4SrvTest, clientPoolClassify) {
|
||||
IfaceMgrTestConfig test_config(true);
|
||||
IfaceMgr::instance().openSockets4();
|
||||
|
||||
NakedDhcpv4Srv srv(0);
|
||||
|
||||
// This test configures 2 pools.
|
||||
// The second pool does not play any role here. The client's
|
||||
// IP address belongs to the first pool, so only that first
|
||||
// pool is being tested.
|
||||
string config = "{ \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
"},"
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet4\": [ "
|
||||
"{ \"pools\": [ { "
|
||||
" \"pool\": \"192.0.2.1 - 192.0.2.100\", "
|
||||
" \"client-class\": \"foo\" }, "
|
||||
" { \"pool\": \"192.0.3.1 - 192.0.3.100\", "
|
||||
" \"client-class\": \"xyzzy\" } ], "
|
||||
" \"subnet\": \"192.0.0.0/16\" } "
|
||||
"],"
|
||||
"\"valid-lifetime\": 4000 }";
|
||||
|
||||
ConstElementPtr json;
|
||||
ASSERT_NO_THROW(json = parseDHCP4(config, true));
|
||||
|
||||
ConstElementPtr status;
|
||||
EXPECT_NO_THROW(status = configureDhcp4Server(srv, json));
|
||||
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
// check if returned status is OK
|
||||
ASSERT_TRUE(status);
|
||||
comment_ = config::parseAnswer(rcode_, status);
|
||||
ASSERT_EQ(0, rcode_);
|
||||
|
||||
// Create a simple packet that we'll use for classification
|
||||
Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
|
||||
dis->setRemoteAddr(IOAddress("192.0.2.1"));
|
||||
dis->setCiaddr(IOAddress("192.0.2.1"));
|
||||
dis->setIface("eth0");
|
||||
OptionPtr clientid = generateClientId();
|
||||
dis->addOption(clientid);
|
||||
|
||||
// This discover does not belong to foo class, so it will not
|
||||
// be serviced
|
||||
Pkt4Ptr offer = srv.processDiscover(dis);
|
||||
EXPECT_FALSE(offer);
|
||||
|
||||
// Let's add the packet to bar class and try again.
|
||||
dis->addClass("bar");
|
||||
|
||||
// Still not supported, because it belongs to wrong class.
|
||||
offer = srv.processDiscover(dis);
|
||||
EXPECT_FALSE(offer);
|
||||
|
||||
// Let's add it to matching class.
|
||||
dis->addClass("foo");
|
||||
|
||||
// This time it should work
|
||||
offer = srv.processDiscover(dis);
|
||||
ASSERT_TRUE(offer);
|
||||
EXPECT_EQ(DHCPOFFER, offer->getType());
|
||||
EXPECT_FALSE(offer->getYiaddr().isV4Zero());
|
||||
}
|
||||
|
||||
// Verifies last resort option 43 is backward compatible
|
||||
TEST_F(Dhcpv4SrvTest, option43LastResort) {
|
||||
IfaceMgrTestConfig test_config(true);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -700,7 +700,7 @@ const char* NETWORKS_CONFIG[] = {
|
||||
|
||||
// Configuration #13.
|
||||
// - 2 classes
|
||||
// - 2 shared networks, each with 1 subnet and client class restricton
|
||||
// - 2 shared networks, each with 1 subnet and client class restriction
|
||||
"{"
|
||||
" \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
@ -861,6 +861,158 @@ const char* NETWORKS_CONFIG[] = {
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
"}",
|
||||
|
||||
// Configuration #16
|
||||
// - 1 shared network with 1 subnet and 2 pools (first pool has class restriction)
|
||||
"{"
|
||||
" \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
" },"
|
||||
" \"client-classes\": ["
|
||||
" {"
|
||||
" \"name\": \"a-devices\","
|
||||
" \"test\": \"option[93].hex == 0x0001\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"b-devices\","
|
||||
" \"test\": \"option[93].hex == 0x0002\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"valid-lifetime\": 600,"
|
||||
" \"shared-networks\": ["
|
||||
" {"
|
||||
" \"name\": \"frog\","
|
||||
" \"interface\": \"eth1\","
|
||||
" \"subnet4\": ["
|
||||
" {"
|
||||
" \"subnet\": \"192.0.2.0/24\","
|
||||
" \"id\": 10,"
|
||||
" \"pools\": ["
|
||||
" {"
|
||||
" \"pool\": \"192.0.2.1 - 192.0.2.63\","
|
||||
" \"client-class\": \"a-devices\""
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"192.0.2.100 - 192.0.2.100\""
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
"}",
|
||||
|
||||
// Configuration #17
|
||||
// - 1 shared network with 1 subnet and 2 pools (each with class restriction)
|
||||
"{"
|
||||
" \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
" },"
|
||||
" \"client-classes\": ["
|
||||
" {"
|
||||
" \"name\": \"a-devices\","
|
||||
" \"test\": \"option[93].hex == 0x0001\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"b-devices\","
|
||||
" \"test\": \"option[93].hex == 0x0002\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"valid-lifetime\": 600,"
|
||||
" \"shared-networks\": ["
|
||||
" {"
|
||||
" \"name\": \"frog\","
|
||||
" \"interface\": \"eth1\","
|
||||
" \"subnet4\": ["
|
||||
" {"
|
||||
" \"subnet\": \"192.0.2.0/24\","
|
||||
" \"id\": 10,"
|
||||
" \"pools\": ["
|
||||
" {"
|
||||
" \"pool\": \"192.0.2.1 - 192.0.2.63\","
|
||||
" \"client-class\": \"a-devices\""
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"192.0.2.100 - 192.0.2.100\","
|
||||
" \"client-class\": \"b-devices\""
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
"}",
|
||||
|
||||
// Configuration #18
|
||||
// - plain subnet and 2 pools (first pool has class restriction)
|
||||
"{"
|
||||
" \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
" },"
|
||||
" \"client-classes\": ["
|
||||
" {"
|
||||
" \"name\": \"a-devices\","
|
||||
" \"test\": \"option[93].hex == 0x0001\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"b-devices\","
|
||||
" \"test\": \"option[93].hex == 0x0002\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"valid-lifetime\": 600,"
|
||||
" \"subnet4\": ["
|
||||
" {"
|
||||
" \"subnet\": \"192.0.2.0/24\","
|
||||
" \"id\": 10,"
|
||||
" \"interface\": \"eth1\","
|
||||
" \"pools\": ["
|
||||
" {"
|
||||
" \"pool\": \"192.0.2.1 - 192.0.2.63\","
|
||||
" \"client-class\": \"a-devices\""
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"192.0.2.100 - 192.0.2.100\""
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
"}",
|
||||
|
||||
// Configuration #19
|
||||
// - plain subnet and 2 pools (each with class restriction)
|
||||
"{"
|
||||
" \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
" },"
|
||||
" \"client-classes\": ["
|
||||
" {"
|
||||
" \"name\": \"a-devices\","
|
||||
" \"test\": \"option[93].hex == 0x0001\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"b-devices\","
|
||||
" \"test\": \"option[93].hex == 0x0002\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"valid-lifetime\": 600,"
|
||||
" \"subnet4\": ["
|
||||
" {"
|
||||
" \"subnet\": \"192.0.2.0/24\","
|
||||
" \"id\": 10,"
|
||||
" \"interface\": \"eth1\","
|
||||
" \"pools\": ["
|
||||
" {"
|
||||
" \"pool\": \"192.0.2.1 - 192.0.2.63\","
|
||||
" \"client-class\": \"a-devices\""
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"192.0.2.100 - 192.0.2.100\","
|
||||
" \"client-class\": \"b-devices\""
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
"}"
|
||||
|
||||
};
|
||||
@ -1813,4 +1965,123 @@ TEST_F(Dhcpv4SharedNetworkTest, customServerIdentifier) {
|
||||
EXPECT_EQ("2.3.4.5", client2.config_.serverid_.toText());
|
||||
}
|
||||
|
||||
// Access to a pool within shared network is restricted by client
|
||||
// classification.
|
||||
TEST_F(Dhcpv4SharedNetworkTest, poolInSharedNetworkSelectedByClass) {
|
||||
// Create client #1
|
||||
Dhcp4Client client1(Dhcp4Client::SELECTING);
|
||||
client1.setIfaceName("eth1");
|
||||
|
||||
// Configure the server with one shared network including one subnet and
|
||||
// in 2 pools in it. The access to one of the pools is restricted
|
||||
// by client classification.
|
||||
configure(NETWORKS_CONFIG[16], *client1.getServer());
|
||||
|
||||
// Client #1 requests an address in the restricted pool but can't be assigned
|
||||
// this address because the client doesn't belong to a certain class.
|
||||
testAssigned([this, &client1] {
|
||||
doDORA(client1, "192.0.2.100", "192.0.2.63");
|
||||
});
|
||||
|
||||
// Release the lease that the client has got, because we'll need this address
|
||||
// further in the test.
|
||||
testAssigned([this, &client1] {
|
||||
ASSERT_NO_THROW(client1.doRelease());
|
||||
});
|
||||
|
||||
// Add option93 which would cause the client to be classified as "a-devices".
|
||||
OptionPtr option93(new OptionUint16(Option::V4, 93, 0x0001));
|
||||
client1.addExtraOption(option93);
|
||||
|
||||
// This time, the allocation of the address provided as hint should be successful.
|
||||
testAssigned([this, &client1] {
|
||||
doDORA(client1, "192.0.2.63", "192.0.2.63");
|
||||
});
|
||||
|
||||
// Client 2 should be assigned an address from the unrestricted pool.
|
||||
Dhcp4Client client2(client1.getServer(), Dhcp4Client::SELECTING);
|
||||
client2.setIfaceName("eth1");
|
||||
testAssigned([this, &client2] {
|
||||
doDORA(client2, "192.0.2.100");
|
||||
});
|
||||
|
||||
// Now, let's reconfigure the server to also apply restrictions on the
|
||||
// pool to which client2 now belongs.
|
||||
configure(NETWORKS_CONFIG[17], *client1.getServer());
|
||||
|
||||
// The client should be refused to renew the lease because it doesn't belong
|
||||
// to "b-devices" class.
|
||||
client2.setState(Dhcp4Client::RENEWING);
|
||||
testAssigned([this, &client2] {
|
||||
doRequest(client2, "");
|
||||
});
|
||||
|
||||
// If we add option93 with a value matching this class, the lease should
|
||||
// get renewed.
|
||||
OptionPtr option93_bis(new OptionUint16(Option::V4, 93, 0x0002));
|
||||
client2.addExtraOption(option93_bis);
|
||||
|
||||
testAssigned([this, &client2] {
|
||||
doRequest(client2, "192.0.2.100");
|
||||
});
|
||||
}
|
||||
|
||||
// Access to a pool within plain subnet is restricted by client classification.
|
||||
TEST_F(Dhcpv4SharedNetworkTest, poolInSubnetSelectedByClass) {
|
||||
// Create client #1
|
||||
Dhcp4Client client1(Dhcp4Client::SELECTING);
|
||||
client1.setIfaceName("eth1");
|
||||
|
||||
// Configure the server with one plain subnet including two pools.
|
||||
// The access to one of the pools is restricted by client classification.
|
||||
configure(NETWORKS_CONFIG[18], *client1.getServer());
|
||||
|
||||
// Client #1 requests an address in the restricted pool but can't be assigned
|
||||
// this address because the client doesn't belong to a certain class.
|
||||
testAssigned([this, &client1] {
|
||||
doDORA(client1, "192.0.2.100", "192.0.2.63");
|
||||
});
|
||||
|
||||
// Release the lease that the client has got, because we'll need this address
|
||||
// further in the test.
|
||||
testAssigned([this, &client1] {
|
||||
ASSERT_NO_THROW(client1.doRelease());
|
||||
});
|
||||
|
||||
// Add option93 which would cause the client to be classified as "a-devices".
|
||||
OptionPtr option93(new OptionUint16(Option::V4, 93, 0x0001));
|
||||
client1.addExtraOption(option93);
|
||||
|
||||
// This time, the allocation of the address provided as hint should be successful.
|
||||
testAssigned([this, &client1] {
|
||||
doDORA(client1, "192.0.2.63", "192.0.2.63");
|
||||
});
|
||||
|
||||
// Client 2 should be assigned an address from the unrestricted pool.
|
||||
Dhcp4Client client2(client1.getServer(), Dhcp4Client::SELECTING);
|
||||
client2.setIfaceName("eth1");
|
||||
testAssigned([this, &client2] {
|
||||
doDORA(client2, "192.0.2.100");
|
||||
});
|
||||
|
||||
// Now, let's reconfigure the server to also apply restrictions on the
|
||||
// pool to which client2 now belongs.
|
||||
configure(NETWORKS_CONFIG[19], *client1.getServer());
|
||||
|
||||
// The client should be refused to renew the lease because it doesn't belong
|
||||
// to "b-devices" class.
|
||||
client2.setState(Dhcp4Client::RENEWING);
|
||||
testAssigned([this, &client2] {
|
||||
doRequest(client2, "");
|
||||
});
|
||||
|
||||
// If we add option93 with a value matching this class, the lease should
|
||||
// get renewed.
|
||||
OptionPtr option93_bis(new OptionUint16(Option::V4, 93, 0x0002));
|
||||
client2.addExtraOption(option93_bis);
|
||||
|
||||
testAssigned([this, &client2] {
|
||||
doRequest(client2, "192.0.2.100");
|
||||
});
|
||||
}
|
||||
} // end of anonymous namespace
|
||||
|
@ -1581,13 +1581,13 @@ static const flex_int16_t yy_rule_linenum[162] =
|
||||
885, 894, 904, 914, 923, 932, 941, 950, 960, 969,
|
||||
978, 987, 996, 1005, 1014, 1023, 1032, 1041, 1051, 1060,
|
||||
|
||||
1069, 1079, 1090, 1100, 1109, 1118, 1127, 1138, 1148, 1157,
|
||||
1167, 1177, 1186, 1195, 1204, 1213, 1223, 1232, 1242, 1251,
|
||||
1260, 1269, 1278, 1287, 1296, 1305, 1314, 1323, 1332, 1341,
|
||||
1350, 1359, 1368, 1377, 1386, 1395, 1404, 1413, 1422, 1431,
|
||||
1440, 1449, 1458, 1468, 1567, 1572, 1577, 1582, 1583, 1584,
|
||||
1585, 1586, 1587, 1589, 1607, 1620, 1625, 1629, 1631, 1633,
|
||||
1635
|
||||
1069, 1079, 1092, 1102, 1111, 1120, 1129, 1140, 1150, 1159,
|
||||
1169, 1179, 1188, 1197, 1206, 1215, 1225, 1234, 1244, 1253,
|
||||
1262, 1271, 1280, 1289, 1298, 1307, 1316, 1325, 1334, 1343,
|
||||
1352, 1361, 1370, 1379, 1388, 1397, 1406, 1415, 1424, 1433,
|
||||
1442, 1451, 1460, 1470, 1569, 1574, 1579, 1584, 1585, 1586,
|
||||
1587, 1588, 1589, 1591, 1609, 1622, 1627, 1631, 1633, 1635,
|
||||
1637
|
||||
} ;
|
||||
|
||||
/* The intent behind this definition is that it'll catch
|
||||
@ -2718,7 +2718,7 @@ YY_RULE_SETUP
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_PREFERRED_LIFETIME(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("preferred-lifetime", driver.loc_);
|
||||
@ -2732,7 +2732,7 @@ YY_RULE_SETUP
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_VALID_LIFETIME(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("valid-lifetime", driver.loc_);
|
||||
@ -2746,7 +2746,7 @@ YY_RULE_SETUP
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_RENEW_TIMER(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("renew-timer", driver.loc_);
|
||||
@ -2760,7 +2760,7 @@ YY_RULE_SETUP
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_REBIND_TIMER(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("rebind-timer", driver.loc_);
|
||||
@ -2785,7 +2785,7 @@ YY_RULE_SETUP
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_SUBNET6(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("subnet6", driver.loc_);
|
||||
@ -2797,7 +2797,7 @@ YY_RULE_SETUP
|
||||
#line 672 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch (driver.ctx_) {
|
||||
case Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
return Dhcp6Parser::make_SHARED_NETWORKS(driver.loc_);
|
||||
default:
|
||||
return Dhcp6Parser::make_STRING("shared-networks", driver.loc_);
|
||||
@ -2828,7 +2828,7 @@ YY_RULE_SETUP
|
||||
case isc::dhcp::Parser6Context::RESERVATIONS:
|
||||
case isc::dhcp::Parser6Context::CLIENT_CLASSES:
|
||||
case isc::dhcp::Parser6Context::CLIENT_CLASS:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_OPTION_DATA(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("option-data", driver.loc_);
|
||||
@ -2847,7 +2847,7 @@ YY_RULE_SETUP
|
||||
case isc::dhcp::Parser6Context::CLIENT_CLASSES:
|
||||
case isc::dhcp::Parser6Context::CLIENT_CLASS:
|
||||
case isc::dhcp::Parser6Context::LOGGERS:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_NAME(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("name", driver.loc_);
|
||||
@ -3042,7 +3042,7 @@ YY_RULE_SETUP
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_INTERFACE(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("interface", driver.loc_);
|
||||
@ -3055,7 +3055,7 @@ YY_RULE_SETUP
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_INTERFACE_ID(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("interface-id", driver.loc_);
|
||||
@ -3080,7 +3080,7 @@ YY_RULE_SETUP
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_RAPID_COMMIT(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("rapid-commit", driver.loc_);
|
||||
@ -3093,7 +3093,7 @@ YY_RULE_SETUP
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_RESERVATION_MODE(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("reservation-mode", driver.loc_);
|
||||
@ -3324,8 +3324,10 @@ YY_RULE_SETUP
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case isc::dhcp::Parser6Context::POOLS:
|
||||
case isc::dhcp::Parser6Context::PD_POOLS:
|
||||
case isc::dhcp::Parser6Context::CLIENT_CLASSES:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASS(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("client-class", driver.loc_);
|
||||
@ -3334,7 +3336,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 103:
|
||||
YY_RULE_SETUP
|
||||
#line 1090 "dhcp6_lexer.ll"
|
||||
#line 1092 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::CLIENT_CLASSES:
|
||||
@ -3347,7 +3349,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 104:
|
||||
YY_RULE_SETUP
|
||||
#line 1100 "dhcp6_lexer.ll"
|
||||
#line 1102 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
@ -3359,7 +3361,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 105:
|
||||
YY_RULE_SETUP
|
||||
#line 1109 "dhcp6_lexer.ll"
|
||||
#line 1111 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::RESERVATIONS:
|
||||
@ -3371,7 +3373,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 106:
|
||||
YY_RULE_SETUP
|
||||
#line 1118 "dhcp6_lexer.ll"
|
||||
#line 1120 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::RESERVATIONS:
|
||||
@ -3383,7 +3385,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 107:
|
||||
YY_RULE_SETUP
|
||||
#line 1127 "dhcp6_lexer.ll"
|
||||
#line 1129 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::MAC_SOURCES:
|
||||
@ -3397,7 +3399,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 108:
|
||||
YY_RULE_SETUP
|
||||
#line 1138 "dhcp6_lexer.ll"
|
||||
#line 1140 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::HOST_RESERVATION_IDENTIFIERS:
|
||||
@ -3410,7 +3412,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 109:
|
||||
YY_RULE_SETUP
|
||||
#line 1148 "dhcp6_lexer.ll"
|
||||
#line 1150 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::RESERVATIONS:
|
||||
@ -3422,7 +3424,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 110:
|
||||
YY_RULE_SETUP
|
||||
#line 1157 "dhcp6_lexer.ll"
|
||||
#line 1159 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::HOST_RESERVATION_IDENTIFIERS:
|
||||
@ -3435,7 +3437,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 111:
|
||||
YY_RULE_SETUP
|
||||
#line 1167 "dhcp6_lexer.ll"
|
||||
#line 1169 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::OPTION_DEF:
|
||||
@ -3448,7 +3450,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 112:
|
||||
YY_RULE_SETUP
|
||||
#line 1177 "dhcp6_lexer.ll"
|
||||
#line 1179 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::OPTION_DATA:
|
||||
@ -3460,7 +3462,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 113:
|
||||
YY_RULE_SETUP
|
||||
#line 1186 "dhcp6_lexer.ll"
|
||||
#line 1188 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::OPTION_DEF:
|
||||
@ -3472,7 +3474,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 114:
|
||||
YY_RULE_SETUP
|
||||
#line 1195 "dhcp6_lexer.ll"
|
||||
#line 1197 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::OPTION_DEF:
|
||||
@ -3484,7 +3486,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 115:
|
||||
YY_RULE_SETUP
|
||||
#line 1204 "dhcp6_lexer.ll"
|
||||
#line 1206 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::OPTION_DEF:
|
||||
@ -3496,11 +3498,11 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 116:
|
||||
YY_RULE_SETUP
|
||||
#line 1213 "dhcp6_lexer.ll"
|
||||
#line 1215 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_RELAY(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("relay", driver.loc_);
|
||||
@ -3509,11 +3511,11 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 117:
|
||||
YY_RULE_SETUP
|
||||
#line 1223 "dhcp6_lexer.ll"
|
||||
#line 1225 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::RELAY:
|
||||
return isc::dhcp::Dhcp6Parser::make_IP_ADDRESS(driver.loc_);
|
||||
return isc::dhcp::Dhcp6Parser::make_IP_ADDRESS(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("ip-address", driver.loc_);
|
||||
}
|
||||
@ -3521,7 +3523,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 118:
|
||||
YY_RULE_SETUP
|
||||
#line 1232 "dhcp6_lexer.ll"
|
||||
#line 1234 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
@ -3533,7 +3535,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 119:
|
||||
YY_RULE_SETUP
|
||||
#line 1242 "dhcp6_lexer.ll"
|
||||
#line 1244 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::HOOKS_LIBRARIES:
|
||||
@ -3545,7 +3547,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 120:
|
||||
YY_RULE_SETUP
|
||||
#line 1251 "dhcp6_lexer.ll"
|
||||
#line 1253 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::HOOKS_LIBRARIES:
|
||||
@ -3557,7 +3559,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 121:
|
||||
YY_RULE_SETUP
|
||||
#line 1260 "dhcp6_lexer.ll"
|
||||
#line 1262 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
@ -3569,7 +3571,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 122:
|
||||
YY_RULE_SETUP
|
||||
#line 1269 "dhcp6_lexer.ll"
|
||||
#line 1271 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DUID_TYPE:
|
||||
@ -3581,7 +3583,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 123:
|
||||
YY_RULE_SETUP
|
||||
#line 1278 "dhcp6_lexer.ll"
|
||||
#line 1280 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DUID_TYPE:
|
||||
@ -3593,7 +3595,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 124:
|
||||
YY_RULE_SETUP
|
||||
#line 1287 "dhcp6_lexer.ll"
|
||||
#line 1289 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DUID_TYPE:
|
||||
@ -3605,7 +3607,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 125:
|
||||
YY_RULE_SETUP
|
||||
#line 1296 "dhcp6_lexer.ll"
|
||||
#line 1298 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SERVER_ID:
|
||||
@ -3617,7 +3619,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 126:
|
||||
YY_RULE_SETUP
|
||||
#line 1305 "dhcp6_lexer.ll"
|
||||
#line 1307 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SERVER_ID:
|
||||
@ -3629,7 +3631,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 127:
|
||||
YY_RULE_SETUP
|
||||
#line 1314 "dhcp6_lexer.ll"
|
||||
#line 1316 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SERVER_ID:
|
||||
@ -3641,7 +3643,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 128:
|
||||
YY_RULE_SETUP
|
||||
#line 1323 "dhcp6_lexer.ll"
|
||||
#line 1325 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SERVER_ID:
|
||||
@ -3653,7 +3655,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 129:
|
||||
YY_RULE_SETUP
|
||||
#line 1332 "dhcp6_lexer.ll"
|
||||
#line 1334 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
@ -3665,7 +3667,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 130:
|
||||
YY_RULE_SETUP
|
||||
#line 1341 "dhcp6_lexer.ll"
|
||||
#line 1343 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::EXPIRED_LEASES_PROCESSING:
|
||||
@ -3677,7 +3679,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 131:
|
||||
YY_RULE_SETUP
|
||||
#line 1350 "dhcp6_lexer.ll"
|
||||
#line 1352 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::EXPIRED_LEASES_PROCESSING:
|
||||
@ -3689,7 +3691,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 132:
|
||||
YY_RULE_SETUP
|
||||
#line 1359 "dhcp6_lexer.ll"
|
||||
#line 1361 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::EXPIRED_LEASES_PROCESSING:
|
||||
@ -3701,7 +3703,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 133:
|
||||
YY_RULE_SETUP
|
||||
#line 1368 "dhcp6_lexer.ll"
|
||||
#line 1370 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::EXPIRED_LEASES_PROCESSING:
|
||||
@ -3713,7 +3715,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 134:
|
||||
YY_RULE_SETUP
|
||||
#line 1377 "dhcp6_lexer.ll"
|
||||
#line 1379 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::EXPIRED_LEASES_PROCESSING:
|
||||
@ -3725,7 +3727,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 135:
|
||||
YY_RULE_SETUP
|
||||
#line 1386 "dhcp6_lexer.ll"
|
||||
#line 1388 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::EXPIRED_LEASES_PROCESSING:
|
||||
@ -3737,7 +3739,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 136:
|
||||
YY_RULE_SETUP
|
||||
#line 1395 "dhcp6_lexer.ll"
|
||||
#line 1397 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
@ -3749,7 +3751,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 137:
|
||||
YY_RULE_SETUP
|
||||
#line 1404 "dhcp6_lexer.ll"
|
||||
#line 1406 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
@ -3761,7 +3763,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 138:
|
||||
YY_RULE_SETUP
|
||||
#line 1413 "dhcp6_lexer.ll"
|
||||
#line 1415 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::CONTROL_SOCKET:
|
||||
@ -3773,7 +3775,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 139:
|
||||
YY_RULE_SETUP
|
||||
#line 1422 "dhcp6_lexer.ll"
|
||||
#line 1424 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::CONTROL_SOCKET:
|
||||
@ -3785,7 +3787,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 140:
|
||||
YY_RULE_SETUP
|
||||
#line 1431 "dhcp6_lexer.ll"
|
||||
#line 1433 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
@ -3797,7 +3799,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 141:
|
||||
YY_RULE_SETUP
|
||||
#line 1440 "dhcp6_lexer.ll"
|
||||
#line 1442 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::CONFIG:
|
||||
@ -3809,7 +3811,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 142:
|
||||
YY_RULE_SETUP
|
||||
#line 1449 "dhcp6_lexer.ll"
|
||||
#line 1451 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::CONFIG:
|
||||
@ -3821,7 +3823,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 143:
|
||||
YY_RULE_SETUP
|
||||
#line 1458 "dhcp6_lexer.ll"
|
||||
#line 1460 "dhcp6_lexer.ll"
|
||||
{
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::CONFIG:
|
||||
@ -3833,7 +3835,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 144:
|
||||
YY_RULE_SETUP
|
||||
#line 1468 "dhcp6_lexer.ll"
|
||||
#line 1470 "dhcp6_lexer.ll"
|
||||
{
|
||||
/* A string has been matched. It contains the actual string and single quotes.
|
||||
We need to get those quotes out of the way and just use its content, e.g.
|
||||
@ -3936,7 +3938,7 @@ YY_RULE_SETUP
|
||||
case 145:
|
||||
/* rule 145 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 1567 "dhcp6_lexer.ll"
|
||||
#line 1569 "dhcp6_lexer.ll"
|
||||
{
|
||||
/* Bad string with a forbidden control character inside */
|
||||
driver.error(driver.loc_, "Invalid control in " + std::string(yytext));
|
||||
@ -3945,7 +3947,7 @@ YY_RULE_SETUP
|
||||
case 146:
|
||||
/* rule 146 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 1572 "dhcp6_lexer.ll"
|
||||
#line 1574 "dhcp6_lexer.ll"
|
||||
{
|
||||
/* Bad string with a bad escape inside */
|
||||
driver.error(driver.loc_, "Bad escape in " + std::string(yytext));
|
||||
@ -3953,7 +3955,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 147:
|
||||
YY_RULE_SETUP
|
||||
#line 1577 "dhcp6_lexer.ll"
|
||||
#line 1579 "dhcp6_lexer.ll"
|
||||
{
|
||||
/* Bad string with an open escape at the end */
|
||||
driver.error(driver.loc_, "Overflow escape in " + std::string(yytext));
|
||||
@ -3961,37 +3963,37 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 148:
|
||||
YY_RULE_SETUP
|
||||
#line 1582 "dhcp6_lexer.ll"
|
||||
#line 1584 "dhcp6_lexer.ll"
|
||||
{ return isc::dhcp::Dhcp6Parser::make_LSQUARE_BRACKET(driver.loc_); }
|
||||
YY_BREAK
|
||||
case 149:
|
||||
YY_RULE_SETUP
|
||||
#line 1583 "dhcp6_lexer.ll"
|
||||
#line 1585 "dhcp6_lexer.ll"
|
||||
{ return isc::dhcp::Dhcp6Parser::make_RSQUARE_BRACKET(driver.loc_); }
|
||||
YY_BREAK
|
||||
case 150:
|
||||
YY_RULE_SETUP
|
||||
#line 1584 "dhcp6_lexer.ll"
|
||||
#line 1586 "dhcp6_lexer.ll"
|
||||
{ return isc::dhcp::Dhcp6Parser::make_LCURLY_BRACKET(driver.loc_); }
|
||||
YY_BREAK
|
||||
case 151:
|
||||
YY_RULE_SETUP
|
||||
#line 1585 "dhcp6_lexer.ll"
|
||||
#line 1587 "dhcp6_lexer.ll"
|
||||
{ return isc::dhcp::Dhcp6Parser::make_RCURLY_BRACKET(driver.loc_); }
|
||||
YY_BREAK
|
||||
case 152:
|
||||
YY_RULE_SETUP
|
||||
#line 1586 "dhcp6_lexer.ll"
|
||||
#line 1588 "dhcp6_lexer.ll"
|
||||
{ return isc::dhcp::Dhcp6Parser::make_COMMA(driver.loc_); }
|
||||
YY_BREAK
|
||||
case 153:
|
||||
YY_RULE_SETUP
|
||||
#line 1587 "dhcp6_lexer.ll"
|
||||
#line 1589 "dhcp6_lexer.ll"
|
||||
{ return isc::dhcp::Dhcp6Parser::make_COLON(driver.loc_); }
|
||||
YY_BREAK
|
||||
case 154:
|
||||
YY_RULE_SETUP
|
||||
#line 1589 "dhcp6_lexer.ll"
|
||||
#line 1591 "dhcp6_lexer.ll"
|
||||
{
|
||||
/* An integer was found. */
|
||||
std::string tmp(yytext);
|
||||
@ -4012,7 +4014,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 155:
|
||||
YY_RULE_SETUP
|
||||
#line 1607 "dhcp6_lexer.ll"
|
||||
#line 1609 "dhcp6_lexer.ll"
|
||||
{
|
||||
/* A floating point was found. */
|
||||
std::string tmp(yytext);
|
||||
@ -4028,7 +4030,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 156:
|
||||
YY_RULE_SETUP
|
||||
#line 1620 "dhcp6_lexer.ll"
|
||||
#line 1622 "dhcp6_lexer.ll"
|
||||
{
|
||||
string tmp(yytext);
|
||||
return isc::dhcp::Dhcp6Parser::make_BOOLEAN(tmp == "true", driver.loc_);
|
||||
@ -4036,33 +4038,33 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 157:
|
||||
YY_RULE_SETUP
|
||||
#line 1625 "dhcp6_lexer.ll"
|
||||
#line 1627 "dhcp6_lexer.ll"
|
||||
{
|
||||
return isc::dhcp::Dhcp6Parser::make_NULL_TYPE(driver.loc_);
|
||||
}
|
||||
YY_BREAK
|
||||
case 158:
|
||||
YY_RULE_SETUP
|
||||
#line 1629 "dhcp6_lexer.ll"
|
||||
#line 1631 "dhcp6_lexer.ll"
|
||||
driver.error (driver.loc_, "JSON true reserved keyword is lower case only");
|
||||
YY_BREAK
|
||||
case 159:
|
||||
YY_RULE_SETUP
|
||||
#line 1631 "dhcp6_lexer.ll"
|
||||
#line 1633 "dhcp6_lexer.ll"
|
||||
driver.error (driver.loc_, "JSON false reserved keyword is lower case only");
|
||||
YY_BREAK
|
||||
case 160:
|
||||
YY_RULE_SETUP
|
||||
#line 1633 "dhcp6_lexer.ll"
|
||||
#line 1635 "dhcp6_lexer.ll"
|
||||
driver.error (driver.loc_, "JSON null reserved keyword is lower case only");
|
||||
YY_BREAK
|
||||
case 161:
|
||||
YY_RULE_SETUP
|
||||
#line 1635 "dhcp6_lexer.ll"
|
||||
#line 1637 "dhcp6_lexer.ll"
|
||||
driver.error (driver.loc_, "Invalid character: " + std::string(yytext));
|
||||
YY_BREAK
|
||||
case YY_STATE_EOF(INITIAL):
|
||||
#line 1637 "dhcp6_lexer.ll"
|
||||
#line 1639 "dhcp6_lexer.ll"
|
||||
{
|
||||
if (driver.states_.empty()) {
|
||||
return isc::dhcp::Dhcp6Parser::make_END(driver.loc_);
|
||||
@ -4088,10 +4090,10 @@ case YY_STATE_EOF(INITIAL):
|
||||
YY_BREAK
|
||||
case 162:
|
||||
YY_RULE_SETUP
|
||||
#line 1660 "dhcp6_lexer.ll"
|
||||
#line 1662 "dhcp6_lexer.ll"
|
||||
ECHO;
|
||||
YY_BREAK
|
||||
#line 4094 "dhcp6_lexer.cc"
|
||||
#line 4096 "dhcp6_lexer.cc"
|
||||
|
||||
case YY_END_OF_BUFFER:
|
||||
{
|
||||
@ -5196,7 +5198,7 @@ void yyfree (void * ptr )
|
||||
|
||||
/* %ok-for-header */
|
||||
|
||||
#line 1660 "dhcp6_lexer.ll"
|
||||
#line 1662 "dhcp6_lexer.ll"
|
||||
|
||||
|
||||
using namespace isc::dhcp;
|
||||
|
@ -609,7 +609,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_PREFERRED_LIFETIME(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("preferred-lifetime", driver.loc_);
|
||||
@ -620,7 +620,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_VALID_LIFETIME(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("valid-lifetime", driver.loc_);
|
||||
@ -631,7 +631,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_RENEW_TIMER(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("renew-timer", driver.loc_);
|
||||
@ -642,7 +642,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_REBIND_TIMER(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("rebind-timer", driver.loc_);
|
||||
@ -661,7 +661,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
\"subnet6\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_SUBNET6(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("subnet6", driver.loc_);
|
||||
@ -670,7 +670,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
|
||||
\"shared-networks\" {
|
||||
switch (driver.ctx_) {
|
||||
case Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
return Dhcp6Parser::make_SHARED_NETWORKS(driver.loc_);
|
||||
default:
|
||||
return Dhcp6Parser::make_STRING("shared-networks", driver.loc_);
|
||||
@ -695,7 +695,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
case isc::dhcp::Parser6Context::RESERVATIONS:
|
||||
case isc::dhcp::Parser6Context::CLIENT_CLASSES:
|
||||
case isc::dhcp::Parser6Context::CLIENT_CLASS:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_OPTION_DATA(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("option-data", driver.loc_);
|
||||
@ -711,7 +711,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
case isc::dhcp::Parser6Context::CLIENT_CLASSES:
|
||||
case isc::dhcp::Parser6Context::CLIENT_CLASS:
|
||||
case isc::dhcp::Parser6Context::LOGGERS:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_NAME(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("name", driver.loc_);
|
||||
@ -864,7 +864,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
\"interface\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_INTERFACE(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("interface", driver.loc_);
|
||||
@ -874,7 +874,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
\"interface-id\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_INTERFACE_ID(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("interface-id", driver.loc_);
|
||||
@ -893,7 +893,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
\"rapid-commit\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_RAPID_COMMIT(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("rapid-commit", driver.loc_);
|
||||
@ -903,7 +903,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
\"reservation-mode\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_RESERVATION_MODE(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("reservation-mode", driver.loc_);
|
||||
@ -1078,8 +1078,10 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
\"client-class\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case isc::dhcp::Parser6Context::POOLS:
|
||||
case isc::dhcp::Parser6Context::PD_POOLS:
|
||||
case isc::dhcp::Parser6Context::CLIENT_CLASSES:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASS(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("client-class", driver.loc_);
|
||||
@ -1212,7 +1214,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
\"relay\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case Parser6Context::SHARED_NETWORK:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_RELAY(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("relay", driver.loc_);
|
||||
@ -1222,7 +1224,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
\"ip-address\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::RELAY:
|
||||
return isc::dhcp::Dhcp6Parser::make_IP_ADDRESS(driver.loc_);
|
||||
return isc::dhcp::Dhcp6Parser::make_IP_ADDRESS(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("ip-address", driver.loc_);
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ The first argument specifies the client and transaction identification
|
||||
information. The second argument includes all classes to which the
|
||||
packet has been assigned.
|
||||
|
||||
% DHCP6_CLASS_UNCONFIGURED %1: client packet belongs to an unconfigured class: %1
|
||||
% DHCP6_CLASS_UNCONFIGURED %1: client packet belongs to an unconfigured class: %2
|
||||
This debug message informs that incoming packet belongs to a class
|
||||
which cannot be found in the configuration. Either a hook written
|
||||
before the classification was added to Kea is used, or class naming is
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1441,7 +1441,7 @@ namespace isc { namespace dhcp {
|
||||
{
|
||||
yyeof_ = 0,
|
||||
yylast_ = 931, ///< Last index in yytable_.
|
||||
yynnts_ = 351, ///< Number of nonterminal symbols.
|
||||
yynnts_ = 352, ///< Number of nonterminal symbols.
|
||||
yyfinal_ = 30, ///< Termination state number.
|
||||
yyterror_ = 1,
|
||||
yyerrcode_ = 256,
|
||||
@ -1542,9 +1542,9 @@ namespace isc { namespace dhcp {
|
||||
case 177: // map_value
|
||||
case 221: // db_type
|
||||
case 297: // hr_mode
|
||||
case 430: // duid_type
|
||||
case 463: // ncr_protocol_value
|
||||
case 471: // replace_client_name_value
|
||||
case 431: // duid_type
|
||||
case 464: // ncr_protocol_value
|
||||
case 472: // replace_client_name_value
|
||||
value.copy< ElementPtr > (other.value);
|
||||
break;
|
||||
|
||||
@ -1585,9 +1585,9 @@ namespace isc { namespace dhcp {
|
||||
case 177: // map_value
|
||||
case 221: // db_type
|
||||
case 297: // hr_mode
|
||||
case 430: // duid_type
|
||||
case 463: // ncr_protocol_value
|
||||
case 471: // replace_client_name_value
|
||||
case 431: // duid_type
|
||||
case 464: // ncr_protocol_value
|
||||
case 472: // replace_client_name_value
|
||||
value.copy< ElementPtr > (v);
|
||||
break;
|
||||
|
||||
@ -1687,9 +1687,9 @@ namespace isc { namespace dhcp {
|
||||
case 177: // map_value
|
||||
case 221: // db_type
|
||||
case 297: // hr_mode
|
||||
case 430: // duid_type
|
||||
case 463: // ncr_protocol_value
|
||||
case 471: // replace_client_name_value
|
||||
case 431: // duid_type
|
||||
case 464: // ncr_protocol_value
|
||||
case 472: // replace_client_name_value
|
||||
value.template destroy< ElementPtr > ();
|
||||
break;
|
||||
|
||||
@ -1736,9 +1736,9 @@ namespace isc { namespace dhcp {
|
||||
case 177: // map_value
|
||||
case 221: // db_type
|
||||
case 297: // hr_mode
|
||||
case 430: // duid_type
|
||||
case 463: // ncr_protocol_value
|
||||
case 471: // replace_client_name_value
|
||||
case 431: // duid_type
|
||||
case 464: // ncr_protocol_value
|
||||
case 472: // replace_client_name_value
|
||||
value.move< ElementPtr > (s.value);
|
||||
break;
|
||||
|
||||
|
@ -1307,6 +1307,7 @@ pool_params: pool_param
|
||||
|
||||
pool_param: pool_entry
|
||||
| option_data_list
|
||||
| client_class
|
||||
| user_context
|
||||
| comment
|
||||
| unknown_map_entry
|
||||
@ -1427,6 +1428,7 @@ pd_pool_param: pd_prefix
|
||||
| pd_prefix_len
|
||||
| pd_delegated_len
|
||||
| option_data_list
|
||||
| client_class
|
||||
| excluded_prefix
|
||||
| excluded_prefix_len
|
||||
| user_context
|
||||
@ -1622,11 +1624,11 @@ client_classes: CLIENT_CLASSES {
|
||||
ctx.leave();
|
||||
};
|
||||
|
||||
client_classes_list: client_class
|
||||
| client_classes_list COMMA client_class
|
||||
client_classes_list: client_class_entry
|
||||
| client_classes_list COMMA client_class_entry
|
||||
;
|
||||
|
||||
client_class: LCURLY_BRACKET {
|
||||
client_class_entry: LCURLY_BRACKET {
|
||||
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
|
||||
ctx.stack_.back()->add(m);
|
||||
ctx.stack_.push_back(m);
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated 201712311009
|
||||
// Generated 201801182315
|
||||
// A Bison parser, made by GNU Bison 3.0.4.
|
||||
|
||||
// Locations for Bison parsers in C++
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated 201712311009
|
||||
// Generated 201801182315
|
||||
// A Bison parser, made by GNU Bison 3.0.4.
|
||||
|
||||
// Positions for Bison parsers in C++
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated 201712311009
|
||||
// Generated 201801182315
|
||||
// A Bison parser, made by GNU Bison 3.0.4.
|
||||
|
||||
// Stack handling for Bison parsers in C++
|
||||
|
@ -176,6 +176,17 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Create a solicit
|
||||
Pkt6Ptr createSolicit(std::string remote_addr = "fe80::abcd") {
|
||||
OptionPtr clientid = generateClientId();
|
||||
Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
query->setRemoteAddr(IOAddress(remote_addr));
|
||||
query->addOption(clientid);
|
||||
query->setIface("eth1");
|
||||
query->addOption(generateIA(D6O_IA_NA, 123, 1500, 3000));
|
||||
return (query);
|
||||
}
|
||||
|
||||
/// @brief Interface Manager's fake configuration control.
|
||||
IfaceMgrTestConfig iface_mgr_test_config_;
|
||||
};
|
||||
@ -244,22 +255,9 @@ TEST_F(ClassifyTest, matchClassification) {
|
||||
ASSERT_NO_THROW(configure(config));
|
||||
|
||||
// Create packets with enough to select the subnet
|
||||
OptionPtr clientid = generateClientId();
|
||||
Pkt6Ptr query1(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
query1->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
query1->addOption(clientid);
|
||||
query1->setIface("eth1");
|
||||
query1->addOption(generateIA(D6O_IA_NA, 123, 1500, 3000));
|
||||
Pkt6Ptr query2(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
query2->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
query2->addOption(clientid);
|
||||
query2->setIface("eth1");
|
||||
query2->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
|
||||
Pkt6Ptr query3(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
query3->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
query3->addOption(clientid);
|
||||
query3->setIface("eth1");
|
||||
query3->addOption(generateIA(D6O_IA_NA, 345, 1500, 3000));
|
||||
Pkt6Ptr query1 = createSolicit();
|
||||
Pkt6Ptr query2 = createSolicit();
|
||||
Pkt6Ptr query3 = createSolicit();
|
||||
|
||||
// Create and add an ORO option to the first 2 queries
|
||||
OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6, D6O_ORO));
|
||||
@ -341,12 +339,7 @@ TEST_F(ClassifyTest, subnetClassPriority) {
|
||||
|
||||
// Create a packet with enough to select the subnet and go through
|
||||
// the SOLICIT processing
|
||||
Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
query->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
OptionPtr clientid = generateClientId();
|
||||
query->addOption(clientid);
|
||||
query->setIface("eth1");
|
||||
query->addOption(generateIA(D6O_IA_NA, 123, 1500, 3000));
|
||||
Pkt6Ptr query = createSolicit();
|
||||
|
||||
// Create and add an ORO option to the query
|
||||
OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6, D6O_ORO));
|
||||
@ -413,12 +406,7 @@ TEST_F(ClassifyTest, subnetGlobalPriority) {
|
||||
|
||||
// Create a packet with enough to select the subnet and go through
|
||||
// the SOLICIT processing
|
||||
Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
query->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
OptionPtr clientid = generateClientId();
|
||||
query->addOption(clientid);
|
||||
query->setIface("eth1");
|
||||
query->addOption(generateIA(D6O_IA_NA, 123, 1500, 3000));
|
||||
Pkt6Ptr query = createSolicit();
|
||||
|
||||
// Create and add an ORO option to the query
|
||||
OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6, D6O_ORO));
|
||||
@ -482,12 +470,7 @@ TEST_F(ClassifyTest, classGlobalPriority) {
|
||||
|
||||
// Create a packet with enough to select the subnet and go through
|
||||
// the SOLICIT processing
|
||||
Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
query->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
OptionPtr clientid = generateClientId();
|
||||
query->addOption(clientid);
|
||||
query->setIface("eth1");
|
||||
query->addOption(generateIA(D6O_IA_NA, 123, 1500, 3000));
|
||||
Pkt6Ptr query = createSolicit();
|
||||
|
||||
// Create and add an ORO option to the query
|
||||
OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6, D6O_ORO));
|
||||
@ -558,12 +541,7 @@ TEST_F(ClassifyTest, classGlobalPersistency) {
|
||||
|
||||
// Create a packet with enough to select the subnet and go through
|
||||
// the SOLICIT processing
|
||||
Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
query->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
OptionPtr clientid = generateClientId();
|
||||
query->addOption(clientid);
|
||||
query->setIface("eth1");
|
||||
query->addOption(generateIA(D6O_IA_NA, 123, 1500, 3000));
|
||||
Pkt6Ptr query = createSolicit();
|
||||
|
||||
// Do not add an ORO.
|
||||
OptionPtr oro = query->getOption(D6O_ORO);
|
||||
@ -620,11 +598,7 @@ TEST_F(ClassifyTest, clientClassifySubnet) {
|
||||
|
||||
ASSERT_NO_THROW(configure(config));
|
||||
|
||||
Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
sol->setRemoteAddr(IOAddress("2001:db8:1::3"));
|
||||
sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
|
||||
OptionPtr clientid = generateClientId();
|
||||
sol->addOption(clientid);
|
||||
Pkt6Ptr sol = createSolicit("2001:db8:1::3");
|
||||
|
||||
// This discover does not belong to foo class, so it will not
|
||||
// be serviced
|
||||
@ -647,17 +621,92 @@ TEST_F(ClassifyTest, clientClassifySubnet) {
|
||||
EXPECT_FALSE(drop);
|
||||
}
|
||||
|
||||
// Checks if the client-class field is indeed used for pool selection.
|
||||
TEST_F(ClassifyTest, clientClassifyPool) {
|
||||
IfaceMgrTestConfig test_config(true);
|
||||
|
||||
NakedDhcpv6Srv srv(0);
|
||||
|
||||
// This test configures 2 pools.
|
||||
// The second pool does not play any role here. The client's
|
||||
// IP address belongs to the first pool, so only that first
|
||||
// pool is being tested.
|
||||
std::string config = "{ \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
"},"
|
||||
"\"preferred-lifetime\": 3000,"
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"client-classes\": [ "
|
||||
" { "
|
||||
" \"name\": \"foo\" "
|
||||
" }, "
|
||||
" { "
|
||||
" \"name\": \"bar\" "
|
||||
" } "
|
||||
"], "
|
||||
"\"subnet6\": [ "
|
||||
" { \"pools\": [ "
|
||||
" { "
|
||||
" \"pool\": \"2001:db8:1::/64\", "
|
||||
" \"client-class\": \"foo\" "
|
||||
" }, "
|
||||
" { "
|
||||
" \"pool\": \"2001:db8:2::/64\", "
|
||||
" \"client-class\": \"xyzzy\" "
|
||||
" } "
|
||||
" ], "
|
||||
" \"subnet\": \"2001:db8:2::/40\" "
|
||||
" } "
|
||||
"], "
|
||||
"\"valid-lifetime\": 4000 }";
|
||||
|
||||
ASSERT_NO_THROW(configure(config));
|
||||
|
||||
Pkt6Ptr query1 = createSolicit("2001:db8:1::3");
|
||||
Pkt6Ptr query2 = createSolicit("2001:db8:1::3");
|
||||
Pkt6Ptr query3 = createSolicit("2001:db8:1::3");
|
||||
|
||||
// This discover does not belong to foo class, so it will not
|
||||
// be serviced
|
||||
srv.classifyPacket(query1);
|
||||
Pkt6Ptr response1 = srv.processSolicit(query1);
|
||||
ASSERT_TRUE(response1);
|
||||
OptionPtr ia_na1 = response1->getOption(D6O_IA_NA);
|
||||
ASSERT_TRUE(ia_na1);
|
||||
EXPECT_TRUE(ia_na1->getOption(D6O_STATUS_CODE));
|
||||
EXPECT_FALSE(ia_na1->getOption(D6O_IAADDR));
|
||||
|
||||
// Let's add the packet to bar class and try again.
|
||||
query2->addClass("bar");
|
||||
// Still not supported, because it belongs to wrong class.
|
||||
srv.classifyPacket(query2);
|
||||
Pkt6Ptr response2 = srv.processSolicit(query2);
|
||||
ASSERT_TRUE(response2);
|
||||
OptionPtr ia_na2 = response2->getOption(D6O_IA_NA);
|
||||
ASSERT_TRUE(ia_na2);
|
||||
EXPECT_TRUE(ia_na2->getOption(D6O_STATUS_CODE));
|
||||
EXPECT_FALSE(ia_na2->getOption(D6O_IAADDR));
|
||||
|
||||
// Let's add it to matching class.
|
||||
query3->addClass("foo");
|
||||
// This time it should work
|
||||
srv.classifyPacket(query3);
|
||||
Pkt6Ptr response3 = srv.processSolicit(query3);
|
||||
ASSERT_TRUE(response3);
|
||||
OptionPtr ia_na3 = response3->getOption(D6O_IA_NA);
|
||||
ASSERT_TRUE(ia_na3);
|
||||
EXPECT_FALSE(ia_na3->getOption(D6O_STATUS_CODE));
|
||||
EXPECT_TRUE(ia_na3->getOption(D6O_IAADDR));
|
||||
}
|
||||
|
||||
// Tests whether a packet with custom vendor-class (not erouter or docsis)
|
||||
// is classified properly.
|
||||
TEST_F(ClassifyTest, vendorClientClassification2) {
|
||||
NakedDhcpv6Srv srv(0);
|
||||
|
||||
// Let's create a SOLICIT.
|
||||
Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
sol->setRemoteAddr(IOAddress("2001:db8:1::3"));
|
||||
sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
|
||||
OptionPtr clientid = generateClientId();
|
||||
sol->addOption(clientid);
|
||||
Pkt6Ptr sol = createSolicit("2001:db8:1::3");
|
||||
|
||||
// Now let's add a vendor-class with id=1234 and content "foo"
|
||||
OptionVendorClassPtr vendor_class(new OptionVendorClass(Option::V6, 1234));
|
||||
@ -720,11 +769,7 @@ TEST_F(ClassifyTest, relayOverrideAndClientClass) {
|
||||
ASSERT_TRUE(subnet1);
|
||||
ASSERT_TRUE(subnet2);
|
||||
|
||||
Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
sol->setRemoteAddr(IOAddress("2001:db8:1::3"));
|
||||
sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
|
||||
OptionPtr clientid = generateClientId();
|
||||
sol->addOption(clientid);
|
||||
Pkt6Ptr sol = createSolicit("2001:db8:1::3");
|
||||
|
||||
// Now pretend the packet came via one relay.
|
||||
Pkt6::RelayInfo relay;
|
||||
|
@ -4211,6 +4211,194 @@ TEST_F(Dhcp6ParserTest, classifySubnets) {
|
||||
EXPECT_TRUE (subnets->at(3)->clientSupported(classes));
|
||||
}
|
||||
|
||||
// Goal of this test is to verify that multiple pools can be configured
|
||||
// with defined client classes.
|
||||
TEST_F(Dhcp6ParserTest, classifyPools) {
|
||||
ConstElementPtr x;
|
||||
string config = "{ " + genIfaceConfig() + ","
|
||||
"\"preferred-lifetime\": 3000,"
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet6\": [ { "
|
||||
" \"pools\": [ { "
|
||||
" \"pool\": \"2001:db8:1::/80\", "
|
||||
" \"client-class\": \"alpha\" "
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"2001:db8:2::/80\", "
|
||||
" \"client-class\": \"beta\" "
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"2001:db8:3::/80\", "
|
||||
" \"client-class\": \"gamma\" "
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"2001:db8:4::/80\" "
|
||||
" } ],"
|
||||
" \"subnet\": \"2001:db8:0::/40\" "
|
||||
" } ],"
|
||||
"\"valid-lifetime\": 4000 }";
|
||||
|
||||
ConstElementPtr json;
|
||||
ASSERT_NO_THROW(json = parseDHCP6(config, true));
|
||||
extractConfig(config);
|
||||
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_TRUE(subnets);
|
||||
ASSERT_EQ(1, subnets->size());
|
||||
const PoolCollection& pools = subnets->at(0)->getPools(Lease::TYPE_NA);
|
||||
ASSERT_EQ(4, pools.size()); // We expect 4 pools
|
||||
|
||||
// Let's check if client belonging to alpha class is supported in pool[0]
|
||||
// and not supported in any other pool (except pool[3], which allows
|
||||
// everyone).
|
||||
ClientClasses classes;
|
||||
classes.insert("alpha");
|
||||
EXPECT_TRUE (pools.at(0)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(3)->clientSupported(classes));
|
||||
|
||||
// Let's check if client belonging to beta class is supported in pool[1]
|
||||
// and not supported in any other pool (except pool[3], which allows
|
||||
// everyone).
|
||||
classes.clear();
|
||||
classes.insert("beta");
|
||||
EXPECT_FALSE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(1)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(3)->clientSupported(classes));
|
||||
|
||||
// Let's check if client belonging to gamma class is supported in pool[2]
|
||||
// and not supported in any other pool (except pool[3], which allows
|
||||
// everyone).
|
||||
classes.clear();
|
||||
classes.insert("gamma");
|
||||
EXPECT_FALSE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(3)->clientSupported(classes));
|
||||
|
||||
// Let's check if client belonging to some other class (not mentioned in
|
||||
// the config) is supported only in pool[3], which allows everyone.
|
||||
classes.clear();
|
||||
classes.insert("delta");
|
||||
EXPECT_FALSE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(3)->clientSupported(classes));
|
||||
|
||||
// Finally, let's check class-less client. He should be allowed only in
|
||||
// the last pool, which does not have any class restrictions.
|
||||
classes.clear();
|
||||
EXPECT_FALSE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(3)->clientSupported(classes));
|
||||
}
|
||||
|
||||
// Goal of this test is to verify that multiple pdpools can be configured
|
||||
// with defined client classes.
|
||||
TEST_F(Dhcp6ParserTest, classifyPdPools) {
|
||||
ConstElementPtr x;
|
||||
string config = "{ " + genIfaceConfig() + ","
|
||||
"\"preferred-lifetime\": 3000,"
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet6\": [ { "
|
||||
" \"pd-pools\": [ { "
|
||||
" \"prefix-len\": 48, "
|
||||
" \"delegated-len\": 64, "
|
||||
" \"prefix\": \"2001:db8:1::\", "
|
||||
" \"client-class\": \"alpha\" "
|
||||
" },"
|
||||
" {"
|
||||
" \"prefix-len\": 48, "
|
||||
" \"delegated-len\": 64, "
|
||||
" \"prefix\": \"2001:db8:2::\", "
|
||||
" \"client-class\": \"beta\" "
|
||||
" },"
|
||||
" {"
|
||||
" \"prefix-len\": 48, "
|
||||
" \"delegated-len\": 64, "
|
||||
" \"prefix\": \"2001:db8:3::\", "
|
||||
" \"client-class\": \"gamma\" "
|
||||
" },"
|
||||
" {"
|
||||
" \"prefix-len\": 48, "
|
||||
" \"delegated-len\": 64, "
|
||||
" \"prefix\": \"2001:db8:4::\" "
|
||||
" } ],"
|
||||
" \"subnet\": \"2001:db8::/64\" "
|
||||
" } ],"
|
||||
"\"valid-lifetime\": 4000 }";
|
||||
|
||||
ConstElementPtr json;
|
||||
ASSERT_NO_THROW(json = parseDHCP6(config, true));
|
||||
extractConfig(config);
|
||||
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_TRUE(subnets);
|
||||
ASSERT_EQ(1, subnets->size());
|
||||
const PoolCollection& pools = subnets->at(0)->getPools(Lease::TYPE_PD);
|
||||
ASSERT_EQ(4, pools.size()); // We expect 4 pools
|
||||
|
||||
// Let's check if client belonging to alpha class is supported in pool[0]
|
||||
// and not supported in any other pool (except pool[3], which allows
|
||||
// everyone).
|
||||
ClientClasses classes;
|
||||
classes.insert("alpha");
|
||||
EXPECT_TRUE (pools.at(0)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(3)->clientSupported(classes));
|
||||
|
||||
// Let's check if client belonging to beta class is supported in pool[1]
|
||||
// and not supported in any other pool (except pool[3], which allows
|
||||
// everyone).
|
||||
classes.clear();
|
||||
classes.insert("beta");
|
||||
EXPECT_FALSE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(1)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(3)->clientSupported(classes));
|
||||
|
||||
// Let's check if client belonging to gamma class is supported in pool[2]
|
||||
// and not supported in any other pool (except pool[3], which allows
|
||||
// everyone).
|
||||
classes.clear();
|
||||
classes.insert("gamma");
|
||||
EXPECT_FALSE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(3)->clientSupported(classes));
|
||||
|
||||
// Let's check if client belonging to some other class (not mentioned in
|
||||
// the config) is supported only in pool[3], which allows everyone.
|
||||
classes.clear();
|
||||
classes.insert("delta");
|
||||
EXPECT_FALSE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(3)->clientSupported(classes));
|
||||
|
||||
// Finally, let's check class-less client. He should be allowed only in
|
||||
// the last pool, which does not have any class restrictions.
|
||||
classes.clear();
|
||||
EXPECT_FALSE(pools.at(0)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(1)->clientSupported(classes));
|
||||
EXPECT_FALSE(pools.at(2)->clientSupported(classes));
|
||||
EXPECT_TRUE (pools.at(3)->clientSupported(classes));
|
||||
}
|
||||
|
||||
// This test checks the ability of the server to parse a configuration
|
||||
// containing a full, valid dhcp-ddns (D2ClientConfig) entry.
|
||||
TEST_F(Dhcp6ParserTest, d2ClientConfig) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -957,7 +957,151 @@ const char* NETWORKS_CONFIG[] = {
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
"}",
|
||||
|
||||
// Configuration #19.
|
||||
// - one shared network with one subnet and two pools (the first has
|
||||
// class restrictions)
|
||||
"{"
|
||||
" \"client-classes\": ["
|
||||
" {"
|
||||
" \"name\": \"a-devices\","
|
||||
" \"test\": \"option[1234].hex == 0x0001\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"b-devices\","
|
||||
" \"test\": \"option[1234].hex == 0x0002\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"shared-networks\": ["
|
||||
" {"
|
||||
" \"name\": \"frog\","
|
||||
" \"interface\": \"eth1\","
|
||||
" \"subnet6\": ["
|
||||
" {"
|
||||
" \"subnet\": \"2001:db8:1::/64\","
|
||||
" \"id\": 10,"
|
||||
" \"pools\": ["
|
||||
" {"
|
||||
" \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\","
|
||||
" \"client-class\": \"a-devices\""
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"2001:db8:1::50 - 2001:db8:1::50\""
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
"}",
|
||||
|
||||
// Configuration #20.
|
||||
// - one shared network with one subnet and two pools (each with class
|
||||
// restriction)
|
||||
"{"
|
||||
" \"client-classes\": ["
|
||||
" {"
|
||||
" \"name\": \"a-devices\","
|
||||
" \"test\": \"option[1234].hex == 0x0001\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"b-devices\","
|
||||
" \"test\": \"option[1234].hex == 0x0002\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"shared-networks\": ["
|
||||
" {"
|
||||
" \"name\": \"frog\","
|
||||
" \"interface\": \"eth1\","
|
||||
" \"subnet6\": ["
|
||||
" {"
|
||||
" \"subnet\": \"2001:db8:1::/64\","
|
||||
" \"id\": 10,"
|
||||
" \"pools\": ["
|
||||
" {"
|
||||
" \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\","
|
||||
" \"client-class\": \"a-devices\""
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"2001:db8:1::50 - 2001:db8:1::50\","
|
||||
" \"client-class\": \"b-devices\""
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
"}",
|
||||
|
||||
// Configuration #21.
|
||||
// - one plain subnet with two pools (the first has class restrictions)
|
||||
"{"
|
||||
" \"client-classes\": ["
|
||||
" {"
|
||||
" \"name\": \"a-devices\","
|
||||
" \"test\": \"option[1234].hex == 0x0001\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"b-devices\","
|
||||
" \"test\": \"option[1234].hex == 0x0002\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"subnet6\": ["
|
||||
" {"
|
||||
" \"subnet\": \"2001:db8:1::/64\","
|
||||
" \"id\": 10,"
|
||||
" \"interface\": \"eth1\","
|
||||
" \"pools\": ["
|
||||
" {"
|
||||
" \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\","
|
||||
" \"client-class\": \"a-devices\""
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"2001:db8:1::50 - 2001:db8:1::50\""
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
"}",
|
||||
|
||||
// Configuration #22.
|
||||
// - one plain subnet with two pools (each with class restriction)
|
||||
"{"
|
||||
" \"client-classes\": ["
|
||||
" {"
|
||||
" \"name\": \"a-devices\","
|
||||
" \"test\": \"option[1234].hex == 0x0001\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"b-devices\","
|
||||
" \"test\": \"option[1234].hex == 0x0002\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"shared-networks\": ["
|
||||
" {"
|
||||
" \"name\": \"frog\","
|
||||
" \"interface\": \"eth1\","
|
||||
" \"subnet6\": ["
|
||||
" {"
|
||||
" \"subnet\": \"2001:db8:1::/64\","
|
||||
" \"id\": 10,"
|
||||
" \"pools\": ["
|
||||
" {"
|
||||
" \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\","
|
||||
" \"client-class\": \"a-devices\""
|
||||
" },"
|
||||
" {"
|
||||
" \"pool\": \"2001:db8:1::50 - 2001:db8:1::50\","
|
||||
" \"client-class\": \"b-devices\""
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
"}"
|
||||
|
||||
};
|
||||
|
||||
/// @Brief Test fixture class for DHCPv6 server using shared networks.
|
||||
@ -2191,4 +2335,131 @@ TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkRapidCommit3) {
|
||||
testRapidCommit(NETWORKS_CONFIG[1], false, "", "");
|
||||
}
|
||||
|
||||
// Pool is selected based on the client class specified.
|
||||
TEST_F(Dhcpv6SharedNetworkTest, poolInSharedNetworkSelectedByClass) {
|
||||
// Create client #1.
|
||||
Dhcp6Client client1;
|
||||
client1.setInterface("eth1");
|
||||
|
||||
// Configure the server with one shared network including one subnet and
|
||||
// two pools. The access to one of the pools is restricted by
|
||||
// by client classification.
|
||||
ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[19], *client1.getServer()));
|
||||
|
||||
// Client #1 requests an address in the restricted pool but can't be assigned
|
||||
// this address because the client doesn't belong to a certain class.
|
||||
ASSERT_NO_THROW(client1.requestAddress(0xabca, IOAddress("2001:db8:1::20")));
|
||||
testAssigned([this, &client1] {
|
||||
ASSERT_NO_THROW(client1.doSARR());
|
||||
});
|
||||
ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::50")));
|
||||
|
||||
// Release the lease that the client has got, because we'll need this address
|
||||
// further in the test.
|
||||
testAssigned([this, &client1] {
|
||||
ASSERT_NO_THROW(client1.doRelease());
|
||||
});
|
||||
|
||||
// Add option 1234 which would cause the client to be classified as "a-devices".
|
||||
OptionPtr option1234(new OptionUint16(Option::V6, 1234, 0x0001));
|
||||
client1.addExtraOption(option1234);
|
||||
|
||||
// This time, the allocation of the address provided as hint should be successful.
|
||||
testAssigned([this, &client1] {
|
||||
ASSERT_NO_THROW(client1.doSARR());
|
||||
});
|
||||
ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")));
|
||||
|
||||
// Client 2 should be assigned an address from the unrestricted pool.
|
||||
Dhcp6Client client2(client1.getServer());
|
||||
client2.setInterface("eth1");
|
||||
ASSERT_NO_THROW(client2.requestAddress(0xabca0));
|
||||
testAssigned([this, &client2] {
|
||||
ASSERT_NO_THROW(client2.doSARR());
|
||||
});
|
||||
ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:1::50")));
|
||||
|
||||
// Now, let's reconfigure the server to also apply restrictions on the
|
||||
// pool to which client2 now belongs.
|
||||
ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[20], *client1.getServer()));
|
||||
|
||||
testAssigned([this, &client2] {
|
||||
ASSERT_NO_THROW(client2.doRenew());
|
||||
});
|
||||
EXPECT_EQ(0, client2.getLeasesWithNonZeroLifetime().size());
|
||||
|
||||
// If we add option 1234 with a value matching this class, the lease should
|
||||
// get renewed.
|
||||
OptionPtr option1234_bis(new OptionUint16(Option::V6, 1234, 0x0002));
|
||||
client2.addExtraOption(option1234_bis);
|
||||
testAssigned([this, &client2] {
|
||||
ASSERT_NO_THROW(client2.doRenew());
|
||||
});
|
||||
EXPECT_EQ(1, client2.getLeaseNum());
|
||||
EXPECT_EQ(1, client2.getLeasesWithNonZeroLifetime().size());
|
||||
}
|
||||
|
||||
// Pool is selected based on the client class specified using a plain subnet.
|
||||
TEST_F(Dhcpv6SharedNetworkTest, poolInSubnetSelectedByClass) {
|
||||
// Create client #1.
|
||||
Dhcp6Client client1;
|
||||
client1.setInterface("eth1");
|
||||
|
||||
// Configure the server with one plain subnet including two pools.
|
||||
// The access to one of the pools is restricted by client classification.
|
||||
ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[21], *client1.getServer()));
|
||||
|
||||
// Client #1 requests an address in the restricted pool but can't be assigned
|
||||
// this address because the client doesn't belong to a certain class.
|
||||
ASSERT_NO_THROW(client1.requestAddress(0xabca, IOAddress("2001:db8:1::20")));
|
||||
testAssigned([this, &client1] {
|
||||
ASSERT_NO_THROW(client1.doSARR());
|
||||
});
|
||||
ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::50")));
|
||||
|
||||
// Release the lease that the client has got, because we'll need this address
|
||||
// further in the test.
|
||||
testAssigned([this, &client1] {
|
||||
ASSERT_NO_THROW(client1.doRelease());
|
||||
});
|
||||
|
||||
// Add option 1234 which would cause the client to be classified as "a-devices".
|
||||
OptionPtr option1234(new OptionUint16(Option::V6, 1234, 0x0001));
|
||||
client1.addExtraOption(option1234);
|
||||
|
||||
// This time, the allocation of the address provided as hint should be successful.
|
||||
testAssigned([this, &client1] {
|
||||
ASSERT_NO_THROW(client1.doSARR());
|
||||
});
|
||||
ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")));
|
||||
|
||||
// Client 2 should be assigned an address from the unrestricted pool.
|
||||
Dhcp6Client client2(client1.getServer());
|
||||
client2.setInterface("eth1");
|
||||
ASSERT_NO_THROW(client2.requestAddress(0xabca0));
|
||||
testAssigned([this, &client2] {
|
||||
ASSERT_NO_THROW(client2.doSARR());
|
||||
});
|
||||
ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:1::50")));
|
||||
|
||||
// Now, let's reconfigure the server to also apply restrictions on the
|
||||
// pool to which client2 now belongs.
|
||||
ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[22], *client1.getServer()));
|
||||
|
||||
testAssigned([this, &client2] {
|
||||
ASSERT_NO_THROW(client2.doRenew());
|
||||
});
|
||||
EXPECT_EQ(0, client2.getLeasesWithNonZeroLifetime().size());
|
||||
|
||||
// If we add option 1234 with a value matching this class, the lease should
|
||||
// get renewed.
|
||||
OptionPtr option1234_bis(new OptionUint16(Option::V6, 1234, 0x0002));
|
||||
client2.addExtraOption(option1234_bis);
|
||||
testAssigned([this, &client2] {
|
||||
ASSERT_NO_THROW(client2.doRenew());
|
||||
});
|
||||
EXPECT_EQ(1, client2.getLeaseNum());
|
||||
EXPECT_EQ(1, client2.getLeasesWithNonZeroLifetime().size());
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
@ -144,19 +144,33 @@ AllocEngine::IterativeAllocator::increasePrefix(const isc::asiolink::IOAddress&
|
||||
return (IOAddress::fromBytes(AF_INET6, packed));
|
||||
}
|
||||
|
||||
isc::asiolink::IOAddress
|
||||
AllocEngine::IterativeAllocator::increaseAddress(const isc::asiolink::IOAddress& address,
|
||||
bool prefix,
|
||||
const uint8_t prefix_len) {
|
||||
if (!prefix) {
|
||||
return (IOAddress::increase(address));
|
||||
} else {
|
||||
return (increasePrefix(address, prefix_len));
|
||||
}
|
||||
}
|
||||
|
||||
isc::asiolink::IOAddress
|
||||
AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
|
||||
const ClientClasses& client_classes,
|
||||
const DuidPtr&,
|
||||
const IOAddress&) {
|
||||
|
||||
// Is this prefix allocation?
|
||||
bool prefix = pool_type_ == Lease::TYPE_PD;
|
||||
uint8_t prefix_len = 0;
|
||||
|
||||
// Let's get the last allocated address. It is usually set correctly,
|
||||
// but there are times when it won't be (like after removing a pool or
|
||||
// perhaps restarting the server).
|
||||
IOAddress last = subnet->getLastAllocated(pool_type_);
|
||||
bool valid = true;
|
||||
bool retrying = false;
|
||||
|
||||
const PoolCollection& pools = subnet->getPools(pool_type_);
|
||||
|
||||
@ -166,58 +180,108 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
|
||||
|
||||
// first we need to find a pool the last address belongs to.
|
||||
PoolCollection::const_iterator it;
|
||||
PoolCollection::const_iterator first = pools.end();
|
||||
PoolPtr first_pool;
|
||||
for (it = pools.begin(); it != pools.end(); ++it) {
|
||||
if (!(*it)->clientSupported(client_classes)) {
|
||||
continue;
|
||||
}
|
||||
if (first == pools.end()) {
|
||||
first = it;
|
||||
}
|
||||
if ((*it)->inRange(last)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Caller checked this cannot happen
|
||||
if (first == pools.end()) {
|
||||
isc_throw(AllocFailed, "No allowed pools defined in selected subnet");
|
||||
}
|
||||
|
||||
// last one was bogus for one of several reasons:
|
||||
// - we just booted up and that's the first address we're allocating
|
||||
// - a subnet was removed or other reconfiguration just completed
|
||||
// - perhaps allocation algorithm was changed
|
||||
// - last pool does not allow this client
|
||||
if (it == pools.end()) {
|
||||
// ok to access first element directly. We checked that pools is non-empty
|
||||
IOAddress next = pools[0]->getFirstAddress();
|
||||
subnet->setLastAllocated(pool_type_, next);
|
||||
return (next);
|
||||
it = first;
|
||||
}
|
||||
|
||||
// Ok, we have a pool that the last address belonged to, let's use it.
|
||||
|
||||
IOAddress next("::");
|
||||
if (!prefix) {
|
||||
next = IOAddress::increase(last); // basically addr++
|
||||
} else {
|
||||
Pool6Ptr pool6 = boost::dynamic_pointer_cast<Pool6>(*it);
|
||||
if (!pool6) {
|
||||
// Something is gravely wrong here
|
||||
isc_throw(Unexpected, "Wrong type of pool: " << (*it)->toText()
|
||||
<< " is not Pool6");
|
||||
for (;;) {
|
||||
// Trying next pool
|
||||
if (retrying) {
|
||||
for (; it != pools.end(); ++it) {
|
||||
if ((*it)->clientSupported(client_classes)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (it == pools.end()) {
|
||||
// Really out of luck today. That was the last pool.
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Get the next prefix
|
||||
next = increasePrefix(last, pool6->getLength());
|
||||
}
|
||||
if ((*it)->inRange(next)) {
|
||||
// the next one is in the pool as well, so we haven't hit pool boundary yet
|
||||
subnet->setLastAllocated(pool_type_, next);
|
||||
return (next);
|
||||
|
||||
last = (*it)->getLastAllocated();
|
||||
valid = (*it)->isLastAllocatedValid();
|
||||
if (!valid && (last == (*it)->getFirstAddress())) {
|
||||
// Pool was (re)initialized
|
||||
(*it)->setLastAllocated(last);
|
||||
subnet->setLastAllocated(pool_type_, last);
|
||||
return (last);
|
||||
}
|
||||
// still can be bogus
|
||||
if (valid && !(*it)->inRange(last)) {
|
||||
valid = false;
|
||||
(*it)->resetLastAllocated();
|
||||
(*it)->setLastAllocated((*it)->getFirstAddress());
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
// Ok, we have a pool that the last address belonged to, let's use it.
|
||||
if (prefix) {
|
||||
Pool6Ptr pool6 = boost::dynamic_pointer_cast<Pool6>(*it);
|
||||
|
||||
if (!pool6) {
|
||||
// Something is gravely wrong here
|
||||
isc_throw(Unexpected, "Wrong type of pool: "
|
||||
<< (*it)->toText()
|
||||
<< " is not Pool6");
|
||||
}
|
||||
// Get the prefix length
|
||||
prefix_len = pool6->getLength();
|
||||
}
|
||||
|
||||
IOAddress next = increaseAddress(last, prefix, prefix_len);
|
||||
if ((*it)->inRange(next)) {
|
||||
// the next one is in the pool as well, so we haven't hit
|
||||
// pool boundary yet
|
||||
(*it)->setLastAllocated(next);
|
||||
subnet->setLastAllocated(pool_type_, next);
|
||||
return (next);
|
||||
}
|
||||
|
||||
valid = false;
|
||||
(*it)->resetLastAllocated();
|
||||
}
|
||||
// We hit pool boundary, let's try to jump to the next pool and try again
|
||||
++it;
|
||||
retrying = true;
|
||||
}
|
||||
|
||||
// We hit pool boundary, let's try to jump to the next pool and try again
|
||||
++it;
|
||||
if (it == pools.end()) {
|
||||
// Really out of luck today. That was the last pool. Let's rewind
|
||||
// to the beginning.
|
||||
next = pools[0]->getFirstAddress();
|
||||
subnet->setLastAllocated(pool_type_, next);
|
||||
return (next);
|
||||
// Let's rewind to the beginning.
|
||||
for (it = first; it != pools.end(); ++it) {
|
||||
if ((*it)->clientSupported(client_classes)) {
|
||||
(*it)->setLastAllocated((*it)->getFirstAddress());
|
||||
(*it)->resetLastAllocated();
|
||||
}
|
||||
}
|
||||
|
||||
// there is a next pool, let's try first address from it
|
||||
next = (*it)->getFirstAddress();
|
||||
subnet->setLastAllocated(pool_type_, next);
|
||||
return (next);
|
||||
// ok to access first element directly. We checked that pools is non-empty
|
||||
last = (*first)->getLastAllocated();
|
||||
(*first)->setLastAllocated(last);
|
||||
subnet->setLastAllocated(pool_type_, last);
|
||||
return (last);
|
||||
}
|
||||
|
||||
AllocEngine::HashedAllocator::HashedAllocator(Lease::Type lease_type)
|
||||
@ -228,6 +292,7 @@ AllocEngine::HashedAllocator::HashedAllocator(Lease::Type lease_type)
|
||||
|
||||
isc::asiolink::IOAddress
|
||||
AllocEngine::HashedAllocator::pickAddress(const SubnetPtr&,
|
||||
const ClientClasses&,
|
||||
const DuidPtr&,
|
||||
const IOAddress&) {
|
||||
isc_throw(NotImplemented, "Hashed allocator is not implemented");
|
||||
@ -241,6 +306,7 @@ AllocEngine::RandomAllocator::RandomAllocator(Lease::Type lease_type)
|
||||
|
||||
isc::asiolink::IOAddress
|
||||
AllocEngine::RandomAllocator::pickAddress(const SubnetPtr&,
|
||||
const ClientClasses&,
|
||||
const DuidPtr&,
|
||||
const IOAddress&) {
|
||||
isc_throw(NotImplemented, "Random allocator is not implemented");
|
||||
@ -361,20 +427,29 @@ namespace {
|
||||
/// function when it belongs to a shared network.
|
||||
/// @param lease_type Type of the lease.
|
||||
/// @param address IPv6 address or prefix to be checked.
|
||||
/// @param check_subnet if true only subnets are checked else both subnets
|
||||
/// and pools are checked
|
||||
///
|
||||
/// @return true if address belongs to a pool in a selected subnet or in
|
||||
/// a pool within any of the subnets belonging to the current shared network.
|
||||
bool
|
||||
inAllowedPool(AllocEngine::ClientContext6& ctx, const Lease::Type& lease_type,
|
||||
const IOAddress& address) {
|
||||
const IOAddress& address, bool check_subnet) {
|
||||
// If the subnet belongs to a shared network we will be iterating
|
||||
// over the subnets that belong to this shared network.
|
||||
Subnet6Ptr current_subnet = ctx.subnet_;
|
||||
while (current_subnet) {
|
||||
|
||||
if (current_subnet->clientSupported(ctx.query_->getClasses())) {
|
||||
if (current_subnet->inPool(lease_type, address)) {
|
||||
return (true);
|
||||
if (check_subnet) {
|
||||
if (current_subnet->inPool(lease_type, address)) {
|
||||
return (true);
|
||||
}
|
||||
} else {
|
||||
if (current_subnet->inPool(lease_type, address,
|
||||
ctx.query_->getClasses())) {
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -677,7 +752,12 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
|
||||
// check if the hint is in pool and is available
|
||||
// This is equivalent of subnet->inPool(hint), but returns the pool
|
||||
pool = boost::dynamic_pointer_cast<Pool6>
|
||||
(subnet->getPool(ctx.currentIA().type_, hint, false));
|
||||
(subnet->getPool(ctx.currentIA().type_, ctx.query_->getClasses(), hint));
|
||||
|
||||
// check if the pool is allowed
|
||||
if (pool && !pool->clientSupported(ctx.query_->getClasses())) {
|
||||
pool.reset();
|
||||
}
|
||||
|
||||
if (pool) {
|
||||
|
||||
@ -775,14 +855,23 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
|
||||
// - we find a free address
|
||||
// - we find an address for which the lease has expired
|
||||
// - we exhaust number of tries
|
||||
uint64_t max_attempts = (attempts_ > 0 ? attempts_ :
|
||||
subnet->getPoolCapacity(ctx.currentIA().type_));
|
||||
uint64_t possible_attempts =
|
||||
subnet->getPoolCapacity(ctx.currentIA().type_,
|
||||
ctx.query_->getClasses());
|
||||
// Try next subnet if there is no chance to get something
|
||||
if (possible_attempts == 0) {
|
||||
subnet = subnet->getNextSubnet(original_subnet);
|
||||
continue;
|
||||
}
|
||||
uint64_t max_attempts = (attempts_ > 0 ? attempts_ : possible_attempts);
|
||||
|
||||
for (uint64_t i = 0; i < max_attempts; ++i) {
|
||||
|
||||
++total_attempts;
|
||||
|
||||
IOAddress candidate = allocator->pickAddress(subnet, ctx.duid_,
|
||||
IOAddress candidate = allocator->pickAddress(subnet,
|
||||
ctx.query_->getClasses(),
|
||||
ctx.duid_,
|
||||
hint);
|
||||
|
||||
/// In-pool reservations: Check if this address is reserved for someone
|
||||
@ -800,7 +889,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
|
||||
uint8_t prefix_len = 128;
|
||||
if (ctx.currentIA().type_ == Lease::TYPE_PD) {
|
||||
pool = boost::dynamic_pointer_cast<Pool6>(
|
||||
subnet->getPool(ctx.currentIA().type_, candidate, false));
|
||||
subnet->getPool(ctx.currentIA().type_, ctx.query_->getClasses(), candidate));
|
||||
if (pool) {
|
||||
prefix_len = pool->getLength();
|
||||
}
|
||||
@ -1034,11 +1123,14 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx,
|
||||
void
|
||||
AllocEngine::removeNonmatchingReservedLeases6(ClientContext6& ctx,
|
||||
Lease6Collection& existing_leases) {
|
||||
// If there are no leases (so nothing to remove) or
|
||||
// host reservation is disabled (so there are no reserved leases),
|
||||
// just return.
|
||||
if (existing_leases.empty() || !ctx.subnet_ ||
|
||||
(ctx.subnet_->getHostReservationMode() == Network::HR_DISABLED) ) {
|
||||
// If there are no leases (so nothing to remove) just return.
|
||||
if (existing_leases.empty() || !ctx.subnet_) {
|
||||
return;
|
||||
}
|
||||
// If host reservation is disabled (so there are no reserved leases)
|
||||
// use the simplified version.
|
||||
if (ctx.subnet_->getHostReservationMode() == Network::HR_DISABLED) {
|
||||
removeNonmatchingReservedNoHostLeases6(ctx, existing_leases);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1075,7 +1167,8 @@ AllocEngine::removeNonmatchingReservedLeases6(ClientContext6& ctx,
|
||||
// be allocated to us from a dynamic pool, but we must check if
|
||||
// this lease belongs to any pool. If it does, we can proceed to
|
||||
// checking the next lease.
|
||||
if (!host && inAllowedPool(ctx, candidate->type_, candidate->addr_)) {
|
||||
if (!host && inAllowedPool(ctx, candidate->type_,
|
||||
candidate->addr_, false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1122,6 +1215,44 @@ AllocEngine::removeNonmatchingReservedLeases6(ClientContext6& ctx,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AllocEngine::removeNonmatchingReservedNoHostLeases6(ClientContext6& ctx,
|
||||
Lease6Collection& existing_leases) {
|
||||
// We need a copy, so we won't be iterating over a container and
|
||||
// removing from it at the same time. It's only a copy of pointers,
|
||||
// so the operation shouldn't be that expensive.
|
||||
Lease6Collection copy = existing_leases;
|
||||
|
||||
BOOST_FOREACH(const Lease6Ptr& candidate, copy) {
|
||||
// Lease can be allocated to us from a dynamic pool, but we must
|
||||
// check if this lease belongs to any allowed pool. If it does,
|
||||
// we can proceed to checking the next lease.
|
||||
if (inAllowedPool(ctx, candidate->type_,
|
||||
candidate->addr_, false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove this lease from LeaseMgr as it doesn't belong to a pool.
|
||||
LeaseMgrFactory::instance().deleteLease(candidate->addr_);
|
||||
|
||||
// Update DNS if needed.
|
||||
queueNCR(CHG_REMOVE, candidate);
|
||||
|
||||
// Need to decrease statistic for assigned addresses.
|
||||
StatsMgr::instance().addValue(
|
||||
StatsMgr::generateName("subnet", candidate->subnet_id_,
|
||||
ctx.currentIA().type_ == Lease::TYPE_NA ?
|
||||
"assigned-nas" : "assigned-pds"),
|
||||
static_cast<int64_t>(-1));
|
||||
|
||||
// Add this to the list of removed leases.
|
||||
ctx.currentIA().old_leases_.push_back(candidate);
|
||||
|
||||
// Let's remove this candidate from existing leases
|
||||
removeLeases(existing_leases, candidate->addr_);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AllocEngine::removeLeases(Lease6Collection& container, const asiolink::IOAddress& addr) {
|
||||
|
||||
@ -1678,7 +1809,8 @@ AllocEngine::updateLeaseData(ClientContext6& ctx, const Lease6Collection& leases
|
||||
|
||||
// If the lease is in the current subnet we need to account
|
||||
// for the re-assignment of The lease.
|
||||
if (inAllowedPool(ctx, ctx.currentIA().type_, lease->addr_)) {
|
||||
if (inAllowedPool(ctx, ctx.currentIA().type_,
|
||||
lease->addr_, true)) {
|
||||
StatsMgr::instance().addValue(
|
||||
StatsMgr::generateName("subnet", lease->subnet_id_,
|
||||
ctx.currentIA().type_ == Lease::TYPE_NA ?
|
||||
@ -2481,6 +2613,7 @@ void findClientLease(AllocEngine::ClientContext4& ctx, Lease4Ptr& client_lease)
|
||||
/// within a shared network.
|
||||
///
|
||||
/// @todo Update this function to take client classification into account.
|
||||
/// @note client classification in pools (vs subnets) is checked
|
||||
///
|
||||
/// @param ctx Client context. Current subnet may be modified by this
|
||||
/// function when it belongs to a shared network.
|
||||
@ -2495,7 +2628,8 @@ inAllowedPool(AllocEngine::ClientContext4& ctx, const IOAddress& address) {
|
||||
Subnet4Ptr current_subnet = ctx.subnet_;
|
||||
while (current_subnet) {
|
||||
|
||||
if (current_subnet->inPool(Lease::TYPE_V4, address)) {
|
||||
if (current_subnet->inPool(Lease::TYPE_V4, address,
|
||||
ctx.query_->getClasses())) {
|
||||
// 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.
|
||||
@ -2819,9 +2953,13 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) {
|
||||
// If the client is requesting an address which is assigned to the client
|
||||
// let's just renew this address. Also, renew this address if the client
|
||||
// doesn't request any specific address.
|
||||
// Added extra checks: the address is reserved or belongs to the dynamic
|
||||
// pool for the case the pool class has changed before the request.
|
||||
if (client_lease) {
|
||||
if ((client_lease->addr_ == ctx.requested_address_) ||
|
||||
ctx.requested_address_.isV4Zero()) {
|
||||
if (((client_lease->addr_ == ctx.requested_address_) ||
|
||||
ctx.requested_address_.isV4Zero()) &&
|
||||
(hasAddressReservation(ctx) ||
|
||||
inAllowedPool(ctx, client_lease->addr_))) {
|
||||
|
||||
LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE,
|
||||
ALLOC_ENGINE_V4_REQUEST_EXTEND_LEASE)
|
||||
@ -3217,10 +3355,19 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) {
|
||||
client_id = ctx.clientid_;
|
||||
}
|
||||
|
||||
const uint64_t max_attempts = (attempts_ > 0 ? attempts_ :
|
||||
subnet->getPoolCapacity(Lease::TYPE_V4));
|
||||
uint64_t possible_attempts =
|
||||
subnet->getPoolCapacity(Lease::TYPE_V4,
|
||||
ctx.query_->getClasses());
|
||||
uint64_t max_attempts = (attempts_ > 0 ? attempts_ : possible_attempts);
|
||||
// Skip trying if there is no chance to get something
|
||||
if (possible_attempts == 0) {
|
||||
max_attempts = 0;
|
||||
}
|
||||
|
||||
for (uint64_t i = 0; i < max_attempts; ++i) {
|
||||
IOAddress candidate = allocator->pickAddress(subnet, client_id,
|
||||
IOAddress candidate = allocator->pickAddress(subnet,
|
||||
ctx.query_->getClasses(),
|
||||
client_id,
|
||||
ctx.requested_address_);
|
||||
// If address is not reserved for another client, try to allocate it.
|
||||
if (!addressReserved(candidate, ctx)) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -8,6 +8,7 @@
|
||||
#define ALLOC_ENGINE_H
|
||||
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcp/classify.h>
|
||||
#include <dhcp/duid.h>
|
||||
#include <dhcp/hwaddr.h>
|
||||
#include <dhcp/pkt4.h>
|
||||
@ -78,13 +79,18 @@ protected:
|
||||
/// than pickResource(), because nobody would immediately know what the
|
||||
/// resource means in this context.
|
||||
///
|
||||
/// Pools which are not allowed for client classes are skipped.
|
||||
///
|
||||
/// @param subnet next address will be returned from pool of that subnet
|
||||
/// @param client_classes list of classes client belongs to
|
||||
/// @param duid Client's DUID
|
||||
/// @param hint client's hint
|
||||
///
|
||||
/// @return the next address
|
||||
virtual isc::asiolink::IOAddress
|
||||
pickAddress(const SubnetPtr& subnet, const DuidPtr& duid,
|
||||
pickAddress(const SubnetPtr& subnet,
|
||||
const ClientClasses& client_classes,
|
||||
const DuidPtr& duid,
|
||||
const isc::asiolink::IOAddress& hint) = 0;
|
||||
|
||||
/// @brief Default constructor.
|
||||
@ -125,11 +131,13 @@ protected:
|
||||
/// @brief returns the next address from pools in a subnet
|
||||
///
|
||||
/// @param subnet next address will be returned from pool of that subnet
|
||||
/// @param client_classes list of classes client belongs to
|
||||
/// @param duid Client's DUID (ignored)
|
||||
/// @param hint client's hint (ignored)
|
||||
/// @return the next address
|
||||
virtual isc::asiolink::IOAddress
|
||||
pickAddress(const SubnetPtr& subnet,
|
||||
const ClientClasses& client_classes,
|
||||
const DuidPtr& duid,
|
||||
const isc::asiolink::IOAddress& hint);
|
||||
protected:
|
||||
@ -147,6 +155,20 @@ protected:
|
||||
static isc::asiolink::IOAddress
|
||||
increasePrefix(const isc::asiolink::IOAddress& prefix,
|
||||
const uint8_t prefix_len);
|
||||
|
||||
/// @brief Returns the next address or prefix
|
||||
///
|
||||
/// This method works for IPv4 addresses, IPv6 addresses and
|
||||
/// IPv6 prefixes.
|
||||
///
|
||||
/// @param address address or prefix to be increased
|
||||
/// @param prefix true when the previous argument is a prefix
|
||||
/// @param prefix_len length of the prefix
|
||||
/// @return result address or prefix
|
||||
static isc::asiolink::IOAddress
|
||||
increaseAddress(const isc::asiolink::IOAddress& address,
|
||||
bool prefix, const uint8_t prefix_len);
|
||||
|
||||
};
|
||||
|
||||
/// @brief Address/prefix allocator that gets an address based on a hash
|
||||
@ -164,12 +186,15 @@ protected:
|
||||
/// @todo: Implement this method
|
||||
///
|
||||
/// @param subnet an address will be picked from pool of that subnet
|
||||
/// @param client_classes list of classes client belongs to
|
||||
/// @param duid Client's DUID
|
||||
/// @param hint a hint (last address that was picked)
|
||||
/// @return selected address
|
||||
virtual isc::asiolink::IOAddress pickAddress(const SubnetPtr& subnet,
|
||||
const DuidPtr& duid,
|
||||
const isc::asiolink::IOAddress& hint);
|
||||
virtual isc::asiolink::IOAddress
|
||||
pickAddress(const SubnetPtr& subnet,
|
||||
const ClientClasses& client_classes,
|
||||
const DuidPtr& duid,
|
||||
const isc::asiolink::IOAddress& hint);
|
||||
};
|
||||
|
||||
/// @brief Random allocator that picks address randomly
|
||||
@ -187,11 +212,14 @@ protected:
|
||||
/// @todo: Implement this method
|
||||
///
|
||||
/// @param subnet an address will be picked from pool of that subnet
|
||||
/// @param client_classes list of classes client belongs to
|
||||
/// @param duid Client's DUID (ignored)
|
||||
/// @param hint the last address that was picked (ignored)
|
||||
/// @return a random address from the pool
|
||||
virtual isc::asiolink::IOAddress
|
||||
pickAddress(const SubnetPtr& subnet, const DuidPtr& duid,
|
||||
pickAddress(const SubnetPtr& subnet,
|
||||
const ClientClasses& client_classes,
|
||||
const DuidPtr& duid,
|
||||
const isc::asiolink::IOAddress& hint);
|
||||
};
|
||||
|
||||
@ -803,8 +831,8 @@ private:
|
||||
/// @brief Removes leases that are reserved for someone else.
|
||||
///
|
||||
/// Goes through the list specified in existing_leases and removes those that
|
||||
/// are reserved by someone else. The removed leases are added to the
|
||||
/// ctx.removed_leases_ collection.
|
||||
/// are reserved by someone else or do not belong to an allowed pool.
|
||||
/// The removed leases are added to the ctx.removed_leases_ collection.
|
||||
///
|
||||
/// @param ctx client context that contains all details (subnet, client-id, etc.)
|
||||
/// @param existing_leases [in/out] leases that should be checked
|
||||
@ -812,6 +840,17 @@ private:
|
||||
removeNonmatchingReservedLeases6(ClientContext6& ctx,
|
||||
Lease6Collection& existing_leases);
|
||||
|
||||
/// @brief Removes leases that are reserved for someone else.
|
||||
///
|
||||
/// Simplified version of removeNonmatchingReservedLeases6 to be
|
||||
/// used when host reservations are disabled.
|
||||
///
|
||||
/// @param ctx client context that contains all details (subnet, client-id, etc.)
|
||||
/// @param existing_leases [in/out] leases that should be checked
|
||||
void
|
||||
removeNonmatchingReservedNoHostLeases6(ClientContext6& ctx,
|
||||
Lease6Collection& existing_leases);
|
||||
|
||||
/// @brief Removed leases that are not reserved for this client
|
||||
///
|
||||
/// This method iterates over existing_leases and will remove leases that are
|
||||
|
@ -377,6 +377,15 @@ PoolParser::parse(PoolStoragePtr pools,
|
||||
<< " (" << option_data->getPosition() << ")");
|
||||
}
|
||||
}
|
||||
|
||||
// Client-class.
|
||||
ConstElementPtr client_class = pool_structure->get("client-class");
|
||||
if (client_class) {
|
||||
string cclass = client_class->stringValue();
|
||||
if (!cclass.empty()) {
|
||||
pool->allowClientClass(cclass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//****************************** Pool4Parser *************************
|
||||
@ -846,6 +855,11 @@ PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) {
|
||||
user_context_ = user_context;
|
||||
}
|
||||
|
||||
ConstElementPtr client_class = pd_pool_->get("client-class");
|
||||
if (client_class) {
|
||||
client_class_ = client_class;
|
||||
}
|
||||
|
||||
// Check the pool parameters. It will throw an exception if any
|
||||
// of the required parameters are invalid.
|
||||
try {
|
||||
@ -869,6 +883,14 @@ PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) {
|
||||
pool_->setContext(user_context_);
|
||||
}
|
||||
|
||||
|
||||
if (client_class_) {
|
||||
string cclass = client_class_->stringValue();
|
||||
if (!cclass.empty()) {
|
||||
pool_->allowClientClass(cclass);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the local pool to the external storage ptr.
|
||||
pools->push_back(pool_);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2013-2018 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -651,7 +651,16 @@ private:
|
||||
/// A storage for pool specific option values.
|
||||
CfgOptionPtr options_;
|
||||
|
||||
/// @brief User context (optional, may be null)
|
||||
///
|
||||
/// User context is arbitrary user data, to be used by hooks.
|
||||
isc::data::ConstElementPtr user_context_;
|
||||
|
||||
/// @brief Client class (a client has to belong to to use this pd-pool)
|
||||
///
|
||||
/// If null, everyone is allowed.
|
||||
isc::data::ConstElementPtr client_class_;
|
||||
|
||||
};
|
||||
|
||||
/// @brief Parser for a list of prefix delegation pools.
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -20,13 +20,35 @@ namespace dhcp {
|
||||
Pool::Pool(Lease::Type type, const isc::asiolink::IOAddress& first,
|
||||
const isc::asiolink::IOAddress& last)
|
||||
:id_(getNextID()), first_(first), last_(last), type_(type),
|
||||
capacity_(0), cfg_option_(new CfgOption()) {
|
||||
capacity_(0), cfg_option_(new CfgOption()), white_list_(),
|
||||
last_allocated_(first), last_allocated_valid_(false) {
|
||||
}
|
||||
|
||||
bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
|
||||
return (first_.smallerEqual(addr) && addr.smallerEqual(last_));
|
||||
}
|
||||
|
||||
bool Pool::clientSupported(const ClientClasses& classes) const {
|
||||
if (white_list_.empty()) {
|
||||
// There is no class defined for this pool, so we do
|
||||
// support everyone.
|
||||
return (true);
|
||||
}
|
||||
|
||||
for (ClientClasses::const_iterator it = white_list_.begin();
|
||||
it != white_list_.end(); ++it) {
|
||||
if (classes.contains(*it)) {
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
void Pool::allowClientClass(const ClientClass& class_name) {
|
||||
white_list_.insert(class_name);
|
||||
}
|
||||
|
||||
std::string
|
||||
Pool::toText() const {
|
||||
std::stringstream tmp;
|
||||
@ -88,6 +110,16 @@ Pool::toElement() const {
|
||||
// Set pool options
|
||||
ConstCfgOptionPtr opts = getCfgOption();
|
||||
map->set("option-data", opts->toElement());
|
||||
|
||||
// Set client-class
|
||||
const ClientClasses& cclasses = getClientClasses();
|
||||
if (cclasses.size() > 1) {
|
||||
isc_throw(ToElementError, "client-class has too many items: "
|
||||
<< cclasses.size());
|
||||
} else if (!cclasses.empty()) {
|
||||
map->set("client-class", Element::create(*cclasses.cbegin()));
|
||||
}
|
||||
|
||||
return (map);
|
||||
}
|
||||
|
||||
@ -310,6 +342,7 @@ Pool6::toElement() const {
|
||||
isc_throw(ToElementError, "invalid prefix range "
|
||||
<< prefix.toText() << "-" << last.toText());
|
||||
}
|
||||
map->set("prefix-len", Element::create(prefix_len));
|
||||
|
||||
// Set delegated-len
|
||||
uint8_t len = getLength();
|
||||
@ -324,10 +357,14 @@ Pool6::toElement() const {
|
||||
uint8_t xlen = xopt->getExcludedPrefixLength();
|
||||
map->set("excluded-prefix-len",
|
||||
Element::create(static_cast<int>(xlen)));
|
||||
} else {
|
||||
map->set("excluded-prefix", Element::create(std::string("::")));
|
||||
map->set("excluded-prefix-len", Element::create(0));
|
||||
}
|
||||
// Let's not insert empty excluded-prefix values. If we ever
|
||||
// decide to insert it after all, here's the code to do it:
|
||||
// else {
|
||||
// map->set("excluded-prefix",
|
||||
// Element::create(std::string("::")));
|
||||
// map->set("excluded-prefix-len", Element::create(0));
|
||||
/// }
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -8,6 +8,7 @@
|
||||
#define POOL_H
|
||||
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcp/classify.h>
|
||||
#include <dhcp/option6_pdexclude.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <cc/data.h>
|
||||
@ -96,6 +97,57 @@ public:
|
||||
return (cfg_option_);
|
||||
}
|
||||
|
||||
/// @brief Checks whether this pool supports client that belongs to
|
||||
/// specified classes.
|
||||
///
|
||||
/// @todo: currently doing the same as network which needs improving.
|
||||
///
|
||||
/// @param client_classes list of all classes the client belongs to
|
||||
/// @return true if client can be supported, false otherwise
|
||||
bool clientSupported(const ClientClasses& client_classes) const;
|
||||
|
||||
/// @brief Adds class class_name to the list of supported classes
|
||||
///
|
||||
/// @param class_name client class to be supported by this pool
|
||||
void allowClientClass(const ClientClass& class_name);
|
||||
|
||||
/// @brief returns the client class white list
|
||||
///
|
||||
/// @note Currently white list is empty or has one element
|
||||
/// @note The returned reference is only valid as long as the object
|
||||
/// returned is valid.
|
||||
///
|
||||
/// @return client classes @ref white_list_
|
||||
const ClientClasses& getClientClasses() const {
|
||||
return (white_list_);
|
||||
}
|
||||
|
||||
/// @brief returns the last address that was tried from this pool
|
||||
///
|
||||
/// @return address/prefix that was last tried from this pool
|
||||
isc::asiolink::IOAddress getLastAllocated() const {
|
||||
return last_allocated_;
|
||||
}
|
||||
|
||||
/// @brief checks if the last address is valid
|
||||
/// @return true if the last address is valid
|
||||
bool isLastAllocatedValid() const {
|
||||
return last_allocated_valid_;
|
||||
}
|
||||
|
||||
/// @brief sets the last address that was tried from this pool
|
||||
///
|
||||
/// @param addr address/prefix to that was tried last
|
||||
void setLastAllocated(const isc::asiolink::IOAddress& addr) {
|
||||
last_allocated_ = addr;
|
||||
last_allocated_valid_ = true;
|
||||
}
|
||||
|
||||
/// @brief resets the last address to invalid
|
||||
void resetLastAllocated() {
|
||||
last_allocated_valid_ = false;
|
||||
}
|
||||
|
||||
/// @brief Unparse a pool object.
|
||||
///
|
||||
/// @return A pointer to unparsed pool configuration.
|
||||
@ -148,6 +200,22 @@ protected:
|
||||
|
||||
/// @brief Pointer to the option data configuration for this pool.
|
||||
CfgOptionPtr cfg_option_;
|
||||
|
||||
/// @brief Optional definition of a client class
|
||||
///
|
||||
/// If empty, all classes are allowed. If non-empty, only those listed
|
||||
/// here are allowed.
|
||||
///
|
||||
/// @ref Network::white_list_
|
||||
ClientClasses white_list_;
|
||||
|
||||
/// @brief Last allocated address
|
||||
/// See @ref isc::dhcp::Subnet::last_allocated_ia_
|
||||
/// Initialized and reset to first
|
||||
isc::asiolink::IOAddress last_allocated_;
|
||||
|
||||
/// @brief Status of last allocated address
|
||||
bool last_allocated_valid_;
|
||||
};
|
||||
|
||||
/// @brief Pool information for IPv4 addresses
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -134,6 +134,23 @@ Subnet::getPoolCapacity(Lease::Type type) const {
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Subnet::getPoolCapacity(Lease::Type type,
|
||||
const ClientClasses& client_classes) const {
|
||||
switch (type) {
|
||||
case Lease::TYPE_V4:
|
||||
case Lease::TYPE_NA:
|
||||
return sumPoolCapacity(pools_, client_classes);
|
||||
case Lease::TYPE_TA:
|
||||
return sumPoolCapacity(pools_ta_, client_classes);
|
||||
case Lease::TYPE_PD:
|
||||
return sumPoolCapacity(pools_pd_, client_classes);
|
||||
default:
|
||||
isc_throw(BadValue, "Unsupported pool type: "
|
||||
<< static_cast<int>(type));
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Subnet::sumPoolCapacity(const PoolCollection& pools) const {
|
||||
uint64_t sum = 0;
|
||||
@ -152,6 +169,28 @@ Subnet::sumPoolCapacity(const PoolCollection& pools) const {
|
||||
return (sum);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Subnet::sumPoolCapacity(const PoolCollection& pools,
|
||||
const ClientClasses& client_classes) const {
|
||||
uint64_t sum = 0;
|
||||
for (PoolCollection::const_iterator p = pools.begin(); p != pools.end(); ++p) {
|
||||
if (!(*p)->clientSupported(client_classes)) {
|
||||
continue;
|
||||
}
|
||||
uint64_t x = (*p)->getCapacity();
|
||||
|
||||
// Check if we can add it. If sum + x > uint64::max, then we would have
|
||||
// overflown if we tried to add it.
|
||||
if (x > std::numeric_limits<uint64_t>::max() - sum) {
|
||||
return (std::numeric_limits<uint64_t>::max());
|
||||
}
|
||||
|
||||
sum += x;
|
||||
}
|
||||
|
||||
return (sum);
|
||||
}
|
||||
|
||||
void Subnet4::checkType(Lease::Type type) const {
|
||||
if (type != Lease::TYPE_V4) {
|
||||
isc_throw(BadValue, "Only TYPE_V4 is allowed for Subnet4");
|
||||
@ -329,6 +368,33 @@ const PoolPtr Subnet::getPool(Lease::Type type, const isc::asiolink::IOAddress&
|
||||
return (candidate);
|
||||
}
|
||||
|
||||
const PoolPtr Subnet::getPool(Lease::Type type,
|
||||
const ClientClasses& client_classes,
|
||||
const isc::asiolink::IOAddress& hint) const {
|
||||
// check if the type is valid (and throw if it isn't)
|
||||
checkType(type);
|
||||
|
||||
const PoolCollection& pools = getPools(type);
|
||||
|
||||
PoolPtr candidate;
|
||||
|
||||
if (!pools.empty()) {
|
||||
PoolCollection::const_iterator ub =
|
||||
std::upper_bound(pools.begin(), pools.end(), hint,
|
||||
prefixLessThanFirstAddress);
|
||||
|
||||
if (ub != pools.begin()) {
|
||||
--ub;
|
||||
if ((*ub)->inRange(hint) && (*ub)->clientSupported(client_classes)) {
|
||||
candidate = *ub;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return a pool or NULL if no match found.
|
||||
return (candidate);
|
||||
}
|
||||
|
||||
void
|
||||
Subnet::addPool(const PoolPtr& pool) {
|
||||
// check if the type is valid (and throw if it isn't)
|
||||
@ -409,6 +475,31 @@ Subnet::inPool(Lease::Type type, const isc::asiolink::IOAddress& addr) const {
|
||||
return (false);
|
||||
}
|
||||
|
||||
bool
|
||||
Subnet::inPool(Lease::Type type,
|
||||
const isc::asiolink::IOAddress& addr,
|
||||
const ClientClasses& client_classes) const {
|
||||
|
||||
// Let's start with checking if it even belongs to that subnet.
|
||||
if ((type != Lease::TYPE_PD) && !inRange(addr)) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
const PoolCollection& pools = getPools(type);
|
||||
|
||||
for (PoolCollection::const_iterator pool = pools.begin();
|
||||
pool != pools.end(); ++pool) {
|
||||
if (!(*pool)->clientSupported(client_classes)) {
|
||||
continue;
|
||||
}
|
||||
if ((*pool)->inRange(addr)) {
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
// There's no pool that address belongs to
|
||||
return (false);
|
||||
}
|
||||
|
||||
bool
|
||||
Subnet::poolOverlaps(const Lease::Type& pool_type, const PoolPtr& pool) const {
|
||||
const PoolCollection& pools = getPools(pool_type);
|
||||
@ -618,78 +709,16 @@ Subnet6::toElement() const {
|
||||
ElementPtr pool_list = Element::createList();
|
||||
for (PoolCollection::const_iterator pool = pools.cbegin();
|
||||
pool != pools.cend(); ++pool) {
|
||||
// Prepare the map for a pool (@todo move this code to pool.cc)
|
||||
ElementPtr pool_map = Element::createMap();
|
||||
// Set user-context
|
||||
(*pool)->contextToElement(pool_map);
|
||||
// Set pool
|
||||
const IOAddress& first = (*pool)->getFirstAddress();
|
||||
const IOAddress& last = (*pool)->getLastAddress();
|
||||
std::string range = first.toText() + "-" + last.toText();
|
||||
// Try to output a prefix (vs a range)
|
||||
int prefix_len = prefixLengthFromRange(first, last);
|
||||
if (prefix_len >= 0) {
|
||||
std::ostringstream oss;
|
||||
oss << first.toText() << "/" << prefix_len;
|
||||
range = oss.str();
|
||||
}
|
||||
pool_map->set("pool", Element::create(range));
|
||||
// Set pool options
|
||||
ConstCfgOptionPtr opts = (*pool)->getCfgOption();
|
||||
pool_map->set("option-data", opts->toElement());
|
||||
// Push on the pool list
|
||||
pool_list->add(pool_map);
|
||||
pool_list->add((*pool)->toElement());
|
||||
}
|
||||
map->set("pools", pool_list);
|
||||
|
||||
// Set pd-pools
|
||||
const PoolCollection& pdpools = getPools(Lease::TYPE_PD);
|
||||
ElementPtr pdpool_list = Element::createList();
|
||||
for (PoolCollection::const_iterator pool = pdpools.cbegin();
|
||||
pool != pdpools.cend(); ++pool) {
|
||||
// Get it as a Pool6 (@todo move this code to pool.cc)
|
||||
const Pool6* pdpool = dynamic_cast<Pool6*>(pool->get());
|
||||
if (!pdpool) {
|
||||
isc_throw(ToElementError, "invalid pd-pool pointer");
|
||||
}
|
||||
// Prepare the map for a pd-pool
|
||||
ElementPtr pool_map = Element::createMap();
|
||||
// Set user-context
|
||||
pdpool->contextToElement(pool_map);
|
||||
// Set prefix
|
||||
const IOAddress& prefix = pdpool->getFirstAddress();
|
||||
pool_map->set("prefix", Element::create(prefix.toText()));
|
||||
// Set prefix-len (get it from min - max)
|
||||
const IOAddress& last = pdpool->getLastAddress();
|
||||
int prefix_len = prefixLengthFromRange(prefix, last);
|
||||
if (prefix_len < 0) {
|
||||
// The pool is bad: give up
|
||||
isc_throw(ToElementError, "invalid prefix range "
|
||||
<< prefix.toText() << "-" << last.toText());
|
||||
}
|
||||
pool_map->set("prefix-len", Element::create(prefix_len));
|
||||
// Set delegated-len
|
||||
uint8_t len = pdpool->getLength();
|
||||
pool_map->set("delegated-len",
|
||||
Element::create(static_cast<int>(len)));
|
||||
|
||||
// Set excluded prefix
|
||||
const Option6PDExcludePtr& xopt =
|
||||
pdpool->getPrefixExcludeOption();
|
||||
if (xopt) {
|
||||
const IOAddress& xprefix =
|
||||
xopt->getExcludedPrefix(prefix, len);
|
||||
pool_map->set("excluded-prefix",
|
||||
Element::create(xprefix.toText()));
|
||||
uint8_t xlen = xopt->getExcludedPrefixLength();
|
||||
pool_map->set("excluded-prefix-len",
|
||||
Element::create(static_cast<int>(xlen)));
|
||||
}
|
||||
|
||||
// Set pool options
|
||||
ConstCfgOptionPtr opts = pdpool->getCfgOption();
|
||||
pool_map->set("option-data", opts->toElement());
|
||||
// Push on the pool list
|
||||
pdpool_list->add(pool_map);
|
||||
pdpool_list->add((*pool)->toElement());
|
||||
}
|
||||
map->set("pd-pools", pdpool_list);
|
||||
|
||||
|
@ -55,26 +55,39 @@ public:
|
||||
/// @return true if the address is in any of the pools
|
||||
bool inPool(Lease::Type type, const isc::asiolink::IOAddress& addr) const;
|
||||
|
||||
/// @brief returns the last address that was tried from this pool
|
||||
/// @brief checks if the specified address is in allowed pools
|
||||
///
|
||||
/// This takes also into account client classes
|
||||
///
|
||||
/// @param type type of pools to iterate over
|
||||
/// @param addr this address will be checked if it belongs to any pools in
|
||||
/// that subnet
|
||||
/// @param client_classes client class list which must be allowed
|
||||
/// @return true if the address is in any of the allowed pools
|
||||
bool inPool(Lease::Type type,
|
||||
const isc::asiolink::IOAddress& addr,
|
||||
const ClientClasses& client_classes) const;
|
||||
|
||||
/// @brief returns the last address that was tried from this subnet
|
||||
///
|
||||
/// This method returns the last address that was attempted to be allocated
|
||||
/// from this subnet. This is used as helper information for the next
|
||||
/// iteration of the allocation algorithm.
|
||||
///
|
||||
/// @todo: Define map<SubnetID, IOAddress> somewhere in the
|
||||
/// @todo: Define map<SubnetID, ClientClass, IOAddress> somewhere in the
|
||||
/// AllocEngine::IterativeAllocator and keep the data there
|
||||
///
|
||||
/// @param type lease type to be returned
|
||||
/// @return address/prefix that was last tried from this pool
|
||||
/// @return address/prefix that was last tried from this subnet
|
||||
isc::asiolink::IOAddress getLastAllocated(Lease::Type type) const;
|
||||
|
||||
/// @brief sets the last address that was tried from this pool
|
||||
/// @brief sets the last address that was tried from this subnet
|
||||
///
|
||||
/// This method sets the last address that was attempted to be allocated
|
||||
/// from this subnet. This is used as helper information for the next
|
||||
/// iteration of the allocation algorithm.
|
||||
///
|
||||
/// @todo: Define map<SubnetID, IOAddress> somewhere in the
|
||||
/// @todo: Define map<SubnetID, ClientClass, IOAddress> somewhere in the
|
||||
/// AllocEngine::IterativeAllocator and keep the data there
|
||||
/// @param addr address/prefix to that was tried last
|
||||
/// @param type lease type to be set
|
||||
@ -143,6 +156,17 @@ public:
|
||||
const PoolPtr getPool(Lease::Type type, const isc::asiolink::IOAddress& addr,
|
||||
bool anypool = true) const;
|
||||
|
||||
/// @brief Returns a pool that specified address belongs to with classes
|
||||
///
|
||||
/// Variant using only pools allowing given classes
|
||||
///
|
||||
/// @param type pool type that the pool is looked for
|
||||
/// @param client_classes client class list which must be allowed
|
||||
/// @param addr address that the returned pool should cover (optional)
|
||||
const PoolPtr getPool(Lease::Type type,
|
||||
const ClientClasses& client_classes,
|
||||
const isc::asiolink::IOAddress& addr) const;
|
||||
|
||||
/// @brief Returns a pool without any address specified
|
||||
///
|
||||
/// @param type pool type that the pool is looked for
|
||||
@ -170,6 +194,14 @@ public:
|
||||
/// @param type type of the lease
|
||||
uint64_t getPoolCapacity(Lease::Type type) const;
|
||||
|
||||
/// @brief Returns the number of possible leases for specified lease type
|
||||
/// allowed for a client which belongs to classes.
|
||||
///
|
||||
/// @param type type of the lease
|
||||
/// @param client_classes List of classes the client belongs to.
|
||||
uint64_t getPoolCapacity(Lease::Type type,
|
||||
const ClientClasses& client_classes) const;
|
||||
|
||||
/// @brief Returns textual representation of the subnet (e.g.
|
||||
/// "2001:db8::/64")
|
||||
///
|
||||
@ -283,11 +315,18 @@ protected:
|
||||
/// @throw BadValue if invalid value is used
|
||||
virtual void checkType(Lease::Type type) const = 0;
|
||||
|
||||
/// @brief returns a sum of possible leases in all pools
|
||||
/// @brief Returns a sum of possible leases in all pools
|
||||
/// @param pools list of pools
|
||||
/// @return sum of possible leases
|
||||
uint64_t sumPoolCapacity(const PoolCollection& pools) const;
|
||||
|
||||
/// @brief Returns a sum of possible leases in all pools allowing classes
|
||||
/// @param pools list of pools
|
||||
/// @param client_classes list of classes
|
||||
/// @return sum of possible/allowed leases
|
||||
uint64_t sumPoolCapacity(const PoolCollection& pools,
|
||||
const ClientClasses& client_classes) const;
|
||||
|
||||
/// @brief Checks if the specified pool overlaps with an existing pool.
|
||||
///
|
||||
/// @param pool_type Pool type.
|
||||
|
@ -326,12 +326,35 @@ TEST_F(AllocEngine4Test, IterativeAllocator) {
|
||||
alloc(new NakedAllocEngine::IterativeAllocator(Lease::TYPE_V4));
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
IOAddress candidate = alloc->pickAddress(subnet_, clientid_,
|
||||
IOAddress candidate = alloc->pickAddress(subnet_, cc_, clientid_,
|
||||
IOAddress("0.0.0.0"));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
|
||||
}
|
||||
}
|
||||
|
||||
// This test verifies that the allocator picks addresses that belong to the
|
||||
// pool using classification
|
||||
TEST_F(AllocEngine4Test, IterativeAllocator_class) {
|
||||
boost::scoped_ptr<NakedAllocEngine::Allocator>
|
||||
alloc(new NakedAllocEngine::IterativeAllocator(Lease::TYPE_V4));
|
||||
|
||||
// Restrict pool_ to the foo class. Add a second pool with bar class.
|
||||
pool_->allowClientClass("foo");
|
||||
Pool4Ptr pool(new Pool4(IOAddress("192.0.2.200"),
|
||||
IOAddress("192.0.2.209")));
|
||||
pool->allowClientClass("bar");
|
||||
subnet_->addPool(pool);
|
||||
|
||||
// Clients are in bar
|
||||
cc_.insert("bar");
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
IOAddress candidate = alloc->pickAddress(subnet_, cc_, clientid_,
|
||||
IOAddress("0.0.0.0"));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate, cc_));
|
||||
}
|
||||
}
|
||||
|
||||
// This test verifies that the iterative allocator really walks over all addresses
|
||||
// in all pools in specified subnet. It also must not pick the same address twice
|
||||
@ -359,7 +382,7 @@ TEST_F(AllocEngine4Test, IterativeAllocator_manyPools4) {
|
||||
std::set<IOAddress> generated_addrs;
|
||||
int cnt = 0;
|
||||
while (++cnt) {
|
||||
IOAddress candidate = alloc.pickAddress(subnet_, clientid_, IOAddress("0.0.0.0"));
|
||||
IOAddress candidate = alloc.pickAddress(subnet_, cc_, clientid_, IOAddress("0.0.0.0"));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
|
||||
|
||||
// One way to easily verify that the iterative allocator really works is
|
||||
@ -690,6 +713,44 @@ TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkClassification) {
|
||||
EXPECT_EQ("192.0.2.17", lease->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 requires another class.
|
||||
TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkPoolClassification) {
|
||||
|
||||
// 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 pool1. This should be only assigned
|
||||
// to clients belonging to cable-modem class.
|
||||
pool1_->allowClientClass("cable-modem");
|
||||
|
||||
// The allocation engine should determine that the pool1 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 pool1.
|
||||
ctx.query_->addClass(ClientClass("cable-modem"));
|
||||
|
||||
ctx.subnet_ = subnet1_;
|
||||
lease = engine_.allocateLease4(ctx);
|
||||
ASSERT_TRUE(lease);
|
||||
EXPECT_EQ("192.0.2.17", lease->addr_.toText());
|
||||
}
|
||||
|
||||
// Test that reservations within shared network take precedence over the
|
||||
// existing leases regardless in which subnet belonging to a shared network
|
||||
// reservations belong.
|
||||
@ -888,6 +949,59 @@ TEST_F(SharedNetworkAlloc4Test, requestSharedNetworkClassification) {
|
||||
EXPECT_TRUE(subnet2_->inPool(Lease::TYPE_V4, lease->addr_));
|
||||
}
|
||||
|
||||
// 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 requires another class.
|
||||
TEST_F(SharedNetworkAlloc4Test, requestSharedNetworkPoolClassification) {
|
||||
// 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 pool1. This should be only assigned
|
||||
// to clients belonging to cable-modem class.
|
||||
pool1_->allowClientClass("cable-modem");
|
||||
|
||||
// The allocation engine should determine that the pool1 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 pool1.
|
||||
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 pool1 anymore and
|
||||
// assign an address from unrestricted pool.
|
||||
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_));
|
||||
}
|
||||
|
||||
// Test that reservations within shared network take precedence over the
|
||||
// existing leases regardless in which subnet belonging to a shared network
|
||||
// reservations belong (DHCPREQUEST case).
|
||||
|
@ -189,11 +189,34 @@ TEST_F(AllocEngine6Test, IterativeAllocator) {
|
||||
alloc(new NakedAllocEngine::IterativeAllocator(Lease::TYPE_NA));
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
IOAddress candidate = alloc->pickAddress(subnet_, duid_, IOAddress("::"));
|
||||
IOAddress candidate = alloc->pickAddress(subnet_, cc_, duid_, IOAddress("::"));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
|
||||
}
|
||||
}
|
||||
|
||||
// This test verifies that the allocator picks addresses that belong to the
|
||||
// pool using classification
|
||||
TEST_F(AllocEngine6Test, IterativeAllocator_class) {
|
||||
boost::scoped_ptr<NakedAllocEngine::Allocator>
|
||||
alloc(new NakedAllocEngine::IterativeAllocator(Lease::TYPE_NA));
|
||||
|
||||
// Restrict pool_ to the foo class. Add a second pool with bar class.
|
||||
pool_->allowClientClass("foo");
|
||||
Pool6Ptr pool(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::100"),
|
||||
IOAddress("2001:db8:1::109")));
|
||||
pool->allowClientClass("bar");
|
||||
subnet_->addPool(pool);
|
||||
|
||||
// Clients are in bar
|
||||
cc_.insert("bar");
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
IOAddress candidate = alloc->pickAddress(subnet_, cc_, duid_, IOAddress("::"));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate, cc_));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(AllocEngine6Test, IterativeAllocatorAddrStep) {
|
||||
NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_NA);
|
||||
|
||||
@ -210,23 +233,100 @@ TEST_F(AllocEngine6Test, IterativeAllocatorAddrStep) {
|
||||
subnet_->addPool(pool3);
|
||||
|
||||
// Let's check the first pool (5 addresses here)
|
||||
EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::3", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::4", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::5", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::3", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::4", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::5", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// The second pool is easy - only one address here
|
||||
EXPECT_EQ("2001:db8:1::100", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::100", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// This is the third and last pool, with 2 addresses in it
|
||||
EXPECT_EQ("2001:db8:1::105", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::106", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::105", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::106", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// We iterated over all addresses and reached to the end of the last pool.
|
||||
// Let's wrap around and start from the beginning
|
||||
EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
}
|
||||
|
||||
TEST_F(AllocEngine6Test, IterativeAllocatorAddrStepInClass) {
|
||||
NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_NA);
|
||||
|
||||
subnet_->delPools(Lease::TYPE_NA); // Get rid of default pool
|
||||
|
||||
Pool6Ptr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"),
|
||||
IOAddress("2001:db8:1::5")));
|
||||
Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::100"),
|
||||
IOAddress("2001:db8:1::100")));
|
||||
Pool6Ptr pool3(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::105"),
|
||||
IOAddress("2001:db8:1::106")));
|
||||
// Set pool1 and pool3 but not pool2 in foo class
|
||||
pool1->allowClientClass("foo");
|
||||
pool3->allowClientClass("foo");
|
||||
subnet_->addPool(pool1);
|
||||
subnet_->addPool(pool2);
|
||||
subnet_->addPool(pool3);
|
||||
|
||||
// Clients are in foo
|
||||
cc_.insert("foo");
|
||||
|
||||
// Let's check the first pool (5 addresses here)
|
||||
EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::3", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::4", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::5", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// The second pool is easy - only one address here
|
||||
EXPECT_EQ("2001:db8:1::100", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// This is the third and last pool, with 2 addresses in it
|
||||
EXPECT_EQ("2001:db8:1::105", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::106", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// We iterated over all addresses and reached to the end of the last pool.
|
||||
// Let's wrap around and start from the beginning
|
||||
EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
}
|
||||
|
||||
TEST_F(AllocEngine6Test, IterativeAllocatorAddrStepOutClass) {
|
||||
NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_NA);
|
||||
|
||||
subnet_->delPools(Lease::TYPE_NA); // Get rid of default pool
|
||||
|
||||
Pool6Ptr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"),
|
||||
IOAddress("2001:db8:1::5")));
|
||||
Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::100"),
|
||||
IOAddress("2001:db8:1::100")));
|
||||
Pool6Ptr pool3(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::105"),
|
||||
IOAddress("2001:db8:1::106")));
|
||||
// Set pool2 in foo
|
||||
pool2->allowClientClass("foo");
|
||||
subnet_->addPool(pool1);
|
||||
subnet_->addPool(pool2);
|
||||
subnet_->addPool(pool3);
|
||||
|
||||
// Let's check the first pool (5 addresses here)
|
||||
EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::3", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::4", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::5", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// The second pool is skipped
|
||||
|
||||
// This is the third and last pool, with 2 addresses in it
|
||||
EXPECT_EQ("2001:db8:1::105", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::106", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// We iterated over all addresses and reached to the end of the last pool.
|
||||
// Let's wrap around and start from the beginning
|
||||
EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
}
|
||||
|
||||
TEST_F(AllocEngine6Test, IterativeAllocatorPrefixStep) {
|
||||
@ -247,41 +347,158 @@ TEST_F(AllocEngine6Test, IterativeAllocatorPrefixStep) {
|
||||
// 2001:db8:2::/56 split into /64 prefixes (256 leases) (or 2001:db8:2:XX::)
|
||||
|
||||
// First pool check (Let's check over all 16 leases)
|
||||
EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:20::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:30::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:40::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:50::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:60::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:70::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:80::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:90::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:a0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:b0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:c0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:d0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:e0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:f0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:20::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:30::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:40::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:50::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:60::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:70::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:80::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:90::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:a0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:b0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:c0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:d0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:e0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:f0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// Second pool (just one lease here)
|
||||
EXPECT_EQ("2001:db8:1::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:1::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// Third pool (256 leases, let's check first and last explicitly and the
|
||||
// rest over in a pool
|
||||
EXPECT_EQ("2001:db8:2::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:2::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
for (int i = 1; i < 255; i++) {
|
||||
stringstream exp;
|
||||
exp << "2001:db8:2:" << hex << i << dec << "::";
|
||||
EXPECT_EQ(exp.str(), alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ(exp.str(), alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
}
|
||||
EXPECT_EQ("2001:db8:2:ff::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:2:ff::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// Ok, we've iterated over all prefixes in all pools. We now wrap around.
|
||||
// We're looping over now (iterating over first pool again)
|
||||
EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
}
|
||||
|
||||
TEST_F(AllocEngine6Test, IterativeAllocatorPrefixStepInClass) {
|
||||
NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_PD);
|
||||
|
||||
subnet_.reset(new Subnet6(IOAddress("2001:db8::"), 32, 1, 2, 3, 4));
|
||||
|
||||
Pool6Ptr pool1(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 56, 60));
|
||||
Pool6Ptr pool2(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:1::"), 48, 48));
|
||||
Pool6Ptr pool3(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:2::"), 56, 64));
|
||||
// Set pool1 and pool3 but not pool2 in foo class
|
||||
pool1->allowClientClass("foo");
|
||||
pool3->allowClientClass("foo");
|
||||
subnet_->addPool(pool1);
|
||||
subnet_->addPool(pool2);
|
||||
subnet_->addPool(pool3);
|
||||
|
||||
// Clients are in foo
|
||||
cc_.insert("foo");
|
||||
|
||||
// We have a 2001:db8::/48 subnet that has 3 pools defined in it:
|
||||
// 2001:db8::/56 split into /60 prefixes (16 leases) (or 2001:db8:0:X0::)
|
||||
// 2001:db8:1::/48 split into a single /48 prefix (just 1 lease)
|
||||
// 2001:db8:2::/56 split into /64 prefixes (256 leases) (or 2001:db8:2:XX::)
|
||||
|
||||
// First pool check (Let's check over all 16 leases)
|
||||
EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:20::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:30::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:40::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:50::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:60::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:70::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:80::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:90::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:a0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:b0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:c0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:d0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:e0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:f0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// Second pool (just one lease here)
|
||||
EXPECT_EQ("2001:db8:1::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// Third pool (256 leases, let's check first and last explicitly and the
|
||||
// rest over in a pool
|
||||
EXPECT_EQ("2001:db8:2::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
for (int i = 1; i < 255; i++) {
|
||||
stringstream exp;
|
||||
exp << "2001:db8:2:" << hex << i << dec << "::";
|
||||
EXPECT_EQ(exp.str(), alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
}
|
||||
EXPECT_EQ("2001:db8:2:ff::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// Ok, we've iterated over all prefixes in all pools. We now wrap around.
|
||||
// We're looping over now (iterating over first pool again)
|
||||
EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
}
|
||||
|
||||
TEST_F(AllocEngine6Test, IterativeAllocatorPrefixStepOutClass) {
|
||||
NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_PD);
|
||||
|
||||
subnet_.reset(new Subnet6(IOAddress("2001:db8::"), 32, 1, 2, 3, 4));
|
||||
|
||||
Pool6Ptr pool1(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 56, 60));
|
||||
Pool6Ptr pool2(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:1::"), 48, 48));
|
||||
Pool6Ptr pool3(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:2::"), 56, 64));
|
||||
// Set pool2 in foo
|
||||
pool2->allowClientClass("foo");
|
||||
subnet_->addPool(pool1);
|
||||
subnet_->addPool(pool2);
|
||||
subnet_->addPool(pool3);
|
||||
|
||||
// We have a 2001:db8::/48 subnet that has 3 pools defined in it:
|
||||
// 2001:db8::/56 split into /60 prefixes (16 leases) (or 2001:db8:0:X0::)
|
||||
// 2001:db8:1::/48 split into a single /48 prefix (just 1 lease)
|
||||
// 2001:db8:2::/56 split into /64 prefixes (256 leases) (or 2001:db8:2:XX::)
|
||||
|
||||
// First pool check (Let's check over all 16 leases)
|
||||
EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:20::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:30::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:40::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:50::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:60::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:70::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:80::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:90::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:a0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:b0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:c0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:d0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:e0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:f0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// The second pool is skipped
|
||||
|
||||
// Third pool (256 leases, let's check first and last explicitly and the
|
||||
// rest over in a pool
|
||||
EXPECT_EQ("2001:db8:2::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
for (int i = 1; i < 255; i++) {
|
||||
stringstream exp;
|
||||
exp << "2001:db8:2:" << hex << i << dec << "::";
|
||||
EXPECT_EQ(exp.str(), alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
}
|
||||
EXPECT_EQ("2001:db8:2:ff::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
|
||||
// Ok, we've iterated over all prefixes in all pools. We now wrap around.
|
||||
// We're looping over now (iterating over first pool again)
|
||||
EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
|
||||
}
|
||||
|
||||
// This test verifies that the iterative allocator can step over addresses
|
||||
@ -289,7 +506,7 @@ TEST_F(AllocEngine6Test, IterativeAllocatorAddressIncrease) {
|
||||
NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_NA);
|
||||
|
||||
// Let's pick the first address
|
||||
IOAddress addr1 = alloc.pickAddress(subnet_, duid_, IOAddress("2001:db8:1::10"));
|
||||
IOAddress addr1 = alloc.pickAddress(subnet_, cc_, duid_, IOAddress("2001:db8:1::10"));
|
||||
|
||||
// Check that we can indeed pick the first address from the pool
|
||||
EXPECT_EQ("2001:db8:1::10", addr1.toText());
|
||||
@ -379,7 +596,7 @@ TEST_F(AllocEngine6Test, IterativeAllocator_manyPools6) {
|
||||
std::set<IOAddress> generated_addrs;
|
||||
int cnt = 0;
|
||||
while (++cnt) {
|
||||
IOAddress candidate = alloc.pickAddress(subnet_, duid_, IOAddress("::"));
|
||||
IOAddress candidate = alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::"));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
|
||||
|
||||
// One way to easily verify that the iterative allocator really works is
|
||||
@ -2185,6 +2402,58 @@ TEST_F(SharedNetworkAlloc6Test, solicitSharedNetworkClassification) {
|
||||
EXPECT_EQ("2001:db8:1::1", lease->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 requires another class.
|
||||
TEST_F(SharedNetworkAlloc6Test, solicitSharedNetworkPoolClassification) {
|
||||
// Try to offer address from subnet1. There is an address available so
|
||||
// it should be offerred.
|
||||
Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
AllocEngine::ClientContext6 ctx(subnet1_, duid_, false, false, "", true,
|
||||
query);
|
||||
ctx.currentIA().iaid_ = iaid_;
|
||||
|
||||
Lease6Ptr lease;
|
||||
ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx)));
|
||||
ASSERT_TRUE(lease);
|
||||
ASSERT_TRUE(subnet1_->inRange(lease->addr_));
|
||||
|
||||
// Apply restrictions on the pool1. This should be only assigned
|
||||
// to clients belonging to cable-modem class.
|
||||
pool1_->allowClientClass("cable-modem");
|
||||
|
||||
// The allocation engine should determine that the pool1 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.
|
||||
AllocEngine::ClientContext6 ctx2(subnet1_, duid_, false, false, "", true,
|
||||
query);
|
||||
ctx2.currentIA().iaid_ = iaid_;
|
||||
ctx2.query_ = query;
|
||||
ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx2)));
|
||||
ASSERT_TRUE(lease);
|
||||
ASSERT_TRUE(subnet2_->inRange(lease->addr_));
|
||||
|
||||
AllocEngine::ClientContext6 ctx3(subnet1_, duid_, false, false, "", true,
|
||||
query);
|
||||
ctx3.currentIA().iaid_ = iaid_;
|
||||
ctx3.query_ = query;
|
||||
|
||||
AllocEngine::ClientContext6 ctx4(subnet1_, duid_, false, false, "", true,
|
||||
query);
|
||||
ctx4.currentIA().iaid_ = iaid_;
|
||||
ctx4.query_ = query;
|
||||
|
||||
// Assign cable-modem class and try again. This time, we should
|
||||
// offer an address from the pool1_.
|
||||
ctx4.query_->addClass(ClientClass("cable-modem"));
|
||||
|
||||
AllocEngine::findReservation(ctx4);
|
||||
ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx4)));
|
||||
ASSERT_TRUE(lease);
|
||||
EXPECT_EQ("2001:db8:1::1", lease->addr_.toText());
|
||||
}
|
||||
|
||||
// This test verifies that the client is offerred a reserved address
|
||||
// even if this address belongs to another subnet within the same
|
||||
// shared network.
|
||||
|
@ -74,6 +74,7 @@ public:
|
||||
:IterativeAllocator(type) {
|
||||
}
|
||||
|
||||
using AllocEngine::IterativeAllocator::increaseAddress;
|
||||
using AllocEngine::IterativeAllocator::increasePrefix;
|
||||
};
|
||||
};
|
||||
@ -221,10 +222,10 @@ public:
|
||||
/// @param input address to be increased
|
||||
/// @param exp_output expected address after increase
|
||||
void
|
||||
checkAddrIncrease(NakedAllocEngine::NakedIterativeAllocator&,
|
||||
checkAddrIncrease(NakedAllocEngine::NakedIterativeAllocator& alloc,
|
||||
std::string input, std::string exp_output) {
|
||||
EXPECT_EQ(exp_output, asiolink::IOAddress::increase(
|
||||
asiolink::IOAddress(input)).toText());
|
||||
EXPECT_EQ(exp_output, alloc.increaseAddress(asiolink::IOAddress(input),
|
||||
false, 0).toText());
|
||||
}
|
||||
|
||||
/// @brief Checks if increasePrefix() works as expected
|
||||
@ -409,6 +410,7 @@ public:
|
||||
bool fqdn_fwd_; ///< Perform forward update for a lease.
|
||||
bool fqdn_rev_; ///< Perform reverse update for a lease.
|
||||
LeaseMgrFactory factory_; ///< pointer to LeaseMgr factory
|
||||
ClientClasses cc_; ///< client classes
|
||||
};
|
||||
|
||||
/// @brief Used in Allocation Engine tests for IPv4
|
||||
@ -510,6 +512,7 @@ public:
|
||||
Pool4Ptr pool_; ///< Pool belonging to subnet_
|
||||
LeaseMgrFactory factory_; ///< Pointer to LeaseMgr factory
|
||||
AllocEngine::ClientContext4 ctx_; ///< Context information passed to various
|
||||
ClientClasses cc_; ///< Client classes
|
||||
///< allocation engine functions.
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -819,6 +819,7 @@ TEST(CfgSubnets4Test, unparsePool) {
|
||||
Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3, 123));
|
||||
Pool4Ptr pool1(new Pool4(IOAddress("192.0.2.1"), IOAddress("192.0.2.10")));
|
||||
Pool4Ptr pool2(new Pool4(IOAddress("192.0.2.64"), 26));
|
||||
pool2->allowClientClass("bar");
|
||||
|
||||
std::string json1 = "{ \"comment\": \"foo\", \"version\": 1 }";
|
||||
data::ElementPtr ctx1 = data::Element::fromJSON(json1);
|
||||
@ -857,6 +858,7 @@ TEST(CfgSubnets4Test, unparsePool) {
|
||||
" },{\n"
|
||||
" \"option-data\": [ ],\n"
|
||||
" \"pool\": \"192.0.2.64/26\"\n,"
|
||||
" \"client-class\": \"bar\",\n"
|
||||
" \"user-context\": { \"foo\": \"bar\" }\n"
|
||||
" }\n"
|
||||
" ]\n"
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -510,6 +510,7 @@ TEST(CfgSubnets6Test, unparsePool) {
|
||||
IOAddress("2001:db8:1::100"),
|
||||
IOAddress("2001:db8:1::199")));
|
||||
Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:1::"), 64));
|
||||
pool2->allowClientClass("bar");
|
||||
|
||||
std::string json1 = "{ \"comment\": \"foo\", \"version\": 1 }";
|
||||
data::ElementPtr ctx1 = data::Element::fromJSON(json1);
|
||||
@ -541,6 +542,7 @@ TEST(CfgSubnets6Test, unparsePool) {
|
||||
" \"option-data\": [ ]\n"
|
||||
" },{\n"
|
||||
" \"pool\": \"2001:db8:1:1::/64\",\n"
|
||||
" \"client-class\": \"bar\",\n"
|
||||
" \"user-context\": { \"foo\": \"bar\" },\n"
|
||||
" \"option-data\": [ ]\n"
|
||||
" }\n"
|
||||
@ -563,6 +565,7 @@ TEST(CfgSubnets6Test, unparsePdPool) {
|
||||
IOAddress("2001:db8:2::"), 48, 64));
|
||||
Pool6Ptr pdpool2(new Pool6(IOAddress("2001:db8:3::"), 48, 56,
|
||||
IOAddress("2001:db8:3::"), 64));
|
||||
pdpool2->allowClientClass("bar");
|
||||
|
||||
data::ElementPtr ctx1 = data::Element::fromJSON("{ \"foo\": [ \"bar\" ] }");
|
||||
pdpool1->setContext(ctx1);
|
||||
@ -597,7 +600,8 @@ TEST(CfgSubnets6Test, unparsePdPool) {
|
||||
" \"delegated-len\": 56,\n"
|
||||
" \"excluded-prefix\": \"2001:db8:3::\",\n"
|
||||
" \"excluded-prefix-len\": 64,\n"
|
||||
" \"option-data\": [ ]\n"
|
||||
" \"option-data\": [ ],\n"
|
||||
" \"client-class\": \"bar\"\n"
|
||||
" }\n"
|
||||
" ],\n"
|
||||
" \"option-data\": [ ]\n"
|
||||
|
@ -190,6 +190,106 @@ TEST(Pool4Test, userContext) {
|
||||
EXPECT_EQ(ctx->str(), pool->getContext()->str());
|
||||
}
|
||||
|
||||
// This test checks that handling for client-class is valid.
|
||||
TEST(Pool4Test, clientClass) {
|
||||
// Create a pool.
|
||||
Pool4Ptr pool(new Pool4(IOAddress("192.0.2.0"),
|
||||
IOAddress("192.0.2.255")));
|
||||
|
||||
// This client does not belong to any class.
|
||||
isc::dhcp::ClientClasses no_class;
|
||||
|
||||
// This client belongs to foo only.
|
||||
isc::dhcp::ClientClasses foo_class;
|
||||
foo_class.insert("foo");
|
||||
|
||||
// This client belongs to bar only. I like that client.
|
||||
isc::dhcp::ClientClasses bar_class;
|
||||
bar_class.insert("bar");
|
||||
|
||||
// This client belongs to foo, bar and baz classes.
|
||||
isc::dhcp::ClientClasses three_classes;
|
||||
three_classes.insert("foo");
|
||||
three_classes.insert("bar");
|
||||
three_classes.insert("baz");
|
||||
|
||||
// No class restrictions defined, any client should be supported
|
||||
EXPECT_EQ(0, pool->getClientClasses().size());
|
||||
EXPECT_TRUE(pool->clientSupported(no_class));
|
||||
EXPECT_TRUE(pool->clientSupported(foo_class));
|
||||
EXPECT_TRUE(pool->clientSupported(bar_class));
|
||||
EXPECT_TRUE(pool->clientSupported(three_classes));
|
||||
|
||||
// Let's allow only clients belonging to "bar" class.
|
||||
pool->allowClientClass("bar");
|
||||
EXPECT_EQ(1, pool->getClientClasses().size());
|
||||
|
||||
EXPECT_FALSE(pool->clientSupported(no_class));
|
||||
EXPECT_FALSE(pool->clientSupported(foo_class));
|
||||
EXPECT_TRUE(pool->clientSupported(bar_class));
|
||||
EXPECT_TRUE(pool->clientSupported(three_classes));
|
||||
}
|
||||
|
||||
// This test checks that handling for multiple client-classes is valid.
|
||||
TEST(Pool4Test, clientClasses) {
|
||||
// Create a pool.
|
||||
Pool4Ptr pool(new Pool4(IOAddress("192.0.2.0"),
|
||||
IOAddress("192.0.2.255")));
|
||||
|
||||
// This client does not belong to any class.
|
||||
isc::dhcp::ClientClasses no_class;
|
||||
|
||||
// This client belongs to foo only.
|
||||
isc::dhcp::ClientClasses foo_class;
|
||||
foo_class.insert("foo");
|
||||
|
||||
// This client belongs to bar only. I like that client.
|
||||
isc::dhcp::ClientClasses bar_class;
|
||||
bar_class.insert("bar");
|
||||
|
||||
// No class restrictions defined, any client should be supported
|
||||
EXPECT_EQ(0, pool->getClientClasses().size());
|
||||
EXPECT_TRUE(pool->clientSupported(no_class));
|
||||
EXPECT_TRUE(pool->clientSupported(foo_class));
|
||||
EXPECT_TRUE(pool->clientSupported(bar_class));
|
||||
|
||||
// Let's allow clients belonging to "bar" or "foo" class.
|
||||
pool->allowClientClass("bar");
|
||||
pool->allowClientClass("foo");
|
||||
EXPECT_EQ(2, pool->getClientClasses().size());
|
||||
|
||||
// Class-less clients are to be rejected.
|
||||
EXPECT_FALSE(pool->clientSupported(no_class));
|
||||
|
||||
// Clients in foo class should be accepted.
|
||||
EXPECT_TRUE(pool->clientSupported(foo_class));
|
||||
|
||||
// Clients in bar class should be accepted as well.
|
||||
EXPECT_TRUE(pool->clientSupported(bar_class));
|
||||
}
|
||||
|
||||
// This test checks that handling for last allocated address/prefix is valid.
|
||||
TEST(Pool4Test, lastAllocated) {
|
||||
// Create a pool.
|
||||
IOAddress first("192.0.2.0");
|
||||
Pool4Ptr pool(new Pool4(first, IOAddress("192.0.2.255")));
|
||||
|
||||
// Initial values are first invalid.
|
||||
EXPECT_EQ(first.toText(), pool->getLastAllocated().toText());
|
||||
EXPECT_FALSE(pool->isLastAllocatedValid());
|
||||
|
||||
// Now set last allocated
|
||||
IOAddress addr("192.0.2.100");
|
||||
EXPECT_NO_THROW(pool->setLastAllocated(addr));
|
||||
EXPECT_EQ(addr.toText(), pool->getLastAllocated().toText());
|
||||
EXPECT_TRUE(pool->isLastAllocatedValid());
|
||||
|
||||
// Reset makes it invalid and does not touch address
|
||||
pool->resetLastAllocated();
|
||||
EXPECT_EQ(addr.toText(), pool->getLastAllocated().toText());
|
||||
EXPECT_FALSE(pool->isLastAllocatedValid());
|
||||
}
|
||||
|
||||
TEST(Pool6Test, constructor_first_last) {
|
||||
|
||||
// let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool
|
||||
@ -494,4 +594,104 @@ TEST(Pool6Test, userContext) {
|
||||
EXPECT_EQ(ctx->str(), pool.getContext()->str());
|
||||
}
|
||||
|
||||
// This test checks that handling for client-class is valid.
|
||||
TEST(Pool6Test, clientClass) {
|
||||
// Create a pool.
|
||||
Pool6 pool(Lease::TYPE_NA, IOAddress("2001:db8::1"),
|
||||
IOAddress("2001:db8::2"));
|
||||
|
||||
// This client does not belong to any class.
|
||||
isc::dhcp::ClientClasses no_class;
|
||||
|
||||
// This client belongs to foo only.
|
||||
isc::dhcp::ClientClasses foo_class;
|
||||
foo_class.insert("foo");
|
||||
|
||||
// This client belongs to bar only. I like that client.
|
||||
isc::dhcp::ClientClasses bar_class;
|
||||
bar_class.insert("bar");
|
||||
|
||||
// This client belongs to foo, bar and baz classes.
|
||||
isc::dhcp::ClientClasses three_classes;
|
||||
three_classes.insert("foo");
|
||||
three_classes.insert("bar");
|
||||
three_classes.insert("baz");
|
||||
|
||||
// No class restrictions defined, any client should be supported
|
||||
EXPECT_EQ(0, pool.getClientClasses().size());
|
||||
EXPECT_TRUE(pool.clientSupported(no_class));
|
||||
EXPECT_TRUE(pool.clientSupported(foo_class));
|
||||
EXPECT_TRUE(pool.clientSupported(bar_class));
|
||||
EXPECT_TRUE(pool.clientSupported(three_classes));
|
||||
|
||||
// Let's allow only clients belonging to "bar" class.
|
||||
pool.allowClientClass("bar");
|
||||
EXPECT_EQ(1, pool.getClientClasses().size());
|
||||
|
||||
EXPECT_FALSE(pool.clientSupported(no_class));
|
||||
EXPECT_FALSE(pool.clientSupported(foo_class));
|
||||
EXPECT_TRUE(pool.clientSupported(bar_class));
|
||||
EXPECT_TRUE(pool.clientSupported(three_classes));
|
||||
}
|
||||
|
||||
// This test checks that handling for multiple client-classes is valid.
|
||||
TEST(Pool6Test, clientClasses) {
|
||||
// Create a pool.
|
||||
Pool6 pool(Lease::TYPE_NA, IOAddress("2001:db8::1"),
|
||||
IOAddress("2001:db8::2"));
|
||||
|
||||
// This client does not belong to any class.
|
||||
isc::dhcp::ClientClasses no_class;
|
||||
|
||||
// This client belongs to foo only.
|
||||
isc::dhcp::ClientClasses foo_class;
|
||||
foo_class.insert("foo");
|
||||
|
||||
// This client belongs to bar only. I like that client.
|
||||
isc::dhcp::ClientClasses bar_class;
|
||||
bar_class.insert("bar");
|
||||
|
||||
// No class restrictions defined, any client should be supported
|
||||
EXPECT_EQ(0, pool.getClientClasses().size());
|
||||
EXPECT_TRUE(pool.clientSupported(no_class));
|
||||
EXPECT_TRUE(pool.clientSupported(foo_class));
|
||||
EXPECT_TRUE(pool.clientSupported(bar_class));
|
||||
|
||||
// Let's allow clients belonging to "bar" or "foo" class.
|
||||
pool.allowClientClass("bar");
|
||||
pool.allowClientClass("foo");
|
||||
EXPECT_EQ(2, pool.getClientClasses().size());
|
||||
|
||||
// Class-less clients are to be rejected.
|
||||
EXPECT_FALSE(pool.clientSupported(no_class));
|
||||
|
||||
// Clients in foo class should be accepted.
|
||||
EXPECT_TRUE(pool.clientSupported(foo_class));
|
||||
|
||||
// Clients in bar class should be accepted as well.
|
||||
EXPECT_TRUE(pool.clientSupported(bar_class));
|
||||
}
|
||||
|
||||
// This test checks that handling for last allocated address/prefix is valid.
|
||||
TEST(Pool6Test, lastAllocated) {
|
||||
// Create a pool.
|
||||
IOAddress first("2001:db8::1");
|
||||
Pool6 pool(Lease::TYPE_NA, first, IOAddress("2001:db8::200"));
|
||||
|
||||
// Initial values are first invalid.
|
||||
EXPECT_EQ(first.toText(), pool.getLastAllocated().toText());
|
||||
EXPECT_FALSE(pool.isLastAllocatedValid());
|
||||
|
||||
// Now set last allocated
|
||||
IOAddress addr("2001:db8::100");
|
||||
EXPECT_NO_THROW(pool.setLastAllocated(addr));
|
||||
EXPECT_EQ(addr.toText(), pool.getLastAllocated().toText());
|
||||
EXPECT_TRUE(pool.isLastAllocatedValid());
|
||||
|
||||
// Reset makes it invalid and does not touch address
|
||||
pool.resetLastAllocated();
|
||||
EXPECT_EQ(addr.toText(), pool.getLastAllocated().toText());
|
||||
EXPECT_FALSE(pool.isLastAllocatedValid());
|
||||
}
|
||||
|
||||
}; // end of anonymous namespace
|
||||
|
@ -168,15 +168,18 @@ TEST(Subnet4Test, pool4InSubnet4) {
|
||||
PoolPtr pool1(new Pool4(IOAddress("192.1.2.0"), 25));
|
||||
PoolPtr pool2(new Pool4(IOAddress("192.1.2.128"), 26));
|
||||
PoolPtr pool3(new Pool4(IOAddress("192.1.2.192"), 30));
|
||||
pool3->allowClientClass("bar");
|
||||
PoolPtr pool4(new Pool4(IOAddress("192.1.2.200"), 30));
|
||||
|
||||
// Add pools in reverse order to make sure that they get ordered by
|
||||
// first address.
|
||||
EXPECT_NO_THROW(subnet->addPool(pool3));
|
||||
EXPECT_NO_THROW(subnet->addPool(pool4));
|
||||
|
||||
// If there's only one pool, get that pool
|
||||
PoolPtr mypool = subnet->getAnyPool(Lease::TYPE_V4);
|
||||
EXPECT_EQ(mypool, pool3);
|
||||
EXPECT_EQ(mypool, pool4);
|
||||
|
||||
EXPECT_NO_THROW(subnet->addPool(pool3));
|
||||
EXPECT_NO_THROW(subnet->addPool(pool2));
|
||||
EXPECT_NO_THROW(subnet->addPool(pool1));
|
||||
|
||||
@ -188,8 +191,8 @@ TEST(Subnet4Test, pool4InSubnet4) {
|
||||
|
||||
// If we provide a hint, we should get a pool that this hint belongs to
|
||||
ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4,
|
||||
IOAddress("192.1.2.195")));
|
||||
EXPECT_EQ(mypool, pool3);
|
||||
IOAddress("192.1.2.201")));
|
||||
EXPECT_EQ(mypool, pool4);
|
||||
|
||||
ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4,
|
||||
IOAddress("192.1.2.129")));
|
||||
@ -203,7 +206,7 @@ TEST(Subnet4Test, pool4InSubnet4) {
|
||||
// third parameter prevents it from returning "any" available
|
||||
// pool if a good match is not found.
|
||||
ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4,
|
||||
IOAddress("192.1.2.200"),
|
||||
IOAddress("192.1.2.210"),
|
||||
false));
|
||||
EXPECT_FALSE(mypool);
|
||||
|
||||
@ -211,6 +214,57 @@ TEST(Subnet4Test, pool4InSubnet4) {
|
||||
IOAddress("192.1.1.254"),
|
||||
false));
|
||||
EXPECT_FALSE(mypool);
|
||||
|
||||
// Now play with classes
|
||||
|
||||
// This client does not belong to any class.
|
||||
isc::dhcp::ClientClasses no_class;
|
||||
|
||||
// This client belongs to foo only.
|
||||
isc::dhcp::ClientClasses foo_class;
|
||||
foo_class.insert("foo");
|
||||
|
||||
// This client belongs to bar only. I like that client.
|
||||
isc::dhcp::ClientClasses bar_class;
|
||||
bar_class.insert("bar");
|
||||
|
||||
// This client belongs to foo, bar and baz classes.
|
||||
isc::dhcp::ClientClasses three_classes;
|
||||
three_classes.insert("foo");
|
||||
three_classes.insert("bar");
|
||||
three_classes.insert("baz");
|
||||
|
||||
// If we provide a hint, we should get a pool that this hint belongs to
|
||||
ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4, no_class,
|
||||
IOAddress("192.1.2.201")));
|
||||
EXPECT_EQ(mypool, pool4);
|
||||
|
||||
ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4, no_class,
|
||||
IOAddress("192.1.2.129")));
|
||||
EXPECT_EQ(mypool, pool2);
|
||||
|
||||
ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4, no_class,
|
||||
IOAddress("192.1.2.64")));
|
||||
EXPECT_EQ(mypool, pool1);
|
||||
|
||||
// Specify addresses which don't belong to any existing pools.
|
||||
ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4, three_classes,
|
||||
IOAddress("192.1.2.210")));
|
||||
EXPECT_FALSE(mypool);
|
||||
|
||||
// Pool3 requires a member of bar
|
||||
ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4, no_class,
|
||||
IOAddress("192.1.2.195")));
|
||||
EXPECT_FALSE(mypool);
|
||||
ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4, foo_class,
|
||||
IOAddress("192.1.2.195")));
|
||||
EXPECT_FALSE(mypool);
|
||||
ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4, bar_class,
|
||||
IOAddress("192.1.2.195")));
|
||||
EXPECT_EQ(mypool, pool3);
|
||||
ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4, three_classes,
|
||||
IOAddress("192.1.2.195")));
|
||||
EXPECT_EQ(mypool, pool3);
|
||||
}
|
||||
|
||||
// Check if it's possible to get specified number of possible leases for
|
||||
@ -237,6 +291,38 @@ TEST(Subnet4Test, getCapacity) {
|
||||
PoolPtr pool3(new Pool4(IOAddress("192.1.2.192"), 30));
|
||||
subnet->addPool(pool3);
|
||||
EXPECT_EQ(196, subnet->getPoolCapacity(Lease::TYPE_V4));
|
||||
|
||||
// Let's add a forth pool /30. This one has 4 addresses.
|
||||
PoolPtr pool4(new Pool4(IOAddress("192.1.2.200"), 30));
|
||||
subnet->addPool(pool4);
|
||||
EXPECT_EQ(200, subnet->getPoolCapacity(Lease::TYPE_V4));
|
||||
|
||||
// Now play with classes
|
||||
|
||||
// This client does not belong to any class.
|
||||
isc::dhcp::ClientClasses no_class;
|
||||
|
||||
// This client belongs to foo only.
|
||||
isc::dhcp::ClientClasses foo_class;
|
||||
foo_class.insert("foo");
|
||||
|
||||
// This client belongs to bar only. I like that client.
|
||||
isc::dhcp::ClientClasses bar_class;
|
||||
bar_class.insert("bar");
|
||||
|
||||
// This client belongs to foo, bar and baz classes.
|
||||
isc::dhcp::ClientClasses three_classes;
|
||||
three_classes.insert("foo");
|
||||
three_classes.insert("bar");
|
||||
three_classes.insert("baz");
|
||||
|
||||
pool3->allowClientClass("bar");
|
||||
|
||||
// Pool3 requires a member of bar
|
||||
EXPECT_EQ(196, subnet->getPoolCapacity(Lease::TYPE_V4, no_class));
|
||||
EXPECT_EQ(196, subnet->getPoolCapacity(Lease::TYPE_V4, foo_class));
|
||||
EXPECT_EQ(200, subnet->getPoolCapacity(Lease::TYPE_V4, bar_class));
|
||||
EXPECT_EQ(200, subnet->getPoolCapacity(Lease::TYPE_V4, three_classes));
|
||||
}
|
||||
|
||||
// Checks that it is not allowed to add invalid pools.
|
||||
@ -435,19 +521,44 @@ TEST(Subnet4Test, inRangeinPool) {
|
||||
|
||||
// the first address that is in range, in pool
|
||||
EXPECT_TRUE(subnet->inRange(IOAddress("192.2.0.0")));
|
||||
EXPECT_TRUE (subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.0.0")));
|
||||
EXPECT_TRUE(subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.0.0")));
|
||||
|
||||
// let's try something in the middle as well
|
||||
EXPECT_TRUE(subnet->inRange(IOAddress("192.2.3.4")));
|
||||
EXPECT_TRUE (subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.3.4")));
|
||||
EXPECT_TRUE(subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.3.4")));
|
||||
|
||||
// the last address that is in range, in pool
|
||||
EXPECT_TRUE(subnet->inRange(IOAddress("192.2.255.255")));
|
||||
EXPECT_TRUE (subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.255.255")));
|
||||
EXPECT_TRUE(subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.255.255")));
|
||||
|
||||
// the first address that is in range, but out of pool
|
||||
EXPECT_TRUE(subnet->inRange(IOAddress("192.3.0.0")));
|
||||
EXPECT_FALSE(subnet->inPool(Lease::TYPE_V4, IOAddress("192.3.0.0")));
|
||||
|
||||
// Add with classes
|
||||
pool1->allowClientClass("bar");
|
||||
EXPECT_TRUE(subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.3.4")));
|
||||
|
||||
// This client does not belong to any class.
|
||||
isc::dhcp::ClientClasses no_class;
|
||||
EXPECT_FALSE(subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.3.4"), no_class));
|
||||
|
||||
// This client belongs to foo only
|
||||
isc::dhcp::ClientClasses foo_class;
|
||||
foo_class.insert("foo");
|
||||
EXPECT_FALSE(subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.3.4"), foo_class));
|
||||
|
||||
// This client belongs to bar only. I like that client.
|
||||
isc::dhcp::ClientClasses bar_class;
|
||||
bar_class.insert("bar");
|
||||
EXPECT_TRUE(subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.3.4"), bar_class));
|
||||
|
||||
// This client belongs to foo, bar and baz classes.
|
||||
isc::dhcp::ClientClasses three_classes;
|
||||
three_classes.insert("foo");
|
||||
three_classes.insert("bar");
|
||||
three_classes.insert("baz");
|
||||
EXPECT_TRUE(subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.3.4"), three_classes));
|
||||
}
|
||||
|
||||
// This test checks if the toText() method returns text representation
|
||||
@ -647,6 +758,37 @@ TEST(Subnet6Test, Pool6getCapacity) {
|
||||
EXPECT_EQ(uint64_t(4294967296ull + 4294967296ull + 65536),
|
||||
subnet->getPoolCapacity(Lease::TYPE_NA));
|
||||
|
||||
// Now play with classes
|
||||
|
||||
// This client does not belong to any class.
|
||||
isc::dhcp::ClientClasses no_class;
|
||||
|
||||
// This client belongs to foo only.
|
||||
isc::dhcp::ClientClasses foo_class;
|
||||
foo_class.insert("foo");
|
||||
|
||||
// This client belongs to bar only. I like that client.
|
||||
isc::dhcp::ClientClasses bar_class;
|
||||
bar_class.insert("bar");
|
||||
|
||||
// This client belongs to foo, bar and baz classes.
|
||||
isc::dhcp::ClientClasses three_classes;
|
||||
three_classes.insert("foo");
|
||||
three_classes.insert("bar");
|
||||
three_classes.insert("baz");
|
||||
|
||||
pool3->allowClientClass("bar");
|
||||
|
||||
// Pool3 requires a member of bar
|
||||
EXPECT_EQ(uint64_t(4294967296ull + 65536),
|
||||
subnet->getPoolCapacity(Lease::TYPE_NA, no_class));
|
||||
EXPECT_EQ(uint64_t(4294967296ull + 65536),
|
||||
subnet->getPoolCapacity(Lease::TYPE_NA, foo_class));
|
||||
EXPECT_EQ(uint64_t(4294967296ull + 4294967296ull + 65536),
|
||||
subnet->getPoolCapacity(Lease::TYPE_NA, bar_class));
|
||||
EXPECT_EQ(uint64_t(4294967296ull + 4294967296ull + 65536),
|
||||
subnet->getPoolCapacity(Lease::TYPE_NA, three_classes));
|
||||
|
||||
// This is 2^64 prefixes. We're overflown uint64_t.
|
||||
PoolPtr pool4(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:4::"), 64));
|
||||
subnet->addPool(pool4);
|
||||
@ -657,6 +799,7 @@ TEST(Subnet6Test, Pool6getCapacity) {
|
||||
subnet->addPool(pool5);
|
||||
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
|
||||
subnet->getPoolCapacity(Lease::TYPE_NA));
|
||||
|
||||
}
|
||||
|
||||
// Test checks whether the number of prefixes available in the pools are
|
||||
@ -725,6 +868,41 @@ TEST(Subnet6Test, Pool6InSubnet6) {
|
||||
mypool = subnet->getPool(Lease::TYPE_NA, IOAddress("2001:db8:1:3::dead:beef"));
|
||||
|
||||
EXPECT_EQ(mypool, pool3);
|
||||
|
||||
// Now play with classes
|
||||
|
||||
// This client does not belong to any class.
|
||||
isc::dhcp::ClientClasses no_class;
|
||||
|
||||
// This client belongs to foo only.
|
||||
isc::dhcp::ClientClasses foo_class;
|
||||
foo_class.insert("foo");
|
||||
|
||||
// This client belongs to bar only. I like that client.
|
||||
isc::dhcp::ClientClasses bar_class;
|
||||
bar_class.insert("bar");
|
||||
|
||||
// This client belongs to foo, bar and baz classes.
|
||||
isc::dhcp::ClientClasses three_classes;
|
||||
three_classes.insert("foo");
|
||||
three_classes.insert("bar");
|
||||
three_classes.insert("baz");
|
||||
|
||||
pool3->allowClientClass("bar");
|
||||
|
||||
// Pool3 requires a member of bar
|
||||
mypool = subnet->getPool(Lease::TYPE_NA, no_class,
|
||||
IOAddress("2001:db8:1:3::dead:beef"));
|
||||
EXPECT_FALSE(mypool);
|
||||
mypool = subnet->getPool(Lease::TYPE_NA, foo_class,
|
||||
IOAddress("2001:db8:1:3::dead:beef"));
|
||||
EXPECT_FALSE(mypool);
|
||||
mypool = subnet->getPool(Lease::TYPE_NA, bar_class,
|
||||
IOAddress("2001:db8:1:3::dead:beef"));
|
||||
EXPECT_EQ(mypool, pool3);
|
||||
mypool = subnet->getPool(Lease::TYPE_NA, three_classes,
|
||||
IOAddress("2001:db8:1:3::dead:beef"));
|
||||
EXPECT_EQ(mypool, pool3);
|
||||
}
|
||||
|
||||
// Check if Subnet6 supports different types of pools properly.
|
||||
@ -1198,11 +1376,11 @@ TEST(Subnet6Test, inRangeinPool) {
|
||||
|
||||
// the first address that is in range, in pool
|
||||
EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::10")));
|
||||
EXPECT_TRUE (subnet->inPool(Lease::TYPE_NA, IOAddress("2001:db8::10")));
|
||||
EXPECT_TRUE(subnet->inPool(Lease::TYPE_NA, IOAddress("2001:db8::10")));
|
||||
|
||||
// let's try something in the middle as well
|
||||
EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::18")));
|
||||
EXPECT_TRUE (subnet->inPool(Lease::TYPE_NA, IOAddress("2001:db8::18")));
|
||||
EXPECT_TRUE(subnet->inPool(Lease::TYPE_NA, IOAddress("2001:db8::18")));
|
||||
|
||||
// the last address that is in range, in pool
|
||||
EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::20")));
|
||||
@ -1211,6 +1389,31 @@ TEST(Subnet6Test, inRangeinPool) {
|
||||
// the first address that is in range, but out of pool
|
||||
EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::21")));
|
||||
EXPECT_FALSE(subnet->inPool(Lease::TYPE_NA, IOAddress("2001:db8::21")));
|
||||
|
||||
// Add with classes
|
||||
pool1->allowClientClass("bar");
|
||||
EXPECT_TRUE(subnet->inPool(Lease::TYPE_NA, IOAddress("2001:db8::18")));
|
||||
|
||||
// This client does not belong to any class.
|
||||
isc::dhcp::ClientClasses no_class;
|
||||
EXPECT_FALSE(subnet->inPool(Lease::TYPE_NA, IOAddress("2001:db8::18"), no_class));
|
||||
|
||||
// This client belongs to foo only
|
||||
isc::dhcp::ClientClasses foo_class;
|
||||
foo_class.insert("foo");
|
||||
EXPECT_FALSE(subnet->inPool(Lease::TYPE_NA, IOAddress("2001:db8::18"), foo_class));
|
||||
|
||||
// This client belongs to bar only. I like that client.
|
||||
isc::dhcp::ClientClasses bar_class;
|
||||
bar_class.insert("bar");
|
||||
EXPECT_TRUE(subnet->inPool(Lease::TYPE_NA, IOAddress("2001:db8::18"), bar_class));
|
||||
|
||||
// This client belongs to foo, bar and baz classes.
|
||||
isc::dhcp::ClientClasses three_classes;
|
||||
three_classes.insert("foo");
|
||||
three_classes.insert("bar");
|
||||
three_classes.insert("baz");
|
||||
EXPECT_TRUE(subnet->inPool(Lease::TYPE_NA, IOAddress("2001:db8::18"), three_classes));
|
||||
}
|
||||
|
||||
// This test verifies that inRange() and inPool() methods work properly
|
||||
|
Loading…
x
Reference in New Issue
Block a user