cfg_subnets4_unittest.cc 12.1 KB
Newer Older
1
// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
2
//
3
4
5
// 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7
8
9
10
11

#include <config.h>
#include <dhcp/classify.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcpsrv/cfg_subnets4.h>
#include <dhcpsrv/subnet.h>
12
#include <dhcpsrv/subnet_id.h>
13
#include <dhcpsrv/subnet_selector.h>
14
15
16
17
18
19
20
21
22
23
24
#include <gtest/gtest.h>

using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::dhcp::test;

namespace {

// This test verifies that it is possible to retrieve a subnet using an
// IP address.
25
TEST(CfgSubnets4Test, selectSubnetByCiaddr) {
26
27
28
29
30
31
32
33
    CfgSubnets4 cfg;

    // Create 3 subnets.
    Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
    Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
    Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));

    // Make sure that initially the subnets don't exist.
34
    SubnetSelector selector;
35
36
37
    selector.ciaddr_ = IOAddress("192.0.2.0");
    // Set some unicast local address to simulate a Renew.
    selector.local_address_ = IOAddress("10.0.0.100");
38
    ASSERT_FALSE(cfg.selectSubnet(selector));
39
40
41
42

    // Add one subnet and make sure it is returned.
    cfg.add(subnet1);
    selector.ciaddr_ = IOAddress("192.0.2.63");
43
    EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
44
45
46
47
48
49
50

    // Add all other subnets.
    cfg.add(subnet2);
    cfg.add(subnet3);

    // Make sure they are returned for the appropriate addresses.
    selector.ciaddr_ = IOAddress("192.0.2.15");
51
    EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
52
    selector.ciaddr_ = IOAddress("192.0.2.85");
53
    EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
54
    selector.ciaddr_ = IOAddress("192.0.2.191");
55
    EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
56
57
58
59

    // Also, make sure that the NULL pointer is returned if the subnet
    // cannot be found.
    selector.ciaddr_ = IOAddress("192.0.2.192");
60
    EXPECT_FALSE(cfg.selectSubnet(selector));
61
62
63
64
65
}


// This test verifies that when the classification information is specified for
// subnets, the proper subnets are returned by the subnet configuration.
66
TEST(CfgSubnets4Test, selectSubnetByClasses) {
67
68
69
70
71
72
73
74
75
76
77
78
    CfgSubnets4 cfg;

    // Create 3 subnets.
    Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
    Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
    Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));

    // Add them to the configuration.
    cfg.add(subnet1);
    cfg.add(subnet2);
    cfg.add(subnet3);

79
    SubnetSelector selector;
80
81
82
83

    selector.local_address_ = IOAddress("10.0.0.10");

    selector.ciaddr_ = IOAddress("192.0.2.5");
84
    EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
85
    selector.ciaddr_ = IOAddress("192.0.2.70");
86
    EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
87
    selector.ciaddr_ = IOAddress("192.0.2.130");
88
    EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
89
90
91
92
93
94
95
96

    ClientClasses client_classes;
    client_classes.insert("bar");
    selector.client_classes_ = client_classes;

    // There are no class restrictions defined, so everything should work
    // as before
    selector.ciaddr_ = IOAddress("192.0.2.5");
97
    EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
98
    selector.ciaddr_ = IOAddress("192.0.2.70");
99
    EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
100
    selector.ciaddr_ = IOAddress("192.0.2.130");
101
    EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
102
103
104
105
106
107
108
109
110

    // Now let's add client class restrictions.
    subnet1->allowClientClass("foo"); // Serve here only clients from foo class
    subnet2->allowClientClass("bar"); // Serve here only clients from bar class
    subnet3->allowClientClass("baz"); // Serve here only clients from baz class

    // The same check as above should result in client being served only in
    // bar class, i.e. subnet2.
    selector.ciaddr_ = IOAddress("192.0.2.5");
111
    EXPECT_FALSE(cfg.selectSubnet(selector));
112
    selector.ciaddr_ = IOAddress("192.0.2.70");
113
    EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
114
    selector.ciaddr_ = IOAddress("192.0.2.130");
115
    EXPECT_FALSE(cfg.selectSubnet(selector));
116
117
118
119
120
121

    // Now let's check that client with wrong class is not supported.
    client_classes.clear();
    client_classes.insert("some_other_class");
    selector.client_classes_ = client_classes;
    selector.ciaddr_ = IOAddress("192.0.2.5");
