2
0
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:
Francis Dupont 2018-01-29 18:37:53 +01:00
commit 3d6bb5b1d4
45 changed files with 5731 additions and 2882 deletions

View File

@ -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"
}
]
},

View File

@ -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"
}
]
},

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -1,4 +1,4 @@
// Generated 201712311009
// Generated 201801182315
// A Bison parser, made by GNU Bison 3.0.4.
// Locations for Bison parsers in C++

View File

@ -1,4 +1,4 @@
// Generated 201712311009
// Generated 201801182315
// A Bison parser, made by GNU Bison 3.0.4.
// Positions for Bison parsers in C++

View File

@ -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++

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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_);
}

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -1,4 +1,4 @@
// Generated 201712311009
// Generated 201801182315
// A Bison parser, made by GNU Bison 3.0.4.
// Locations for Bison parsers in C++

View File

@ -1,4 +1,4 @@
// Generated 201712311009
// Generated 201801182315
// A Bison parser, made by GNU Bison 3.0.4.
// Positions for Bison parsers in C++

View File

@ -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++

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)) {

View File

@ -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

View File

@ -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_);
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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).

View File

@ -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.

View File

@ -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.
};

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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