122
    EXPECT_FALSE(cfg.selectSubnet(selector));
123
    selector.ciaddr_ = IOAddress("192.0.2.70");
124
    EXPECT_FALSE(cfg.selectSubnet(selector));
125
    selector.ciaddr_ = IOAddress("192.0.2.130");
126
    EXPECT_FALSE(cfg.selectSubnet(selector));
127
128
129
130

    // Finally, let's check that client without any classes is not supported.
    client_classes.clear();
    selector.ciaddr_ = IOAddress("192.0.2.5");
131
    EXPECT_FALSE(cfg.selectSubnet(selector));
132
    selector.ciaddr_ = IOAddress("192.0.2.70");
133
    EXPECT_FALSE(cfg.selectSubnet(selector));
134
    selector.ciaddr_ = IOAddress("192.0.2.130");
135
    EXPECT_FALSE(cfg.selectSubnet(selector));
136
137
}

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// This test verifies the option selection can be used and is only
// used when present.
TEST(CfgSubnets4Test, selectSubnetByOptionSelect) {
    CfgSubnets4 cfg;

    // Create 3 subnets.
    Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
    Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
    Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));

    // Add them to the configuration.
    cfg.add(subnet1);
    cfg.add(subnet2);
    cfg.add(subnet3);

    SubnetSelector selector;

    // Check that without option selection something else is used
    selector.ciaddr_ = IOAddress("192.0.2.5");
    EXPECT_EQ(subnet1, cfg.selectSubnet(selector));

    // The option selection has precedence
    selector.option_select_ = IOAddress("192.0.2.130");
    EXPECT_EQ(subnet3, cfg.selectSubnet(selector));

    // Over relay-info too
    selector.giaddr_ = IOAddress("10.0.0.1");
    subnet2->setRelayInfo(IOAddress("10.0.0.1"));
    EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
    selector.option_select_ = IOAddress("0.0.0.0");
    EXPECT_EQ(subnet2, cfg.selectSubnet(selector));

    // Check that a not matching option selection it shall fail
    selector.option_select_ = IOAddress("10.0.0.1");
    EXPECT_FALSE(cfg.selectSubnet(selector));
}

175
176
// This test verifies that the relay information can be used to retrieve the
// subnet.
177
TEST(CfgSubnets4Test, selectSubnetByRelayAddress) {
178
179
180
181
182
183
184
185
186
187
188
189
    CfgSubnets4 cfg;

    // Create 3 subnets.
    Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
    Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
    Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));

    // Add them to the configuration.
    cfg.add(subnet1);
    cfg.add(subnet2);
    cfg.add(subnet3);

190
    SubnetSelector selector;
191
192
193

    // Check that without relay-info specified, subnets are not selected
    selector.giaddr_ = IOAddress("10.0.0.1");
194
    EXPECT_FALSE(cfg.selectSubnet(selector));
195
    selector.giaddr_ = IOAddress("10.0.0.2");
196
    EXPECT_FALSE(cfg.selectSubnet(selector));
197
    selector.giaddr_ = IOAddress("10.0.0.3");
198
    EXPECT_FALSE(cfg.selectSubnet(selector));
199
200
201
202
203
204
205
206

    // Now specify relay info
    subnet1->setRelayInfo(IOAddress("10.0.0.1"));
    subnet2->setRelayInfo(IOAddress("10.0.0.2"));
    subnet3->setRelayInfo(IOAddress("10.0.0.3"));

    // And try again. This time relay-info is there and should match.
    selector.giaddr_ = IOAddress("10.0.0.1");
207
    EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
208
    selector.giaddr_ = IOAddress("10.0.0.2");
209
    EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
210
    selector.giaddr_ = IOAddress("10.0.0.3");
211
    EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
212
213
214
215
}

// This test verifies that the subnet can be selected for the client
// using a source address if the client hasn't set the ciaddr.
216
TEST(CfgSubnets4Test, selectSubnetNoCiaddr) {
217
218
219
220
221
222
223
224
    CfgSubnets4 cfg;

    // Create 3 subnets.
    Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
    Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
    Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));

    // Make sure that initially the subnets don't exist.
225
    SubnetSelector selector;
226
227
228
    selector.remote_address_ = IOAddress("192.0.2.0");
    // Set some unicast local address to simulate a Renew.
    selector.local_address_ = IOAddress("10.0.0.100");
229
    ASSERT_FALSE(cfg.selectSubnet(selector));
230
231
232
233

    // Add one subnet and make sure it is returned.
    cfg.add(subnet1);
    selector.remote_address_ = IOAddress("192.0.2.63");
234
    EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
235
236
237
238
239
240
241

    // Add all other subnets.
    cfg.add(subnet2);
    cfg.add(subnet3);

    // Make sure they are returned for the appropriate addresses.
    selector.remote_address_ = IOAddress("192.0.2.15");
242
    EXPECT_EQ(subnet1, cfg.selectSubnet(selector));
243
    selector.remote_address_ = IOAddress("192.0.2.85");
244
    EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
245
    selector.remote_address_ = IOAddress("192.0.2.191");
246
    EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
247
248
249
250

    // Also, make sure that the NULL pointer is returned if the subnet
    // cannot be found.
    selector.remote_address_ = IOAddress("192.0.2.192");
251
    EXPECT_FALSE(cfg.selectSubnet(selector));
252
253
254
255
}

// This test verifies that the subnet can be selected using an address
// set on the local interface.
256
TEST(CfgSubnets4Test, selectSubnetInterface) {
257
258
259
260
    // The IfaceMgrTestConfig object initializes fake interfaces:
    // eth0, eth1 and lo on the configuration manager. The CfgSubnets4
    // object uses addresses assigned to these fake interfaces to
    // select the appropriate subnet.
261
262
263
    IfaceMgrTestConfig config(true);

    CfgSubnets4 cfg;
264
    SubnetSelector selector;
265
266
267
268

    // Initially, there are no subnets configured, so none of the IPv4
    // addresses assigned to eth0 and eth1 can match with any subnet.
    selector.iface_name_ = "eth0";
269
    EXPECT_FALSE(cfg.selectSubnet(selector));
270
    selector.iface_name_ = "eth1";
271
    EXPECT_FALSE(cfg.selectSubnet(selector));
272
273
274
275
276
277
278

    // Configure first subnet which address on eth0 corresponds to.
    Subnet4Ptr subnet1(new Subnet4(IOAddress("10.0.0.1"), 24, 1, 2, 3));
    cfg.add(subnet1);

    // The address on eth0 should match the existing subnet.
    selector.iface_name_ = "eth0";
279
    Subnet4Ptr subnet1_ret = cfg.selectSubnet(selector);
280
281
282
283
    ASSERT_TRUE(subnet1_ret);
    EXPECT_EQ(subnet1->get().first, subnet1_ret->get().first);
    // There should still be no match for eth1.
    selector.iface_name_ = "eth1";
284
    EXPECT_FALSE(cfg.selectSubnet(selector));
285
286
287
288
289
290
291
292

    // Configure a second subnet.
    Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.1"), 24, 1, 2, 3));
    cfg.add(subnet2);

    // There should be match between eth0 and subnet1 and between eth1 and
    // subnet 2.
    selector.iface_name_ = "eth0";
293
    subnet1_ret = cfg.selectSubnet(selector);
294
295
296
    ASSERT_TRUE(subnet1_ret);
    EXPECT_EQ(subnet1->get().first, subnet1_ret->get().first);
    selector.iface_name_ = "eth1";
297
    Subnet4Ptr subnet2_ret = cfg.selectSubnet(selector);
298
299
300
301
302
    ASSERT_TRUE(subnet2_ret);
    EXPECT_EQ(subnet2->get().first, subnet2_ret->get().first);

    // This function throws an exception if the name of the interface is wrong.
    selector.iface_name_ = "bogus-interface";
303
    EXPECT_THROW(cfg.selectSubnet(selector), isc::BadValue);
304
305
306
307
}

// Checks that detection of duplicated subnet IDs works as expected. It should
// not be possible to add two IPv4 subnets holding the same ID.
308
TEST(CfgSubnets4Test, duplication) {
309
310
311
312
313
314
315
316
317
    CfgSubnets4 cfg;

    Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3, 123));
    Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3, 124));
    Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3, 123));

    ASSERT_NO_THROW(cfg.add(subnet1));
    EXPECT_NO_THROW(cfg.add(subnet2));
    // Subnet 3 has the same ID as subnet 1. It shouldn't be able to add it.
318
    EXPECT_THROW(cfg.add(subnet3), isc::dhcp::DuplicateSubnetID);
319
320
321
322
}


} // end of anonymous namespace