1 // Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7 #include <config.h>
8 #include <asiolink/io_address.h>
9 #include <dhcp/docsis3_option_defs.h>
10 #include <dhcp/option6_addrlst.h>
11 #include <dhcp/option_int.h>
12 #include <dhcp/option_vendor.h>
13 #include <dhcp/tests/iface_mgr_test_config.h>
14 #include <dhcp6/tests/dhcp6_test_utils.h>
15 #include <dhcp6/tests/dhcp6_client.h>
16 #include <boost/algorithm/string/join.hpp>
17 #include <boost/lexical_cast.hpp>
18 #include <functional>
19 #include <list>
20 #include <sstream>
21
22 using namespace isc;
23 using namespace isc::asiolink;
24 using namespace isc::dhcp;
25 using namespace isc::dhcp::test;
26
27 namespace {
28
29 /// @brief Set of JSON configurations used by the Host reservation unit tests.
30 ///
31 /// - Configuration 0:
32 /// Single subnet with two reservations, one with a hostname, one without
33 ///
34 /// - Configuration 1:
35 /// Multiple reservations using different host identifiers.
36 ///
37 /// - Configuration 2:
38 /// Same as configuration 1 but 'host-reservation-identifiers' specified
39 /// in non-default order.
40 ///
41 /// - Configuration 3:
42 /// - Used to test that host specific options override pool specific,
43 /// subnet specific and global options.
44 ///
45 /// - Configuration 4:
46 /// - Used to test that client receives options solely specified in a
47 /// host scope.
48 ///
49 /// - Configuration 5:
50 /// - Used to test that host specific vendor options override globally
51 /// specified vendor options.
52 ///
53 /// - Configuration 6:
54 /// - One subnet with very short pool, i.e. two addresses
55 ///
56 /// - Configuration 7:
57 /// - Similar to Configuration 6, but one of the addresses reserved to client
58 /// with the DUID 04:03:02:01.
59 ///
60 /// Descriptions of next configurations are in the comment with the number.
61 const char* CONFIGS[] = {
62 // Configuration 0:
63 "{ "
64 "\"interfaces-config\": {"
65 " \"interfaces\": [ \"*\" ]"
66 "},"
67 "\"valid-lifetime\": 4000, "
68 "\"preferred-lifetime\": 3000,"
69 "\"rebind-timer\": 2000, "
70 "\"renew-timer\": 1000, "
71 "\"subnet6\": [ "
72 " { "
73 " \"subnet\": \"2001:db8:1::/48\", "
74 " \"pools\": [ { \"pool\": \"2001:db8:1:1::/64\" } ],"
75 " \"interface\" : \"eth0\" , "
76 " \"reservations\": ["
77 " {"
78 " \"duid\": \"01:02:03:04\","
79 " \"ip-addresses\": [ \"2001:db8:1:1::babe\" ],"
80 " \"hostname\": \"alice\""
81 " },"
82 " {"
83 " \"duid\": \"01:02:03:05\","
84 " \"ip-addresses\": [ \"2001:db8:1:1::babf\" ]"
85 " } ]"
86 " } ]"
87 "}",
88
89 // Configuration 1:
90 "{ "
91 "\"interfaces-config\": {"
92 " \"interfaces\": [ \"*\" ]"
93 "},"
94 "\"valid-lifetime\": 4000, "
95 "\"preferred-lifetime\": 3000,"
96 "\"rebind-timer\": 2000, "
97 "\"renew-timer\": 1000, "
98 "\"mac-sources\": [ \"ipv6-link-local\" ], "
99 "\"subnet6\": [ "
100 " { "
101 " \"subnet\": \"2001:db8:1::/48\", "
102 " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
103 " \"interface\" : \"eth0\" , "
104 " \"reservations\": ["
105 " {"
106 " \"hw-address\": \"38:60:77:d5:ff:ee\","
107 " \"ip-addresses\": [ \"2001:db8:1::1\" ]"
108 " },"
109 " {"
110 " \"duid\": \"01:02:03:05\","
111 " \"ip-addresses\": [ \"2001:db8:1::2\" ]"
112 " } ]"
113 " } ]"
114 "}",
115
116 // Configuration 2:
117 "{ "
118 "\"interfaces-config\": {"
119 " \"interfaces\": [ \"*\" ]"
120 "},"
121 "\"host-reservation-identifiers\": [ \"duid\", \"hw-address\" ],"
122 "\"valid-lifetime\": 4000, "
123 "\"preferred-lifetime\": 3000,"
124 "\"rebind-timer\": 2000, "
125 "\"renew-timer\": 1000, "
126 "\"mac-sources\": [ \"ipv6-link-local\" ], "
127 "\"subnet6\": [ "
128 " { "
129 " \"subnet\": \"2001:db8:1::/48\", "
130 " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
131 " \"interface\" : \"eth0\" , "
132 " \"reservations\": ["
133 " {"
134 " \"hw-address\": \"38:60:77:d5:ff:ee\","
135 " \"ip-addresses\": [ \"2001:db8:1::1\" ]"
136 " },"
137 " {"
138 " \"duid\": \"01:02:03:05\","
139 " \"ip-addresses\": [ \"2001:db8:1::2\" ]"
140 " } ]"
141 " } ]"
142 "}",
143
144 // Configuration 3:
145 "{ "
146 "\"interfaces-config\": {"
147 " \"interfaces\": [ \"*\" ]"
148 "},"
149 "\"host-reservation-identifiers\": [ \"duid\" ],"
150 "\"valid-lifetime\": 4000, "
151 "\"preferred-lifetime\": 3000,"
152 "\"rebind-timer\": 2000, "
153 "\"renew-timer\": 1000, "
154 "\"option-data\": [ {"
155 " \"name\": \"nisp-servers\","
156 " \"data\": \"3000:3::123\""
157 "} ],"
158 "\"subnet6\": [ "
159 " { "
160 " \"subnet\": \"2001:db8:1::/48\", "
161 " \"pools\": [ {"
162 " \"pool\": \"2001:db8:1::/64\","
163 " \"option-data\": [ {"
164 " \"name\": \"dns-servers\","
165 " \"data\": \"3000:2::111\""
166 " } ]"
167 " } ],"
168 " \"interface\" : \"eth0\","
169 " \"option-data\": [ {"
170 " \"name\": \"dns-servers\","
171 " \"data\": \"3000:2::123\""
172 " },"
173 " {"
174 " \"name\": \"nis-servers\","
175 " \"data\": \"3000:2::123\""
176 " },"
177 " {"
178 " \"name\": \"sntp-servers\","
179 " \"data\": \"3000:2::123\""
180 " } ],"
181 " \"reservations\": ["
182 " {"
183 " \"duid\": \"01:02:03:05\","
184 " \"ip-addresses\": [ \"2001:db8:1::2\" ],"
185 " \"option-data\": [ {"
186 " \"name\": \"dns-servers\","
187 " \"data\": \"3000:1::234\""
188 " },"
189 " {"
190 " \"name\": \"nis-servers\","
191 " \"data\": \"3000:1::234\""
192 " } ]"
193 " } ]"
194 " } ]"
195 "}",
196
197 // Configuration 4:
198 "{ "
199 "\"interfaces-config\": {"
200 " \"interfaces\": [ \"*\" ]"
201 "},"
202 "\"host-reservation-identifiers\": [ \"duid\" ],"
203 "\"valid-lifetime\": 4000, "
204 "\"preferred-lifetime\": 3000,"
205 "\"rebind-timer\": 2000, "
206 "\"renew-timer\": 1000, "
207 "\"subnet6\": [ "
208 " { "
209 " \"subnet\": \"2001:db8:1::/48\", "
210 " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
211 " \"interface\" : \"eth0\","
212 " \"reservations\": ["
213 " {"
214 " \"duid\": \"01:02:03:05\","
215 " \"ip-addresses\": [ \"2001:db8:1::2\" ],"
216 " \"option-data\": [ {"
217 " \"name\": \"dns-servers\","
218 " \"data\": \"3000:1::234\""
219 " },"
220 " {"
221 " \"name\": \"nis-servers\","
222 " \"data\": \"3000:1::234\""
223 " } ]"
224 " } ]"
225 " } ]"
226 "}",
227
228 // Configuration 5:
229 "{ "
230 "\"interfaces-config\": {"
231 " \"interfaces\": [ \"*\" ]"
232 "},"
233 "\"host-reservation-identifiers\": [ \"duid\" ],"
234 "\"valid-lifetime\": 4000, "
235 "\"preferred-lifetime\": 3000,"
236 "\"rebind-timer\": 2000, "
237 "\"renew-timer\": 1000, "
238 "\"option-data\": [ {"
239 " \"name\": \"vendor-opts\","
240 " \"data\": \"4491\""
241 "},"
242 "{"
243 " \"name\": \"tftp-servers\","
244 " \"space\": \"vendor-4491\","
245 " \"data\": \"3000:3::123\""
246 "} ],"
247 "\"subnet6\": [ "
248 " { "
249 " \"subnet\": \"2001:db8:1::/48\", "
250 " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
251 " \"interface\" : \"eth0\","
252 " \"reservations\": ["
253 " {"
254 " \"duid\": \"01:02:03:05\","
255 " \"ip-addresses\": [ \"2001:db8:1::2\" ],"
256 " \"option-data\": [ {"
257 " \"name\": \"vendor-opts\","
258 " \"data\": \"4491\""
259 " },"
260 " {"
261 " \"name\": \"tftp-servers\","
262 " \"space\": \"vendor-4491\","
263 " \"data\": \"3000:1::234\""
264 " } ]"
265 " } ]"
266 " } ]"
267 "}",
268
269 // Configuration 6:
270 "{ "
271 "\"interfaces-config\": {"
272 " \"interfaces\": [ \"*\" ]"
273 "},"
274 "\"host-reservation-identifiers\": [ \"duid\" ],"
275 "\"valid-lifetime\": 40, "
276 "\"preferred-lifetime\": 30,"
277 "\"rebind-timer\": 20, "
278 "\"renew-timer\": 10, "
279 "\"subnet6\": [ "
280 " { "
281 " \"subnet\": \"2001:db8:1::/48\", "
282 " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::2\" } ],"
283 " \"pd-pools\": ["
284 " {"
285 " \"prefix\": \"3000::\","
286 " \"prefix-len\": 119,"
287 " \"delegated-len\": 120"
288 " }"
289 " ],"
290 " \"interface\" : \"eth0\""
291 "} ]"
292 "}",
293
294 // Configuration 7:
295 "{ "
296 "\"interfaces-config\": {"
297 " \"interfaces\": [ \"*\" ]"
298 "},"
299 "\"host-reservation-identifiers\": [ \"duid\" ],"
300 "\"valid-lifetime\": 40, "
301 "\"preferred-lifetime\": 30,"
302 "\"rebind-timer\": 20, "
303 "\"renew-timer\": 10, "
304 "\"subnet6\": [ "
305 " { "
306 " \"subnet\": \"2001:db8:1::/48\", "
307 " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::2\" } ],"
308 " \"pd-pools\": ["
309 " {"
310 " \"prefix\": \"3000::\","
311 " \"prefix-len\": 119,"
312 " \"delegated-len\": 120"
313 " }"
314 " ],"
315 " \"interface\" : \"eth0\","
316 " \"reservations\": ["
317 " {"
318 " \"duid\": \"04:03:02:01\","
319 " \"ip-addresses\": [ \"2001:db8:1::2\" ],"
320 " \"prefixes\": [ \"3000::100/120\" ]"
321 " }"
322 " ]"
323 "} ]"
324 "}",
325
326 // Configuration 8: Global HRs TYPE_NAs
327 "{ "
328 "\"interfaces-config\": { \n"
329 " \"interfaces\": [ \"*\" ] \n"
330 "},\n "
331 "\"host-reservation-identifiers\": [ \"duid\", \"hw-address\" ], \n"
332 "\"reservations\": [ \n"
333 "{ \n"
334 " \"duid\": \"01:02:03:04\", \n"
335 " \"hostname\": \"duid-host-fixed\", \n"
336 " \"ip-addresses\": [ \"3001::1\" ] \n"
337 "}, \n"
338 "{ \n"
339 " \"duid\": \"01:02:03:05\", \n"
340 " \"hostname\": \"duid-host-dynamic\" \n"
341 "}, \n"
342 "{ \n"
343 " \"hw-address\": \"38:60:77:d5:ff:ee\", \n"
344 " \"hostname\": \"hw-host\" \n"
345 "} \n"
346 "], \n"
347 "\"valid-lifetime\": 4000, \n"
348 "\"preferred-lifetime\": 3000, \n"
349 "\"rebind-timer\": 2000, \n"
350 "\"renew-timer\": 1000, \n"
351 "\"mac-sources\": [ \"ipv6-link-local\" ], \n"
352 "\"subnet6\": [ \n"
353 " { \n"
354 " \"id\": 1, \n"
355 " \"subnet\": \"2001:db8:1::/48\", \n"
356 " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ], \n"
357 " \"interface\" : \"eth0\", \n"
358 " \"reservations-global\": true, \n"
359 " \"reservations-in-subnet\": false \n"
360 " },"
361 " { \n"
362 " \"id\": 2, \n"
363 " \"subnet\": \"2001:db8:2::/48\", \n"
364 " \"pools\": [ { \"pool\": \"2001:db8:2::/64\" } ], \n"
365 " \"interface\" : \"eth1\", \n"
366 " \"reservations\": [ \n"
367 " { \n"
368 " \"duid\": \"01:02:03:05\", \n"
369 " \"hostname\": \"subnet-duid-host\" \n"
370 " }] \n"
371 " }"
372 " ] \n"
373 "} \n"
374 ,
375 // Configuration 9: Global HRs TYPE_PDs
376 "{ "
377 "\"interfaces-config\": { \n"
378 " \"interfaces\": [ \"*\" ] \n"
379 "},\n "
380 "\"host-reservation-identifiers\": [ \"duid\", \"hw-address\" ], \n"
381 "\"reservations\": [ \n"
382 "{ \n"
383 " \"duid\": \"01:02:03:04\", \n"
384 " \"hostname\": \"duid-host-fixed\", \n"
385 " \"prefixes\": [ \"4000::100/120\" ]"
386 "}, \n"
387 "{ \n"
388 " \"duid\": \"01:02:03:05\", \n"
389 " \"hostname\": \"duid-host-dynamic\" \n"
390 "} \n"
391 "], \n"
392 "\"valid-lifetime\": 4000, \n"
393 "\"preferred-lifetime\": 3000, \n"
394 "\"rebind-timer\": 2000, \n"
395 "\"renew-timer\": 1000, \n"
396 "\"mac-sources\": [ \"ipv6-link-local\" ], \n"
397 "\"subnet6\": [ \n"
398 " { \n"
399 " \"id\": 1, \n"
400 " \"subnet\": \"2001:db8:1::/48\", \n"
401 " \"interface\" : \"eth0\", \n"
402 " \"reservations-global\": true, \n"
403 " \"reservations-in-subnet\": false, \n"
404 " \"pd-pools\": [ \n"
405 " { \n"
406 " \"prefix\": \"3000::\", \n"
407 " \"prefix-len\": 119, \n"
408 " \"delegated-len\": 120 \n"
409 " }] \n"
410 " },"
411 " { \n"
412 " \"id\": 2, \n"
413 " \"subnet\": \"2001:db8:2::/48\", \n"
414 " \"interface\" : \"eth1\", \n"
415 " \"pd-pools\": [ \n"
416 " { \n"
417 " \"prefix\": \"3001::\", \n"
418 " \"prefix-len\": 119, \n"
419 " \"delegated-len\": 120 \n"
420 " }], \n"
421 " \"reservations\": [ \n"
422 " { \n"
423 " \"duid\": \"01:02:03:05\", \n"
424 " \"hostname\": \"subnet-duid-host\" \n"
425 " }] \n"
426 " }"
427 " ] \n"
428 "} \n",
429
430 // Configuration 10: client-class reservation in global, shared network
431 // and client-class guarded pools.
432 "{ \"interfaces-config\": {\n"
433 " \"interfaces\": [ \"*\" ]\n"
434 "},\n"
435 "\"host-reservation-identifiers\": [ \"duid\", \"hw-address\" ], \n"
436 "\"client-classes\": ["
437 "{"
438 " \"name\": \"reserved_class\""
439 "},"
440 "{"
441 " \"name\": \"unreserved_class\","
442 " \"test\": \"not member('reserved_class')\""
443 "}"
444 "],\n"
445 "\"reservations-global\": true,\n"
446 "\"reservations-in-subnet\": false,\n"
447 "\"valid-lifetime\": 4000,\n"
448 "\"reservations\": [ \n"
449 "{\n"
450 " \"duid\": \"01:02:03:05\",\n"
451 " \"client-classes\": [ \"reserved_class\" ]\n"
452 "}\n"
453 "],\n"
454 "\"shared-networks\": [{"
455 " \"name\": \"frog\",\n"
456 " \"subnet6\": [\n"
457 " {\n"
458 " \"subnet\": \"2001:db8:1::/64\", \n"
459 " \"id\": 10,"
460 " \"pools\": ["
461 " {"
462 " \"pool\": \"2001:db8:1::10-2001:db8:1::11\","
463 " \"client-class\": \"reserved_class\""
464 " }"
465 " ],\n"
466 " \"interface\": \"eth0\"\n"
467 " },\n"
468 " {\n"
469 " \"subnet\": \"2001:db8:2::/64\", \n"
470 " \"id\": 11,"
471 " \"pools\": ["
472 " {"
473 " \"pool\": \"2001:db8:2::10-2001:db8:2::11\","
474 " \"client-class\": \"unreserved_class\""
475 " }"
476 " ],\n"
477 " \"interface\": \"eth0\"\n"
478 " }\n"
479 " ]\n"
480 "}]\n"
481 "}",
482
483 // Configuration 11: client-class reservation in global, shared network
484 // and client-class guarded subnets.
485 "{ \"interfaces-config\": {\n"
486 " \"interfaces\": [ \"*\" ]\n"
487 "},\n"
488 "\"host-reservation-identifiers\": [ \"duid\", \"hw-address\" ], \n"
489 "\"client-classes\": ["
490 "{"
491 " \"name\": \"reserved_class\""
492 "},"
493 "{"
494 " \"name\": \"unreserved_class\","
495 " \"test\": \"not member('reserved_class')\""
496 "}"
497 "],\n"
498 "\"reservations-global\": true,\n"
499 "\"reservations-in-subnet\": false,\n"
500 "\"valid-lifetime\": 4000,\n"
501 "\"reservations\": [ \n"
502 "{\n"
503 " \"duid\": \"01:02:03:05\",\n"
504 " \"client-classes\": [ \"reserved_class\" ]\n"
505 "}\n"
506 "],\n"
507 "\"shared-networks\": [{"
508 " \"name\": \"frog\",\n"
509 " \"subnet6\": [\n"
510 " {\n"
511 " \"subnet\": \"2001:db8:1::/64\", \n"
512 " \"client-class\": \"reserved_class\","
513 " \"id\": 10,"
514 " \"pools\": ["
515 " {"
516 " \"pool\": \"2001:db8:1::10-2001:db8:1::11\""
517 " }"
518 " ],\n"
519 " \"interface\": \"eth0\"\n"
520 " },\n"
521 " {\n"
522 " \"subnet\": \"2001:db8:2::/64\", \n"
523 " \"client-class\": \"unreserved_class\","
524 " \"id\": 11,"
525 " \"pools\": ["
526 " {"
527 " \"pool\": \"2001:db8:2::10-2001:db8:2::11\""
528 " }"
529 " ],\n"
530 " \"interface\": \"eth0\"\n"
531 " }\n"
532 " ]\n"
533 "}]\n"
534 "}",
535
536 // Configuration 12 client-class reservation and client-class guarded pools.
537 "{ \"interfaces-config\": {\n"
538 " \"interfaces\": [ \"*\" ]\n"
539 "},\n"
540 "\"client-classes\": ["
541 "{"
542 " \"name\": \"reserved_class\""
543 "},"
544 "{"
545 " \"name\": \"unreserved_class\","
546 " \"test\": \"not member('reserved_class')\""
547 "}"
548 "],\n"
549 "\"valid-lifetime\": 4000,\n"
550 "\"subnet6\": [\n"
551 " {\n"
552 " \"subnet\": \"2001:db8:1::/64\", \n"
553 " \"id\": 10,"
554 " \"reservations\": [{ \n"
555 " \"duid\": \"01:02:03:05\",\n"
556 " \"client-classes\": [ \"reserved_class\" ]\n"
557 " }],\n"
558 " \"pools\": ["
559 " {"
560 " \"pool\": \"2001:db8:1::10-2001:db8:1::11\","
561 " \"client-class\": \"reserved_class\""
562 " },"
563 " {"
564 " \"pool\": \"2001:db8:1::20-2001:db8:1::21\","
565 " \"client-class\": \"unreserved_class\""
566 " }"
567 " ],\n"
568 " \"interface\": \"eth0\"\n"
569 " }\n"
570 "]\n"
571 "}",
572
573 // Configuration 13 multiple reservations for the same IP address.
574 "{ \"interfaces-config\": {\n"
575 " \"interfaces\": [ \"*\" ]\n"
576 "},\n"
577 "\"valid-lifetime\": 4000,\n"
578 "\"ip-reservations-unique\": false,\n"
579 "\"subnet6\": [\n"
580 " {\n"
581 " \"subnet\": \"2001:db8:1::/64\",\n"
582 " \"id\": 10,"
583 " \"reservations\": [\n"
584 " {\n"
585 " \"duid\": \"01:02:03:04\",\n"
586 " \"ip-addresses\": [ \"2001:db8:1::15\" ]\n"
587 " },\n"
588 " {\n"
589 " \"duid\": \"01:02:03:05\",\n"
590 " \"ip-addresses\": [ \"2001:db8:1::15\" ]\n"
591 " }\n"
592 " ],\n"
593 " \"pools\": ["
594 " {\n"
595 " \"pool\": \"2001:db8:1::10-2001:db8:1::200\""
596 " }\n"
597 " ],\n"
598 " \"interface\": \"eth0\"\n"
599 " }\n"
600 "]\n"
601 "}",
602
603 // Configuration 14 multiple reservations for the same delegated prefix.
604 "{ \"interfaces-config\": {\n"
605 " \"interfaces\": [ \"*\" ]\n"
606 "},\n"
607 "\"valid-lifetime\": 4000,\n"
608 "\"ip-reservations-unique\": false,\n"
609 "\"subnet6\": [\n"
610 " {\n"
611 " \"subnet\": \"2001:db8:1::/64\",\n"
612 " \"id\": 10,"
613 " \"reservations\": [\n"
614 " {\n"
615 " \"duid\": \"01:02:03:04\",\n"
616 " \"prefixes\": [ \"3000::5a:0/112\" ]\n"
617 " },\n"
618 " {\n"
619 " \"duid\": \"01:02:03:05\",\n"
620 " \"prefixes\": [ \"3000::5a:0/112\" ]\n"
621 " }\n"
622 " ],\n"
623 " \"pd-pools\": ["
624 " {\n"
625 " \"prefix\": \"3000::\",\n"
626 " \"prefix-len\": 64,\n"
627 " \"delegated-len\": 112\n"
628 " }\n"
629 " ],\n"
630 " \"interface\": \"eth0\"\n"
631 " }\n"
632 "]\n"
633 "}"
634 };
635
636 /// @brief Base class representing leases and hints conveyed within IAs.
637 ///
638 /// This is a base class for @ref Reservation and @ref Hint classes.
639 class IAResource {
640 public:
641
642 /// @brief Constructor.
643 ///
644 /// Creates a resource instance from a string. The string is provided in
645 /// one of the following formats:
646 /// - "2001:db8:1::1" for addresses.
647 /// - "2001:db8::/64" for prefixes.
648 /// - "::/0" to mark lease or hint as unspecified (empty).
649 IAResource(const std::string& resource);
650
651 /// @brief Checks if resource is unspecified.
652 ///
653 /// @return true if resource is unspecified.
654 bool isEmpty() const;
655
656 /// @brief Checks if resource is a prefix.
657 ///
658 /// @return true if resource is a prefix.
659 bool isPrefix() const;
660
661 /// @brief Returns prefix or address (depending on resource type).
662 const IOAddress& getPrefix() const;
663
664 /// @brief Returns prefix length.
665 uint8_t getPrefixLen() const;
666
667 /// @brief Returns textual representation of the resource.
668 std::string toText() const;
669
670 /// @brief Operator converting resource to string.
671 operator std::string() const;
672
673 private:
674
675 /// @brief Holds prefix or address (depending on resource type).
676 IOAddress prefix_;
677
678 /// @brief Holds prefix length (for prefixes).
679 uint8_t prefix_len_;
680
681 };
682
IAResource(const std::string & resource)683 IAResource::IAResource(const std::string& resource)
684 : prefix_(IOAddress::IPV6_ZERO_ADDRESS()), prefix_len_(0) {
685 // Check if resource is a prefix, i.e. search for slash.
686 size_t slash_pos = resource.find("/");
687 if ((slash_pos != std::string::npos) && (slash_pos < resource.size() - 1)) {
688 prefix_len_ = boost::lexical_cast<unsigned int>(resource.substr(slash_pos + 1));
689 }
690 prefix_ = IOAddress(resource.substr(0, slash_pos));
691 }
692
693 bool
isEmpty() const694 IAResource::isEmpty() const {
695 return (prefix_.isV6Zero() && (prefix_len_ == 0));
696 }
697
698 bool
isPrefix() const699 IAResource::isPrefix() const {
700 return (!isEmpty() && (prefix_len_ > 0));
701 }
702
703 const IOAddress&
getPrefix() const704 IAResource::getPrefix() const {
705 return (prefix_);
706 }
707
708 uint8_t
getPrefixLen() const709 IAResource::getPrefixLen() const {
710 return (prefix_len_);
711 }
712
713 std::string
toText() const714 IAResource::toText() const {
715 std::ostringstream s;
716 s << "\"" << prefix_;
717 if (prefix_len_ > 0) {
718 s << "/" << static_cast<int>(prefix_len_);
719 }
720 s << "\"";
721 return (s.str());
722 }
723
operator std::string() const724 IAResource::operator std::string() const {
725 return (toText());
726 }
727
728 /// @brief Address or prefix reservation.
729 class Reservation : public IAResource {
730 public:
731
732 /// @brief Constructor
733 ///
734 /// @param resource Resource string as for @ref IAResource constructor.
Reservation(const std::string & resource)735 Reservation(const std::string& resource)
736 : IAResource(resource) {
737 }
738
739 /// @brief Convenience function returning unspecified resource.
740 static const Reservation& UNSPEC();
741
742 };
743
UNSPEC()744 const Reservation& Reservation::UNSPEC() {
745 static Reservation unspec("::/0");
746 return (unspec);
747 }
748
749 /// @brief Address or prefix hint.
750 class Hint : public IAResource {
751 public:
752
753 /// @brief Constructor.
754 ///
755 /// Includes IAID of an IA in which hint should be placed.
756 ///
757 /// @param iaid IAID of IA in which hint should be placed.
758 /// @param resource Resource string as for @ref IAResource constructor.
Hint(const IAID & iaid,const std::string & resource)759 Hint(const IAID& iaid, const std::string& resource)
760 : IAResource(resource), iaid_(iaid) {
761 }
762
763 /// @brief Returns IAID.
764 const IAID& getIAID() const;
765
766 /// @brief Convenience function returning unspecified hint.
767 static const Hint& UNSPEC();
768
769 private:
770
771 /// @brief Holds IAID as 32-bit unsigned integer.
772 IAID iaid_;
773 };
774
775 const IAID&
getIAID() const776 Hint::getIAID() const {
777 return (iaid_);
778 }
779
UNSPEC()780 const Hint& Hint::UNSPEC() {
781 static Hint unspec(IAID(0), "::/0");
782 return (unspec);
783 }
784
785 /// @brief Test fixture class for testing host reservations
786 class HostTest : public Dhcpv6SrvTest {
787 public:
788
789
790 /// @brief Constructor.
791 ///
792 /// Sets up fake interfaces.
HostTest()793 HostTest()
794 : Dhcpv6SrvTest(),
795 iface_mgr_test_config_(true),
796 client_(),
797 do_solicit_(std::bind(&Dhcp6Client::doSolicit, &client_, true)),
798 do_solicit_request_(std::bind(&Dhcp6Client::doSARR, &client_)) {
799 }
800
801 /// @brief Checks that specified option contains a desired address.
802 ///
803 /// The option must cast to the @ref Option6AddrLst type. The function
804 /// expects that this option contains at least one address and checks
805 /// first address for equality with @ref expected_addr.
806 ///
807 /// @param option_type Option type.
808 /// @param expected_addr Desired address.
809 /// @param config Configuration obtained from the server.
verifyAddressOption(const uint16_t option_type,const std::string & expected_addr,const Dhcp6Client::Configuration & config) const810 void verifyAddressOption(const uint16_t option_type,
811 const std::string& expected_addr,
812 const Dhcp6Client::Configuration& config) const {
813 Option6AddrLstPtr opt = boost::dynamic_pointer_cast<
814 Option6AddrLst>(config.findOption(option_type));
815 ASSERT_TRUE(opt) << "option " << option_type << " not found or it "
816 "is of incorrect type";
817 Option6AddrLst::AddressContainer addrs = opt->getAddresses();
818 ASSERT_GE(addrs.size(), 1) << "test failed for option type " << option_type;
819 EXPECT_EQ(expected_addr, addrs[0].toText())
820 << "test failed for option type " << option_type;
821 }
822
823 /// @brief Verifies that the reservation is retrieved by the server
824 /// using one of the host identifiers.
825 ///
826 /// @param client Reference to a client to be used in the test.
827 /// The client should be preconfigured to insert a specific identifier
828 /// into the message, e.g. DUID, HW address etc.
829 /// @param config_index Index of the configuration to use in the CONFIGS
830 /// table.
831 /// @param exp_ip_address Expected IPv6 address in the returned
832 /// reservation.
testReservationByIdentifier(Dhcp6Client & client,const unsigned int config_index,const std::string & exp_ip_address)833 void testReservationByIdentifier(Dhcp6Client& client,
834 const unsigned int config_index,
835 const std::string& exp_ip_address) {
836 configure(CONFIGS[config_index], *client.getServer());
837
838 const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
839 getCfgSubnets6()->getAll();
840 ASSERT_EQ(1, subnets->size());
841
842 // Configure client to request IA_NA and append IA_NA option
843 // to the client's message.
844 client.requestAddress(1234, IOAddress("2001:db8:1:1::dead:beef"));
845
846 // Perform 4-way exchange.
847 ASSERT_NO_THROW(client.doSARR());
848
849 // Verify that the client we got the reserved address
850 ASSERT_EQ(1, client.getLeaseNum());
851 Lease6 lease_client = client.getLease(0);
852 EXPECT_EQ(exp_ip_address, lease_client.addr_.toText());
853 }
854
855 /// @brief Initiate exchange with DHCPv6 server.
856 ///
857 /// This method initiates DHCPv6 message exchange between a specified
858 /// client and the server. The msg_type is used to indicate what kind
859 /// of exchange should be initiated. If the message type is a Renew
860 /// or Rebind, the 4-way handshake is made first. If the message type
861 /// is a Request, the Solicit-Advertise is done prior to this.
862 ///
863 /// @param msg_type Message type to be sent to the server.
864 /// @param client Reference to a client to be used to initiate the
865 /// exchange with the server.
866 void doExchange(const uint16_t msg_type, Dhcp6Client& client);
867
868 /// @brief Verifies that host specific options override subnet specific
869 /// options.
870 ///
871 /// Overridden options are requested with Option Request option.
872 ///
873 /// @param msg_type DHCPv6 message type to be sent to the server. If the
874 /// message type is Renew or Rebind, the 4-way exchange is made prior to
875 /// sending a Renew or Rebind. For a Request case, the Solicit-Advertise
876 /// is also performed.
877 void testOverrideRequestedOptions(const uint16_t msg_type);
878
879 /// @brief Verifies that client receives options when they are solely
880 /// defined in the host scope (and not in the global, subnet or pool
881 /// scope).
882 ///
883 /// @param msg_type DHCPv6 message type to be sent to the server. If the
884 /// message type is Renew or Rebind, the 4-way exchange is made prior to
885 /// sending a Renew or Rebind. For a Request case, the Solicit-Advertise
886 /// is also performed.
887 void testHostOnlyOptions(const uint16_t msg_type);
888
889 /// @brief Verifies that host specific vendor options override vendor
890 /// options defined in the global scope.
891 ///
892 /// @param msg_type DHCPv6 message type to be sent to the server. If the
893 /// message type is Renew or Rebind, the 4-way exchange is made prior to
894 /// sending a Renew or Rebind. For a Request case, the Solicit-Advertise
895 /// is also performed.
896 void testOverrideVendorOptions(const uint16_t msg_type);
897
898 /// @brief Checks if the client obtained lease for specified reservation.
899 ///
900 /// @param r Reservation.
901 /// @param [out] address_count This value is incremented if the client
902 /// obtained the address lease.
903 /// @param [out] prefix_count This value is incremented if the client
904 /// obtained the prefix lease.
905 void testLeaseForIA(const Reservation& r, size_t& address_count,
906 size_t& prefix_count);
907
908 /// @brief Checks if the client obtained lease for specified hint.
909 ///
910 /// The hint belongs to a specific IA (identified by IAID) and is expected
911 /// to be returned in this IA by the server.
912 ///
913 /// @param h Hint.
914 void testLeaseForIA(const Hint& h);
915
916 /// @brief A generic test for assigning multiple reservations to a single
917 /// client sending multiple IAs.
918 ///
919 /// This test creates a server configuration which includes one subnet,
920 /// address pool of "2001:db8:1::1 - 2001:db8:1::10" and the prefix pool
921 /// of 3001::/32, with delegated prefix length of 64. The configuration
922 /// may include between 0 and 6 reservations for a client with DUID of
923 /// "01:02:03:04".
924 ///
925 /// The test performs an exchange with a server, typically 4-way exchange
926 /// or Solicit-Advertise. The client's message includes 3 IA_NAs (with
927 /// IAIDs in range of 1..3) and 3 IA_PDs (with IAIDs in range of 4..6).
928 ///
929 /// It is possible to specify hints for selected IAs. The IA is in such
930 /// case identified by the IAID.
931 ///
932 /// The test expects that the server returns 6 leases. It checks if those
933 /// leases contain all reserved addresses and prefixes specified as
934 /// arguments of the test. If the number of IAs is greater than the
935 /// number of reservations it checks that for the remaining IAs the
936 /// leases from dynamic pools are assigned.
937 ///
938 /// The strict_iaid_check flag controls whether the test should verify
939 /// that the address or prefix specified as a hint is assigned by the
940 /// server to the IA in which the hint was placed by the client.
941 ///
942 /// @param client_operation Dhcp6Client function to be executed to
943 /// perform an exchange with the server.
944 /// @param r1 Reservation 1. Default value is "unspecified", in which
945 /// case the reservation will not be created.
946 /// @param r2 Reservation 2.
947 /// @param r3 Reservation 3.
948 /// @param r4 Reservation 4.
949 /// @param r5 Reservation 5.
950 /// @param r6 Reservation 6.
951 /// @param strict_iaid_check Indicates if the test should check if the
952 /// hints sent by the client have been allocated by the server to the
953 /// particular IAs. Default value is NO (no checks).
954 /// @param h1 Hint 1. Default value is "unspecified", in which case the
955 /// hint will not be included.
956 /// @param h2 Hint 2.
957 /// @param h3 Hint 3.
958 /// @param h4 Hint 4.
959 /// @param h5 Hint 5.
960 /// @param h6 Hint 6.
961 void testMultipleIAs(const std::function<void ()>& client_operation,
962 const Reservation& r1 = Reservation::UNSPEC(),
963 const Reservation& r2 = Reservation::UNSPEC(),
964 const Reservation& r3 = Reservation::UNSPEC(),
965 const Reservation& r4 = Reservation::UNSPEC(),
966 const Reservation& r5 = Reservation::UNSPEC(),
967 const Reservation& r6 = Reservation::UNSPEC(),
968 const StrictIAIDChecking& strict_iaid_check =
969 StrictIAIDChecking::NO(),
970 const Hint& h1 = Hint::UNSPEC(),
971 const Hint& h2 = Hint::UNSPEC(),
972 const Hint& h3 = Hint::UNSPEC(),
973 const Hint& h4 = Hint::UNSPEC(),
974 const Hint& h5 = Hint::UNSPEC(),
975 const Hint& h6 = Hint::UNSPEC());
976
977 /// @brief Checks if specified reservation is for address or prefix and
978 /// stores reservation in the textual format on one of the lists.
979 ///
980 /// @param [out] address_list Reference to a list containing address
981 /// reservations.
982 /// @param [out] prefix_list Reference to a list containing prefix
983 /// reservations.
984 static void storeReservation(const Reservation& r,
985 std::list<std::string>& address_list,
986 std::list<std::string>& prefix_list);
987
988 /// @brief Creates configuration for testing processing multiple IAs.
989 ///
990 /// This method creates a server configuration which includes one subnet,
991 /// address pool of "2001:db8:1::1 - 2001:db8:1::10" and the prefix pool
992 /// of 3001::/32, with delegated prefix length of 64. The configuration
993 /// may include between 0 and 6 reservations for a client with DUID of
994 /// "01:02:03:04".
995 ///
996 /// @param r1 Reservation 1. Default value is "unspecified" in which case
997 /// the reservation will not be included in the configuration.
998 /// @param r2 Reservation 2.
999 /// @param r3 Reservation 3.
1000 /// @param r4 Reservation 4.
1001 /// @param r5 Reservation 5.
1002 /// @param r6 Reservation 6.
1003 ///
1004 /// @return Text containing server configuration in JSON format.
1005 std::string configString(const DUID& duid,
1006 const Reservation& r1 = Reservation::UNSPEC(),
1007 const Reservation& r2 = Reservation::UNSPEC(),
1008 const Reservation& r3 = Reservation::UNSPEC(),
1009 const Reservation& r4 = Reservation::UNSPEC(),
1010 const Reservation& r5 = Reservation::UNSPEC(),
1011 const Reservation& r6 = Reservation::UNSPEC()) const;
1012
1013 /// @brief Verifies that an SARR exchange results in the expected lease
1014 ///
1015 /// @param client Client configured to request a single lease
1016 /// @param exp_address expected address/prefix of the lease
1017 /// @param exp_hostname expected hostname on the lease
1018 void sarrTest(Dhcp6Client& client, const std::string& exp_address,
1019 const std::string& exp_hostname);
1020
1021 /// @brief Configures client to include hint.
1022 ///
1023 /// @param client Reference to a client.
1024 /// @param hint Const reference to an object holding the hint.
1025 static void requestIA(Dhcp6Client& client, const Hint& hint);
1026
1027 /// @brief Test pool or subnet selection using global class reservation.
1028 ///
1029 /// Verifies that client class specified in the global reservation
1030 /// may be used to influence pool or subnet selection.
1031 ///
1032 /// @param config_idx Index of the server configuration from the
1033 /// @c CONFIGS array.
1034 /// @param first_address Address to be allocated from the pool having
1035 /// a reservation.
1036 /// @param second_address Address to be allocated from the pool not
1037 /// having a reservation.
1038 void testGlobalClassSubnetPoolSelection(const int config_idx,
1039 const std::string& first_address = "2001:db8:1::10",
1040 const std::string& second_address = "2001:db8:2::10");
1041
1042 /// @brief Test that two clients having reservations for the same IP
1043 /// address are offered the reserved lease.
1044 ///
1045 /// This test verifies the case when two clients have reservations for
1046 /// the same IP address. The first client sends Solicit and is offered
1047 /// the reserved address. At the same time, the second client having
1048 /// the reservation for the same IP address performs 4-way exchange
1049 /// using the reserved address as a hint in Solicit.
1050 /// The client gets the lease for this address. This test verifies
1051 /// that the allocation engine correctly identifies that the second
1052 /// client has a reservation for this address.
1053 ///
1054 /// @param duid1 Hardware address of the first client having the
1055 /// reservation.
1056 /// @param duid2 Hardware address of the second client having the
1057 /// reservation.
1058 void testMultipleClientsRace(const std::string& duid1,
1059 const std::string& duid2);
1060
1061 /// @brief Configures client to include 6 IAs without hints.
1062 ///
1063 /// This method configures the client to include 3 IA_NAs and
1064 /// 3 IA_PDs.
1065 ///
1066 /// @param client Reference to a client.
1067 static void requestEmptyIAs(Dhcp6Client& client);
1068
1069 /// @brief Interface Manager's fake configuration control.
1070 IfaceMgrTestConfig iface_mgr_test_config_;
1071
1072 /// @brief Instance of the common DHCPv6 client.
1073 Dhcp6Client client_;
1074
1075 /// @brief Pointer to the Dhcp6Client::doSolicit method.
1076 std::function<void() > do_solicit_;
1077
1078 /// @brief Pointer to the Dhcp6Client::doSARR method.
1079 std::function<void() > do_solicit_request_;
1080 };
1081
1082 void
doExchange(const uint16_t msg_type,Dhcp6Client & client)1083 HostTest::doExchange(const uint16_t msg_type, Dhcp6Client& client) {
1084 switch (msg_type) {
1085 case DHCPV6_INFORMATION_REQUEST:
1086 ASSERT_NO_THROW(client.doInfRequest());
1087 break;
1088 case DHCPV6_REQUEST:
1089 ASSERT_NO_THROW(client.doSARR());
1090 break;
1091 case DHCPV6_SOLICIT:
1092 ASSERT_NO_THROW(client.doSolicit());
1093 break;
1094 case DHCPV6_RENEW:
1095 ASSERT_NO_THROW(client.doSARR());
1096 ASSERT_NO_THROW(client.doRenew());
1097 break;
1098 case DHCPV6_REBIND:
1099 ASSERT_NO_THROW(client.doSARR());
1100 ASSERT_NO_THROW(client.doRebind());
1101 break;
1102 default:
1103 ;
1104 }
1105
1106 // Make sure that the server has responded with a Reply.
1107 ASSERT_TRUE(client.getContext().response_);
1108 ASSERT_EQ(DHCPV6_REPLY, client.getContext().response_->getType());
1109
1110 }
1111
1112
1113 void
testOverrideRequestedOptions(const uint16_t msg_type)1114 HostTest::testOverrideRequestedOptions(const uint16_t msg_type) {
1115 Dhcp6Client client;
1116 // Reservation has been made for a client with this DUID.
1117 client.setDUID("01:02:03:05");
1118
1119 // Request all options specified in the configuration.
1120 client.requestOption(D6O_NAME_SERVERS);
1121 client.requestOption(D6O_NIS_SERVERS);
1122 client.requestOption(D6O_NISP_SERVERS);
1123 client.requestOption(D6O_SNTP_SERVERS);
1124
1125 configure(CONFIGS[3], *client.getServer());
1126
1127 ASSERT_NO_FATAL_FAILURE(doExchange(msg_type, client));
1128
1129 {
1130 SCOPED_TRACE("host specific dns-servers");
1131 // Host specific DNS server should be used.
1132 verifyAddressOption(D6O_NAME_SERVERS, "3000:1::234", client.config_);
1133 }
1134
1135 {
1136 SCOPED_TRACE("host specific nis-servers");
1137 // Host specific NIS server should be used.
1138 verifyAddressOption(D6O_NIS_SERVERS, "3000:1::234", client.config_);
1139 }
1140
1141 {
1142 SCOPED_TRACE("subnet specific sntp-servers");
1143 // Subnet specific SNTP server should be used as it is not specified
1144 // in a host scope.
1145 verifyAddressOption(D6O_SNTP_SERVERS, "3000:2::123", client.config_);
1146 }
1147
1148 {
1149 SCOPED_TRACE("global nisp-servers");
1150 // Globally specified NISP server should be used as it is not
1151 // specified in a host scope.
1152 verifyAddressOption(D6O_NISP_SERVERS, "3000:3::123", client.config_);
1153 }
1154 }
1155
1156 void
testLeaseForIA(const Reservation & r,size_t & address_count,size_t & prefix_count)1157 HostTest::testLeaseForIA(const Reservation& r, size_t& address_count,
1158 size_t& prefix_count) {
1159 if (r.isPrefix()) {
1160 ++prefix_count;
1161 EXPECT_TRUE(client_.hasLeaseForPrefix(r.getPrefix(),
1162 r.getPrefixLen(),
1163 IAID(3 + prefix_count)));
1164
1165 } else if (!r.isEmpty()) {
1166 ++address_count;
1167 EXPECT_TRUE(client_.hasLeaseForAddress(r.getPrefix(),
1168 IAID(address_count)));
1169 }
1170 }
1171
1172 void
testLeaseForIA(const Hint & h)1173 HostTest::testLeaseForIA(const Hint& h) {
1174 if (h.isPrefix()) {
1175 EXPECT_TRUE(client_.hasLeaseForPrefix(h.getPrefix(), h.getPrefixLen(),
1176 h.getIAID()))
1177 << "there is no lease for prefix " << h.toText()
1178 << " and IAID = " << h.getIAID();
1179
1180 } else if (!h.isEmpty()) {
1181 EXPECT_TRUE(client_.hasLeaseForAddress(h.getPrefix(), h.getIAID()))
1182 << "there is no lease for address " << h.toText()
1183 << " and IAID = " << h.getIAID();
1184 }
1185 }
1186
1187 void
testMultipleIAs(const std::function<void ()> & client_operation,const Reservation & r1,const Reservation & r2,const Reservation & r3,const Reservation & r4,const Reservation & r5,const Reservation & r6,const StrictIAIDChecking & strict_iaid_check,const Hint & h1,const Hint & h2,const Hint & h3,const Hint & h4,const Hint & h5,const Hint & h6)1188 HostTest::testMultipleIAs(const std::function<void ()>& client_operation,
1189 const Reservation& r1, const Reservation& r2,
1190 const Reservation& r3, const Reservation& r4,
1191 const Reservation& r5, const Reservation& r6,
1192 const StrictIAIDChecking& strict_iaid_check,
1193 const Hint& h1, const Hint& h2 ,
1194 const Hint& h3, const Hint& h4,
1195 const Hint& h5, const Hint& h6) {
1196 client_.setDUID("01:02:03:04");
1197
1198 /// Create configuration with 0 to 6 reservations.
1199 const std::string c = configString(*client_.getDuid(), r1, r2, r3,
1200 r4, r5, r6);
1201
1202 ASSERT_NO_THROW(configure(c, *client_.getServer()));
1203
1204 // First includes all IAs. They are initially empty.
1205 requestEmptyIAs(client_);
1206
1207 // For each specified hint, include it in the respective IA. Hints
1208 // which are "unspecified" will not be included.
1209 requestIA(client_, h1);
1210 requestIA(client_, h2);
1211 requestIA(client_, h3);
1212 requestIA(client_, h4);
1213 requestIA(client_, h5);
1214 requestIA(client_, h6);
1215
1216
1217 // Send Solicit and require that the client saves received configuration
1218 // so as we can test that advertised configuration is correct.
1219 ASSERT_NO_THROW(client_operation());
1220
1221 ASSERT_EQ(6, client_.getLeaseNum());
1222
1223 // Count reserved addresses and prefixes assigned from reservations.
1224 size_t address_count = 0;
1225 size_t prefix_count = 0;
1226
1227 testLeaseForIA(r1, address_count, prefix_count);
1228 testLeaseForIA(r2, address_count, prefix_count);
1229 testLeaseForIA(r3, address_count, prefix_count);
1230 testLeaseForIA(r4, address_count, prefix_count);
1231 testLeaseForIA(r5, address_count, prefix_count);
1232 testLeaseForIA(r6, address_count, prefix_count);
1233
1234 // Get all addresses assigned from the dynamic pool (not reserved).
1235 std::vector<Lease6> leases =
1236 client_.getLeasesByAddressRange(IOAddress("2001:db8:1::1"),
1237 IOAddress("2001:db8:1::10"));
1238 // There are 3 IA_NAs and for a few we have assigned reserved addresses.
1239 // The remaining ones should be assigned from the dynamic pool.
1240 ASSERT_EQ(3 - address_count, leases.size());
1241
1242 // Get all prefixes assigned from the dynamic pool (not reserved).
1243 leases = client_.getLeasesByPrefixPool(IOAddress("3001::"), 32, 64);
1244 ASSERT_EQ(3 - prefix_count, leases.size());
1245
1246 // Check that the hints have been allocated to respective IAs.
1247 if (strict_iaid_check) {
1248 testLeaseForIA(h1);
1249 testLeaseForIA(h2);
1250 testLeaseForIA(h3);
1251 testLeaseForIA(h4);
1252 testLeaseForIA(h5);
1253 testLeaseForIA(h6);
1254 }
1255 }
1256
1257
1258 void
storeReservation(const Reservation & r,std::list<std::string> & address_list,std::list<std::string> & prefix_list)1259 HostTest::storeReservation(const Reservation& r,
1260 std::list<std::string>& address_list,
1261 std::list<std::string>& prefix_list) {
1262 if (!r.isEmpty()) {
1263 if (r.isPrefix()) {
1264 prefix_list.push_back(r);
1265 } else {
1266 address_list.push_back(r);
1267 }
1268 }
1269 }
1270
1271 std::string
configString(const DUID & duid,const Reservation & r1,const Reservation & r2,const Reservation & r3,const Reservation & r4,const Reservation & r5,const Reservation & r6) const1272 HostTest::configString(const DUID& duid,
1273 const Reservation& r1, const Reservation& r2,
1274 const Reservation& r3, const Reservation& r4,
1275 const Reservation& r5, const Reservation& r6) const {
1276 std::list<std::string> address_list;
1277 std::list<std::string> prefix_list;
1278 storeReservation(r1, address_list, prefix_list);
1279 storeReservation(r2, address_list, prefix_list);
1280 storeReservation(r3, address_list, prefix_list);
1281 storeReservation(r4, address_list, prefix_list);
1282 storeReservation(r5, address_list, prefix_list);
1283 storeReservation(r6, address_list, prefix_list);
1284
1285 std::ostringstream s;
1286 s << "{ "
1287 "\"interfaces-config\": {"
1288 " \"interfaces\": [ \"*\" ]"
1289 "},"
1290 "\"valid-lifetime\": 4000, "
1291 "\"preferred-lifetime\": 3000,"
1292 "\"rebind-timer\": 2000, "
1293 "\"renew-timer\": 1000, "
1294 "\"subnet6\": [ "
1295 " { "
1296 " \"subnet\": \"2001:db8:1::/48\", "
1297 " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::10\" } ],"
1298 " \"pd-pools\": [ { \"prefix\": \"3001::\", \"prefix-len\": 32,"
1299 " \"delegated-len\": 64 } ],"
1300 " \"interface\" : \"eth0\"";
1301
1302 // Create reservations.
1303 if (!address_list.empty() || !prefix_list.empty()) {
1304 s << ","
1305 " \"reservations\": ["
1306 " {"
1307 " \"duid\": ";
1308 s << "\"" << duid.toText() << "\",";
1309
1310 if (!address_list.empty()) {
1311 s << " \"ip-addresses\": [ "
1312 << boost::algorithm::join(address_list, ", ")
1313 << "]";
1314 }
1315
1316 if (!prefix_list.empty()) {
1317 if (!address_list.empty()) {
1318 s << ", ";
1319 }
1320 s << " \"prefixes\": [ "
1321 << boost::algorithm::join(prefix_list, ", ")
1322 << "]";
1323 }
1324
1325 s << " } ]";
1326 }
1327
1328 s << " } ]"
1329 "}";
1330
1331 return (s.str());
1332 }
1333
1334 void
requestIA(Dhcp6Client & client,const Hint & hint)1335 HostTest::requestIA(Dhcp6Client& client, const Hint& hint) {
1336 if ((hint.getIAID() != 0) && !hint.isEmpty()) {
1337 if (hint.isPrefix()) {
1338 client.requestPrefix(hint.getIAID(), hint.getPrefixLen(),
1339 hint.getPrefix());
1340 } else {
1341 client.requestAddress(hint.getIAID(), hint.getPrefix());
1342 }
1343 }
1344 }
1345
1346 void
testHostOnlyOptions(const uint16_t msg_type)1347 HostTest::testHostOnlyOptions(const uint16_t msg_type) {
1348 Dhcp6Client client;
1349 client.setDUID("01:02:03:05");
1350 client.requestOption(D6O_NAME_SERVERS);
1351 client.requestOption(D6O_NIS_SERVERS);
1352
1353 configure(CONFIGS[3], *client.getServer());
1354
1355 ASSERT_NO_FATAL_FAILURE(doExchange(msg_type, client));
1356
1357 {
1358 SCOPED_TRACE("host specific dns-servers");
1359 // DNS servers are specified only in a host scope.
1360 verifyAddressOption(D6O_NAME_SERVERS, "3000:1::234", client.config_);
1361 }
1362
1363 {
1364 SCOPED_TRACE("host specific nis-servers");
1365 // NIS servers are specified only in a host scope.
1366 verifyAddressOption(D6O_NIS_SERVERS, "3000:1::234", client.config_);
1367 }
1368 }
1369
1370 void
testOverrideVendorOptions(const uint16_t msg_type)1371 HostTest::testOverrideVendorOptions(const uint16_t msg_type) {
1372 Dhcp6Client client;
1373 client.setDUID("01:02:03:05");
1374
1375 // Client needs to include Vendor Specific Information option
1376 // with ORO suboption, which the server will use to determine
1377 // which suboptions should be returned to the client.
1378 OptionVendorPtr opt_vendor(new OptionVendor(Option::V6,
1379 VENDOR_ID_CABLE_LABS));
1380 // Include ORO with TFTP servers suboption code being requested.
1381 opt_vendor->addOption(OptionPtr(new OptionUint16(Option::V6, DOCSIS3_V6_ORO,
1382 DOCSIS3_V6_TFTP_SERVERS)));
1383 client.addExtraOption(opt_vendor);
1384
1385 configure(CONFIGS[5], *client.getServer());
1386
1387 ASSERT_NO_FATAL_FAILURE(doExchange(msg_type, client));
1388
1389 // Vendor Specific Information option should be returned by the server.
1390 OptionVendorPtr vendor_opt = boost::dynamic_pointer_cast<
1391 OptionVendor>(client.config_.findOption(D6O_VENDOR_OPTS));
1392 ASSERT_TRUE(vendor_opt);
1393
1394 // TFTP server suboption should be returned because it was requested
1395 // with Option Request suboption.
1396 Option6AddrLstPtr tftp = boost::dynamic_pointer_cast<
1397 Option6AddrLst>(vendor_opt->getOption(DOCSIS3_V6_TFTP_SERVERS));
1398 ASSERT_TRUE(tftp);
1399
1400 // Address specified in the host scope should be used.
1401 Option6AddrLst::AddressContainer addrs = tftp->getAddresses();
1402 ASSERT_EQ(addrs.size(), 1);
1403 EXPECT_EQ("3000:1::234", addrs[0].toText());
1404 }
1405
1406 void
testGlobalClassSubnetPoolSelection(const int config_idx,const std::string & first_address,const std::string & second_address)1407 HostTest::testGlobalClassSubnetPoolSelection(const int config_idx,
1408 const std::string& first_address,
1409 const std::string& second_address) {
1410 Dhcp6Client client_resrv;
1411
1412 // Use DUID for which we have host reservation including client class.
1413 client_resrv.setDUID("01:02:03:05");
1414
1415 ASSERT_NO_FATAL_FAILURE(configure(CONFIGS[config_idx], *client_resrv.getServer()));
1416
1417 // This client should be given an address from the 2001:db8:1::/64 subnet.
1418 // Let's use the 2001:db8:2::10 as a hint to make sure that the server
1419 // refuses allocating it and uses the sole pool available for this
1420 // client.
1421 client_resrv.requestAddress(1, IOAddress(second_address));
1422 ASSERT_NO_THROW(client_resrv.doSARR());
1423 ASSERT_EQ(1, client_resrv.getLeaseNum());
1424 Lease6 lease_client = client_resrv.getLease(0);
1425 EXPECT_EQ(first_address, lease_client.addr_.toText());
1426
1427 // This client has no reservation and therefore should be
1428 // assigned to the unreserved_class and be given an address
1429 // from the other pool.
1430 Dhcp6Client client_no_resrv(client_resrv.getServer());
1431 client_no_resrv.setDUID("01:02:03:04");
1432
1433 // Let's use the address of 2001:db8:1::10 as a hint to make sure that the
1434 // server refuses it in favor of the 2001:db8:2::10.
1435 client_no_resrv.requestAddress(1, IOAddress(first_address));
1436 ASSERT_NO_THROW(client_no_resrv.doSARR());
1437 ASSERT_EQ(1, client_no_resrv.getLeaseNum());
1438 lease_client = client_no_resrv.getLease(0);
1439 EXPECT_EQ(second_address, lease_client.addr_.toText());
1440 }
1441
1442 void
testMultipleClientsRace(const std::string & duid1,const std::string & duid2)1443 HostTest::testMultipleClientsRace(const std::string& duid1,
1444 const std::string& duid2) {
1445 Dhcp6Client client1;
1446 client1.setDUID(duid1);
1447 ASSERT_NO_THROW(configure(CONFIGS[13], *client1.getServer()));
1448 // client1 performs 4-way exchange to get the reserved lease.
1449 requestIA(client1, Hint(IAID(1), "2001:db8:1::15"));
1450 ASSERT_NO_THROW(client1.doSARR());
1451
1452 // Make sure the client has obtained reserved lease.
1453 ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
1454
1455 // Create another client that has a reservation for the same
1456 // IP address.
1457 Dhcp6Client client2(client1.getServer());
1458 client2.setDUID(duid2);
1459 requestIA(client2, Hint(IAID(1), "2001:db8:1::15"));
1460
1461 // client2 performs 4-way exchange.
1462 ASSERT_NO_THROW(client2.doSARR());
1463
1464 // Make sure the client didn't get the reserved lease. This lease has been
1465 // already taken by the client1.
1466 EXPECT_FALSE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
1467
1468 // Make sure the client2 got a lease from the configured pool.
1469 EXPECT_TRUE(client2.hasLeaseForAddressRange(IOAddress("2001:db8:1::10"),
1470 IOAddress("2001:db8:1::200")));
1471 }
1472
1473 void
requestEmptyIAs(Dhcp6Client & client)1474 HostTest::requestEmptyIAs(Dhcp6Client& client) {
1475 // Create IAs with IAIDs between 1 and 6.
1476 client.requestAddress(1);
1477 client.requestAddress(2);
1478 client.requestAddress(3);
1479 client.requestPrefix(4);
1480 client.requestPrefix(5);
1481 client.requestPrefix(6);
1482 }
1483
1484 void
sarrTest(Dhcp6Client & client,const std::string & exp_address,const std::string & exp_hostname)1485 HostTest::sarrTest(Dhcp6Client& client, const std::string& exp_address,
1486 const std::string& exp_hostname) {
1487 // Perform 4-way exchange.
1488 ASSERT_NO_THROW(client.doSARR());
1489
1490 // Verify that the client got a dynamic address
1491 ASSERT_EQ(1, client.getLeaseNum());
1492 Lease6 lease_client = client.getLease(0);
1493 EXPECT_EQ(exp_address, lease_client.addr_.toText());
1494
1495 // Check that the server recorded the lease
1496 // and that the server lease has expected hostname.
1497 Lease6Ptr lease_server = checkLease(lease_client);
1498 ASSERT_TRUE(lease_server);
1499 EXPECT_EQ(exp_hostname, lease_server->hostname_);
1500 }
1501
1502
1503 // Test basic SARR scenarios against a server configured with one subnet
1504 // containing two reservations. One reservation with a hostname, one
1505 // without a hostname. Scenarios:
1506 //
1507 // - Verify that a client when matched to a host reservation with a hostname
1508 // gets that reservation and the lease hostname matches the reserved hostname
1509 //
1510 // - Verify that a client when matched to a host reservation without a hostname
1511 // gets that reservation and the lease hostname is blank
1512 //
1513 // - Verify that a client that does not match a host reservation gets a dynamic
1514 // lease and the hostname for the lease is blank.
1515 //
TEST_F(HostTest,basicSarrs)1516 TEST_F(HostTest, basicSarrs) {
1517 Dhcp6Client client;
1518 configure(CONFIGS[0], *client.getServer());
1519
1520 const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
1521 getCfgSubnets6()->getAll();
1522 ASSERT_EQ(1, subnets->size());
1523
1524 // Configure client to request IA_NA and append IA_NA option
1525 // to the client's message.
1526 client.setDUID("01:02:03:04");
1527 client.requestAddress(1234, IOAddress("2001:db8:1:1::dead:beef"));
1528
1529 // Perform 4-way exchange.
1530 ASSERT_NO_THROW(client.doSARR());
1531
1532 // Verify that the client we got the reserved address
1533 ASSERT_EQ(1, client.getLeaseNum());
1534 Lease6 lease_client = client.getLease(0);
1535 EXPECT_EQ("2001:db8:1:1::babe", lease_client.addr_.toText());
1536
1537 // Check that the server recorded the lease.
1538 // and lease has reserved hostname
1539 Lease6Ptr lease_server = checkLease(lease_client);
1540 ASSERT_TRUE(lease_server);
1541 EXPECT_EQ("alice", lease_server->hostname_);
1542
1543 // Now redo the client, adding one to the DUID
1544 client.clearConfig();
1545 client.modifyDUID();
1546
1547 // Perform 4-way exchange.
1548 ASSERT_NO_THROW(client.doSARR());
1549
1550 // Verify that the client we got the reserved address
1551 ASSERT_EQ(1, client.getLeaseNum());
1552 lease_client = client.getLease(0);
1553 EXPECT_EQ("2001:db8:1:1::babf", lease_client.addr_.toText());
1554
1555 // Check that the server recorded the lease.
1556 // and that the server lease has NO hostname
1557 lease_server = checkLease(lease_client);
1558 ASSERT_TRUE(lease_server);
1559 EXPECT_EQ("", lease_server->hostname_);
1560
1561 // Now redo the client with yet another DUID and verify that
1562 // we get a dynamic address.
1563 client.clearConfig();
1564 client.modifyDUID();
1565 client.clearRequestedIAs();
1566 client.requestAddress(1234);
1567
1568 // Perform 4-way exchange.
1569 ASSERT_NO_THROW(client.doSARR());
1570
1571 // Verify that the client got a dynamic address
1572 ASSERT_EQ(1, client.getLeaseNum());
1573 lease_client = client.getLease(0);
1574 EXPECT_EQ("2001:db8:1:1::", lease_client.addr_.toText());
1575
1576 // Check that the server recorded the lease.
1577 // and that the server lease has NO hostname
1578 lease_server = checkLease(lease_client);
1579 ASSERT_TRUE(lease_server);
1580 EXPECT_EQ("", lease_server->hostname_);
1581 }
1582
1583 // Test basic SARR and renew situation with a client that matches a host
1584 // reservation
TEST_F(HostTest,sarrAndRenew)1585 TEST_F(HostTest, sarrAndRenew) {
1586 Dhcp6Client client;
1587
1588 configure(CONFIGS[0], *client.getServer());
1589
1590 // Configure client to request IA_NA.
1591 client.requestAddress();
1592
1593 const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
1594 getCfgSubnets6()->getAll();
1595 ASSERT_EQ(1, subnets->size());
1596
1597 // Configure client to request IA_NA and aAppend IA_NA option
1598 // to the client's message.
1599 client.setDUID("01:02:03:04");
1600 client.requestAddress(1234, IOAddress("2001:db8:1:1::dead:beef"));
1601
1602 // Perform 4-way exchange.
1603 ASSERT_NO_THROW(client.doSARR());
1604
1605 // Now play with time
1606 client.fastFwdTime(1000);
1607
1608 // Verify that the client we got the reserved address
1609 ASSERT_EQ(1, client.getLeaseNum());
1610 Lease6 lease_client = client.getLease(0);
1611 EXPECT_EQ("2001:db8:1:1::babe", lease_client.addr_.toText());
1612
1613 // Do not send the hint while renewing.
1614 client.clearRequestedIAs();
1615
1616 // Send Renew message to the server.
1617 ASSERT_NO_THROW(client.doRenew());
1618
1619 // Verify that we got an extended lease back
1620 ASSERT_EQ(1, client.getLeaseNum());
1621 Lease6 lease_client2 = client.getLease(0);
1622 EXPECT_EQ("2001:db8:1:1::babe", lease_client2.addr_.toText());
1623
1624 // The client's lease should have been extended. The client will
1625 // update the cltt to current time when the lease gets extended.
1626 ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000);
1627
1628 // Make sure, that the client's lease matches the lease held by the
1629 // server and that we have the reserved host name.
1630 Lease6Ptr lease_server2 = checkLease(lease_client2);
1631 EXPECT_TRUE(lease_server2);
1632 EXPECT_EQ("alice", lease_server2->hostname_);
1633 }
1634
1635 // Test basic SARR and rebind situation with a client that matches a host
1636 // reservation.
TEST_F(HostTest,sarrAndRebind)1637 TEST_F(HostTest, sarrAndRebind) {
1638 Dhcp6Client client;
1639
1640 configure(CONFIGS[0], *client.getServer());
1641
1642 // Configure client to request IA_NA.
1643 client.requestAddress();
1644
1645 const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
1646 getCfgSubnets6()->getAll();
1647 ASSERT_EQ(1, subnets->size());
1648
1649 // Configure client to request IA_NA and aAppend IA_NA option
1650 // to the client's message.
1651 client.setDUID("01:02:03:04");
1652 client.requestAddress(1234, IOAddress("2001:db8:1:1::dead:beef"));
1653
1654 // Perform 4-way exchange.
1655 ASSERT_NO_THROW(client.doSARR());
1656
1657 // Now play with time
1658 client.fastFwdTime(1000);
1659
1660 // Verify that the client we got the reserved address
1661 ASSERT_EQ(1, client.getLeaseNum());
1662 Lease6 lease_client = client.getLease(0);
1663 EXPECT_EQ("2001:db8:1:1::babe", lease_client.addr_.toText());
1664
1665 // Do not send the hint while renewing.
1666 client.clearRequestedIAs();
1667
1668 // Send Rebind message to the server.
1669 ASSERT_NO_THROW(client.doRebind());
1670
1671 // Verify that we got an extended lease back
1672 ASSERT_EQ(1, client.getLeaseNum());
1673 Lease6 lease_client2 = client.getLease(0);
1674 EXPECT_EQ("2001:db8:1:1::babe", lease_client2.addr_.toText());
1675
1676 // The client's lease should have been extended. The client will
1677 // update the cltt to current time when the lease gets extended.
1678 ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000);
1679
1680 // Make sure, that the client's lease matches the lease held by the
1681 // server and that we have the reserved host name.
1682 Lease6Ptr lease_server2 = checkLease(lease_client2);
1683 EXPECT_TRUE(lease_server2);
1684 EXPECT_EQ("alice", lease_server2->hostname_);
1685 }
1686
1687 // This test verifies that the host reservation by DUID is found by the
1688 // server.
TEST_F(HostTest,reservationByDUID)1689 TEST_F(HostTest, reservationByDUID) {
1690 Dhcp6Client client;
1691 // Set DUID matching the one used to create host reservations.
1692 client.setDUID("01:02:03:05");
1693 // Run the actual test.
1694 testReservationByIdentifier(client, 1, "2001:db8:1::2");
1695 }
1696
1697 // This test verifies that the host reservation by HW address is found
1698 // by the server.
TEST_F(HostTest,reservationByHWAddress)1699 TEST_F(HostTest, reservationByHWAddress) {
1700 Dhcp6Client client;
1701 // Set link local address for the client which the server will
1702 // use to decode the HW address as 38:60:77:d5:ff:ee. This
1703 // decoded address will be used to search for host reservations.
1704 client.setLinkLocal(IOAddress("fe80::3a60:77ff:fed5:ffee"));
1705 // Run the actual test.
1706 testReservationByIdentifier(client, 1, "2001:db8:1::1");
1707 }
1708
1709 // This test verifies that order in which host identifiers are used to
1710 // retrieve host reservations can be controlled.
TEST_F(HostTest,hostIdentifiersOrder)1711 TEST_F(HostTest, hostIdentifiersOrder) {
1712 Dhcp6Client client;
1713 // Set DUID matching the one used to create host reservations.
1714 client.setDUID("01:02:03:05");
1715 // Set link local address for the client which the server will
1716 // use to decode the HW address as 38:60:77:d5:ff:ee. This
1717 // decoded address will be used to search for host reservations.
1718 client.setLinkLocal(IOAddress("fe80::3a60:77ff:fed5:ffee"));
1719 testReservationByIdentifier(client, 2, "2001:db8:1::2");
1720 }
1721
1722 // This test checks that host specific options override subnet specific
1723 // and pool specific options. Overridden options are requested with Option
1724 // Request option (Information-request case).
TEST_F(HostTest,overrideRequestedOptionsInformationRequest)1725 TEST_F(HostTest, overrideRequestedOptionsInformationRequest) {
1726 testOverrideRequestedOptions(DHCPV6_INFORMATION_REQUEST);
1727 }
1728
1729 // This test checks that host specific options override subnet specific
1730 // and pool specific options. Overridden options are requested with Option
1731 // Request option (Request case).
TEST_F(HostTest,overrideRequestedOptionsRequest)1732 TEST_F(HostTest, overrideRequestedOptionsRequest) {
1733 testOverrideRequestedOptions(DHCPV6_REQUEST);
1734 }
1735
1736 // This test checks that host specific options override subnet specific
1737 // and pool specific options. Overridden options are requested with Option
1738 // Request option (Renew case).
TEST_F(HostTest,overrideRequestedOptionsRenew)1739 TEST_F(HostTest, overrideRequestedOptionsRenew) {
1740 testOverrideRequestedOptions(DHCPV6_RENEW);
1741 }
1742
1743 // This test checks that host specific options override subnet specific
1744 // and pool specific options. Overridden options are requested with Option
1745 // Request option (Rebind case).
TEST_F(HostTest,overrideRequestedOptionsRebind)1746 TEST_F(HostTest, overrideRequestedOptionsRebind) {
1747 testOverrideRequestedOptions(DHCPV6_REBIND);
1748 }
1749
1750 // This test checks that client receives options when they are
1751 // solely defined in the host scope and not in the global or subnet
1752 // scope (Information-request case).
TEST_F(HostTest,testHostOnlyOptionsInformationRequest)1753 TEST_F(HostTest, testHostOnlyOptionsInformationRequest) {
1754 testHostOnlyOptions(DHCPV6_INFORMATION_REQUEST);
1755 }
1756
1757 // This test checks that client receives options when they are
1758 // solely defined in the host scope and not in the global or subnet
1759 // scope (Request case).
TEST_F(HostTest,testHostOnlyOptionsRequest)1760 TEST_F(HostTest, testHostOnlyOptionsRequest) {
1761 testHostOnlyOptions(DHCPV6_REQUEST);
1762 }
1763
1764 // This test checks that client receives options when they are
1765 // solely defined in the host scope and not in the global or subnet
1766 // scope (Renew case).
TEST_F(HostTest,testHostOnlyOptionsRenew)1767 TEST_F(HostTest, testHostOnlyOptionsRenew) {
1768 testHostOnlyOptions(DHCPV6_RENEW);
1769 }
1770
1771 // This test checks that client receives options when they are
1772 // solely defined in the host scope and not in the global or subnet
1773 // scope (Rebind case).
TEST_F(HostTest,testHostOnlyOptionsRebind)1774 TEST_F(HostTest, testHostOnlyOptionsRebind) {
1775 testHostOnlyOptions(DHCPV6_REBIND);
1776 }
1777
1778 // This test checks that host specific vendor options override vendor
1779 // options defined in the global scope (Request case).
TEST_F(HostTest,overrideVendorOptionsRequest)1780 TEST_F(HostTest, overrideVendorOptionsRequest) {
1781 testOverrideVendorOptions(DHCPV6_REQUEST);
1782 }
1783
1784 // This test checks that host specific vendor options override vendor
1785 // options defined in the global scope (Renew case).
TEST_F(HostTest,overrideVendorOptionsRenew)1786 TEST_F(HostTest, overrideVendorOptionsRenew) {
1787 testOverrideVendorOptions(DHCPV6_RENEW);
1788 }
1789
1790 // This test checks that host specific vendor options override vendor
1791 // options defined in the global scope (Rebind case).
TEST_F(HostTest,overrideVendorOptionsRebind)1792 TEST_F(HostTest, overrideVendorOptionsRebind) {
1793 testOverrideVendorOptions(DHCPV6_REBIND);
1794 }
1795
1796 // In this test the client sends Solicit with 3 IA_NAs and 3 IA_PDs
1797 // without hints and the server should return those IAs with 3 reserved
1798 // addresses and 3 reserved prefixes.
TEST_F(HostTest,multipleIAsSolicit)1799 TEST_F(HostTest, multipleIAsSolicit) {
1800 testMultipleIAs(do_solicit_,
1801 Reservation("2001:db8:1:1::1"),
1802 Reservation("2001:db8:1:1::2"),
1803 Reservation("2001:db8:1:1::3"),
1804 Reservation("3000:1:1::/64"),
1805 Reservation("3000:1:2::/64"),
1806 Reservation("3000:1:3::/64"));
1807 }
1808
1809 // In this test the client performs 4-way exchange, sending 3 IA_NAs
1810 // and 3 IA_PDs without hints. The server should return those IAs
1811 // with 3 reserved addresses and 3 reserved prefixes.
TEST_F(HostTest,multipleIAsRequest)1812 TEST_F(HostTest, multipleIAsRequest) {
1813 testMultipleIAs(do_solicit_request_,
1814 Reservation("2001:db8:1:1::1"),
1815 Reservation("2001:db8:1:1::2"),
1816 Reservation("2001:db8:1:1::3"),
1817 Reservation("3000:1:1::/64"),
1818 Reservation("3000:1:2::/64"),
1819 Reservation("3000:1:3::/64"));
1820 }
1821
1822 // In this test the client sends Solicit with 3 IA_NAs and 3 IA_PDs
1823 // without hints. The server has 2 reservations for addresses and
1824 // 2 reservations for prefixes for this client. The server should
1825 // assign reserved addresses and prefixes to the client, and return
1826 // them in 2 IA_NAs and 2 IA_PDs. For the remaining IA_NA and IA_PD
1827 // the server should allocate address and prefix from a dynamic pools.
TEST_F(HostTest,staticAndDynamicIAs)1828 TEST_F(HostTest, staticAndDynamicIAs) {
1829 testMultipleIAs(do_solicit_,
1830 Reservation("2001:db8:1:1::2"),
1831 Reservation("2001:db8:1:1::3"),
1832 Reservation("3000:1:1::/64"),
1833 Reservation("3000:1:3::/64"));
1834 }
1835
1836 // In this test the client sends Solicit with 3 IA_NAs and 3 IA_PDs.
1837 // The client includes an address hint for IAID = 1, a prefix length
1838 // hint for the IAID = 5, and the prefix hint for IAID = 6. The hints
1839 // match the reserved resources and should be allocated for the client.
TEST_F(HostTest,multipleIAsHintsForReservations)1840 TEST_F(HostTest, multipleIAsHintsForReservations) {
1841 testMultipleIAs(do_solicit_,
1842 Reservation("2001:db8:1:1::1"),
1843 Reservation("2001:db8:1:1::2"),
1844 Reservation("2001:db8:1:1::3"),
1845 Reservation("3000:1:1::/64"),
1846 Reservation("3000:1:2::/64"),
1847 Reservation("3000:1:3::/64"),
1848 StrictIAIDChecking::NO(),
1849 Hint(IAID(1), "2001:db8:1:1::2"),
1850 Hint(IAID(5), "::/64"),
1851 Hint(IAID(6), "3000:1:1::/64"));
1852 }
1853
1854 // In this test the client sends Solicit with 3 IA_NAs and 3 IA_PDs.
1855 // The client includes one address hint for IAID = 1 and one
1856 // prefix hint for IAID = 6. The hints point to an address and prefix
1857 // from the dynamic pools, but because the server has reservations
1858 // for other addresses and prefixes outside the pool, the address
1859 // and prefix specified as hint should not be allocated. Instead
1860 // the server should allocate reserved leases.
TEST_F(HostTest,multipleIAsHintsInPool)1861 TEST_F(HostTest, multipleIAsHintsInPool) {
1862 testMultipleIAs(do_solicit_,
1863 Reservation("2001:db8:1:1::1"),
1864 Reservation("2001:db8:1:1::2"),
1865 Reservation("2001:db8:1:1::3"),
1866 Reservation("3000:1:1::/64"),
1867 Reservation("3000:1:2::/64"),
1868 Reservation("3000:1:3::/64"),
1869 StrictIAIDChecking::NO(),
1870 Hint(IAID(1), "2001:db8:1::2"),
1871 Hint(IAID(6), "3001::/64"));
1872 }
1873
1874 // In this test, the client sends Solicit with 3 IA_NAs and 3 IA_PDs.
1875 // The client includes one address hint for which the client has
1876 // reservation, one prefix hint for which the client has reservation,
1877 // one hint for an address from the dynamic pool and one hint for a
1878 // prefix from a dynamic pool. The server has reservations for 2
1879 // addresses and 2 prefixes. The server should allocate reserved
1880 // leases and address and prefix from a dynamic pool, which client
1881 // included as hints.
TEST_F(HostTest,staticAndDynamicIAsHints)1882 TEST_F(HostTest, staticAndDynamicIAsHints) {
1883 testMultipleIAs(do_solicit_,
1884 Reservation("2001:db8:1:1::1"),
1885 Reservation("2001:db8:1:1::3"),
1886 Reservation("3000:1:1::/64"),
1887 Reservation("3000:1:2::/64"),
1888 Reservation::UNSPEC(),
1889 Reservation::UNSPEC(),
1890 StrictIAIDChecking::NO(),
1891 Hint(IAID(1), "2001:db8:1::2"),
1892 Hint(IAID(3), "2001:db8:1:1::1"),
1893 Hint(IAID(5), "3001::/64"),
1894 Hint(IAID(6), "3000::/64"));
1895 }
1896
1897 // In this test, the client sends Solicit with 3 IA_NAs and 3 IA_PDs.
1898 // The server has reservation for two addresses and two prefixes for
1899 // this client. The client includes address hint in the third IA_NA
1900 // and in the third IA_PD. The server should offer 2 addresses in the
1901 // first two IA_NAs and 2 prefixes in the two IA_PDs. The server should
1902 // respect hints provided within the 3rd IA_NA and 3rd IA_PD. The server
1903 // wouldn't respect hints if they were provided within 1st or 2nd IA of
1904 // a given type, because the server always tries to allocate the
1905 // reserved leases in the first place.
TEST_F(HostTest,staticAndDynamicIAsHintsStrictIAIDCheck)1906 TEST_F(HostTest, staticAndDynamicIAsHintsStrictIAIDCheck) {
1907 testMultipleIAs(do_solicit_,
1908 Reservation("2001:db8:1:1::1"),
1909 Reservation("2001:db8:1:1::2"),
1910 Reservation("3000:1:1::/64"),
1911 Reservation("3000:1:2::/64"),
1912 Reservation::UNSPEC(),
1913 Reservation::UNSPEC(),
1914 StrictIAIDChecking::YES(),
1915 Hint(IAID(3), "2001:db8:1::5"),
1916 Hint(IAID(6), "3001:0:0:10::/64"));
1917 }
1918
1919 // In this test, the client performs 4-way exchange and includes 3 IA_NAs
1920 // and 3 IA_PDs. The client provides no hints. The server has 3 address
1921 // reservations and 3 prefix reservations for this client and allocates them
1922 // as a result of 4-way exchange. The client then sends a Renew and the server
1923 // should renew all leases allocated for the client during the 4-way exchange.
TEST_F(HostTest,multipleIAsRenew)1924 TEST_F(HostTest, multipleIAsRenew) {
1925 // 4-way exchange
1926 testMultipleIAs(do_solicit_request_,
1927 Reservation("2001:db8:1:1::1"),
1928 Reservation("2001:db8:1:1::2"),
1929 Reservation("2001:db8:1:1::3"),
1930 Reservation("3000:1:1::/64"),
1931 Reservation("3000:1:2::/64"),
1932 Reservation("3000:1:3::/64"));
1933
1934 // Renew
1935 ASSERT_NO_THROW(client_.doRenew());
1936
1937 // Make sure that the client still has the same leases.
1938 ASSERT_EQ(6, client_.getLeaseNum());
1939
1940 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::1")));
1941 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::2")));
1942 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::3")));
1943 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:1::"), 64));
1944 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:2::"), 64));
1945 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:3::"), 64));
1946 }
1947
1948 // In this test, the client performs 4-way exchange and includes 3 IA_NAs
1949 // and IA_PDs. The server has 3 address and 3 prefix reservations for the
1950 // client and allocates them all. Once the 4-way exchange is complete,
1951 // the client sends Solicit in which it specifies hints for all IAs. The
1952 // hints are for the reserved addresses but some of them are included in
1953 // different IAs than they are assigned to. The server should ignore hints
1954 // and respond with currently assigned leases.
TEST_F(HostTest,multipleIAsSolicitAfterAcquisition)1955 TEST_F(HostTest, multipleIAsSolicitAfterAcquisition) {
1956 // 4-way exchange
1957 testMultipleIAs(do_solicit_request_,
1958 Reservation("2001:db8:1:1::1"),
1959 Reservation("2001:db8:1:1::2"),
1960 Reservation("2001:db8:1:1::3"),
1961 Reservation("3000:1:1::/64"),
1962 Reservation("3000:1:2::/64"),
1963 Reservation("3000:1:3::/64"));
1964
1965 client_.clearRequestedIAs();
1966
1967 // Specify hints.
1968
1969 // "2001:db8:1:1::1" is allocated for IAID = 1 but we specify it as
1970 // a hint for IAID = 3 and so on.
1971 requestIA(client_, Hint(IAID(3), "2001:db8:1:1::1"));
1972 requestIA(client_, Hint(IAID(2), "2001:db8:1:1::2"));
1973 requestIA(client_, Hint(IAID(1), "2001:db8:1:1::3"));
1974 requestIA(client_, Hint(IAID(6), "3000:1:1::/64"));
1975 requestIA(client_, Hint(IAID(5), "3000:1:2::/64"));
1976 requestIA(client_, Hint(IAID(4), "3000:1:3::/64"));
1977
1978 // Send Solicit with hints as specified above.
1979 ASSERT_NO_THROW(do_solicit_());
1980
1981 // Make sure that the client still has the same leases and the leases
1982 // should be assigned to the same IAs.
1983 ASSERT_EQ(6, client_.getLeaseNum());
1984
1985 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::1"),
1986 IAID(1)));
1987 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::2"),
1988 IAID(2)));
1989 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::3"),
1990 IAID(3)));
1991 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:1::"), 64,
1992 IAID(4)));
1993 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:2::"), 64,
1994 IAID(5)));
1995 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:3::"), 64,
1996 IAID(6)));
1997 }
1998
1999 // In this test, the client performs 4-way exchange and includes 3 IA_NAs and
2000 // 3 IA_PDs and includes no hints. The server has reservations for 2 addresses
2001 // and 2 prefixes for this client. The server allocates reserved leases and
2002 // an additional address and prefix from the dynamic pools. The server is
2003 // reconfigured to add 3rd address and 3rd prefix reservation for the client.
2004 // The client sends a Renew and the server should renew existing leases and
2005 // allocate newly reserved address and prefix, replacing the previously
2006 // allocated dynamic leases. For both dynamically allocated leases, the
2007 // server should return IAs with zero lifetimes.
TEST_F(HostTest,appendReservationDuringRenew)2008 TEST_F(HostTest, appendReservationDuringRenew) {
2009 // 4-way exchange to acquire 4 reserved leases and 2 dynamic leases.
2010 testMultipleIAs(do_solicit_request_,
2011 Reservation("2001:db8:1:1::1"),
2012 Reservation("2001:db8:1:1::2"),
2013 Reservation("3000:1:1::/64"),
2014 Reservation("3000:1:2::/64"));
2015
2016 // The server must have not lease for the address and prefix for which
2017 // we will later make reservations, because these are outside of the
2018 // dynamic pool.
2019 ASSERT_FALSE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::3")));
2020 ASSERT_FALSE(client_.hasLeaseForPrefix(IOAddress("3000:1:3::"), 64));
2021
2022 // Retrieve leases from the dynamic pools and store them so as we can
2023 // later check that they were returned with zero lifetimes when the
2024 // reservations are added.
2025 std::vector<Lease6> leases =
2026 client_.getLeasesByAddressRange(IOAddress("2001:db8:1::1"),
2027 IOAddress("2001:db8:1::10"));
2028 ASSERT_EQ(1, leases.size());
2029 IOAddress dynamic_address_lease = leases[0].addr_;
2030
2031 leases = client_.getLeasesByPrefixPool(IOAddress("3001::"), 32, 64);
2032 ASSERT_EQ(1, leases.size());
2033 IOAddress dynamic_prefix_lease = leases[0].addr_;
2034
2035 // Add two additional reservations.
2036 std::string c = configString(*client_.getDuid(),
2037 Reservation("2001:db8:1:1::1"),
2038 Reservation("2001:db8:1:1::2"),
2039 Reservation("2001:db8:1:1::3"),
2040 Reservation("3000:1:1::/64"),
2041 Reservation("3000:1:2::/64"),
2042 Reservation("3000:1:3::/64"));
2043
2044 ASSERT_NO_THROW(configure(c, *client_.getServer()));
2045
2046 // Client renews and includes all leases it currently has in the IAs.
2047 ASSERT_NO_THROW(client_.doRenew());
2048
2049 // The expectation is that the server allocated two new reserved leases to
2050 // the client and removed leases allocated from the dynamic pools. The
2051 // number if leases in the server configuration should include those that
2052 // are returned with zero lifetimes. Hence, the total number of leases
2053 // should be equal to 6 + 2 = 8.
2054 ASSERT_EQ(8, client_.getLeaseNum());
2055
2056 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::1")));
2057 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::2")));
2058 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::3")));
2059 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:1::"), 64));
2060 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:2::"), 64));
2061 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:3::"), 64));
2062
2063 // Make sure that the replaced leases have been returned with zero lifetimes.
2064 EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForAddress(dynamic_address_lease));
2065 EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForPrefix(dynamic_prefix_lease, 64));
2066
2067 // Now let's test the scenario when all reservations are removed for this
2068 // client.
2069 c = configString(*client_.getDuid());
2070
2071 ASSERT_NO_THROW(configure(c, *client_.getServer()));
2072
2073 // An attempt to renew should result in removing all allocated leases,
2074 // because these leases are no longer reserved and they don't belong to the
2075 // dynamic pools.
2076 ASSERT_NO_THROW(client_.doRenew());
2077
2078 // The total number of leases should include removed leases and newly
2079 // allocated once, i.e. 6 + 6 = 12.
2080 ASSERT_EQ(12, client_.getLeaseNum());
2081
2082 // All removed leases should be returned with zero lifetimes.
2083 EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1:1::1")));
2084 EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1:1::2")));
2085 EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1:1::3")));
2086 EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForPrefix(IOAddress("3000:1:1::"), 64));
2087 EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForPrefix(IOAddress("3000:1:2::"), 64));
2088 EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForPrefix(IOAddress("3000:1:3::"), 64));
2089
2090 // Make sure that all address leases are within the dynamic pool range.
2091 leases = client_.getLeasesByAddressRange(IOAddress("2001:db8:1::1"),
2092 IOAddress("2001:db8:1::10"));
2093 EXPECT_EQ(3, leases.size());
2094
2095 // Make sure that all prefix leases are also within the dynamic pool range.
2096 leases = client_.getLeasesByPrefixPool(IOAddress("3001::"), 32, 64);
2097 EXPECT_EQ(3, leases.size());
2098 }
2099
2100 // In this test, the client performs 4-way exchange and includes 3 IA_NAs
2101 // and 3 IA_PDs. Initially, the server has 2 address reservations and
2102 // 2 prefix reservations for this client. The server allocates the 2
2103 // reserved addresses to the first 2 IA_NAs and 2 reserved prefixes to the
2104 // first two IA_PDs. The server is reconfigured and 2 new reservations are
2105 // inserted: new address reservation before existing address reservations
2106 // and prefix reservation before existing prefix reservations.
2107 // The server should detect that leases already exist for reserved addresses
2108 // and prefixes and it should not remove existing leases. Instead, it should
2109 // replace dynamically allocated leases with newly added reservations
TEST_F(HostTest,insertReservationDuringRenew)2110 TEST_F(HostTest, insertReservationDuringRenew) {
2111 // 4-way exchange to acquire 4 reserved leases and 2 dynamic leases.
2112 testMultipleIAs(do_solicit_request_,
2113 Reservation("2001:db8:1:1::1"),
2114 Reservation("2001:db8:1:1::2"),
2115 Reservation("3000:1:1::/64"),
2116 Reservation("3000:1:2::/64"));
2117
2118 // The server must have not lease for the address and prefix for which
2119 // we will later make reservations, because these are outside of the
2120 // dynamic pool.
2121 ASSERT_FALSE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::3")));
2122 ASSERT_FALSE(client_.hasLeaseForPrefix(IOAddress("3000:1:3::"), 64));
2123
2124 // Retrieve leases from the dynamic pools and store them so as we can
2125 // later check that they were returned with zero lifetimes when the
2126 // reservations are added.
2127 std::vector<Lease6> leases =
2128 client_.getLeasesByAddressRange(IOAddress("2001:db8:1::1"),
2129 IOAddress("2001:db8:1::10"));
2130 ASSERT_EQ(1, leases.size());
2131 IOAddress dynamic_address_lease = leases[0].addr_;
2132
2133 leases = client_.getLeasesByPrefixPool(IOAddress("3001::"), 32, 64);
2134 ASSERT_EQ(1, leases.size());
2135 IOAddress dynamic_prefix_lease = leases[0].addr_;
2136
2137 // Add two additional reservations.
2138 std::string c = configString(*client_.getDuid(),
2139 Reservation("2001:db8:1:1::3"),
2140 Reservation("2001:db8:1:1::1"),
2141 Reservation("2001:db8:1:1::2"),
2142 Reservation("3000:1:3::/64"),
2143 Reservation("3000:1:1::/64"),
2144 Reservation("3000:1:2::/64"));
2145
2146 ASSERT_NO_THROW(configure(c, *client_.getServer()));
2147
2148 // Client renews and includes all leases it currently has in the IAs.
2149 ASSERT_NO_THROW(client_.doRenew());
2150
2151 // The expectation is that the server allocated two new reserved leases to
2152 // the client and removed leases allocated from the dynamic pools. The
2153 // number if leases in the server configuration should include those that
2154 // are returned with zero lifetimes. Hence, the total number of leases
2155 // should be equal to 6 + 2 = 8.
2156 ASSERT_EQ(8, client_.getLeaseNum());
2157
2158 // Even though the new reservations have been added before existing
2159 // reservations, the server should assign them to the IAs with
2160 // IAID = 3 (for address) and IAID = 6 (for prefix).
2161 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::1"),
2162 IAID(1)));
2163 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::2"),
2164 IAID(2)));
2165 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::3"),
2166 IAID(3)));
2167 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:1::"), 64,
2168 IAID(4)));
2169 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:2::"), 64,
2170 IAID(5)));
2171 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:3::"), 64,
2172 IAID(6)));
2173
2174 // Make sure that the replaced leases have been returned with zero lifetimes.
2175 EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForAddress(dynamic_address_lease));
2176 EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForPrefix(dynamic_prefix_lease, 64));
2177 }
2178
2179 // In this test there are two clients. One client obtains two leases: one
2180 // for a prefix, another one for an address. The server is reconfigured
2181 // to make 4 reservations to a different client. Two of those reservations
2182 // are for the prefix and the address assigned to the first client. The
2183 // second client performs 4-way exchange and the server detects that two
2184 // reserved leases are not available because they are in use by another
2185 // client. The server assigns available address and prefix and an address
2186 // and prefix from dynamic pool. The first client renews and the server
2187 // detects that the renewed leases are reserved for another client. As
2188 // a result, the client obtains an address and prefix from the dynamic
2189 // pools. The second client renews and it obtains all reserved
2190 // addresses and prefixes.
TEST_F(HostTest,multipleIAsConflict)2191 TEST_F(HostTest, multipleIAsConflict) {
2192 Dhcp6Client client;
2193 client.setDUID("01:02:03:05");
2194
2195 // Create configuration without any reservations.
2196 std::string c = configString(*client_.getDuid());
2197
2198 ASSERT_NO_THROW(configure(c, *client_.getServer()));
2199
2200 // First client performs 4-way exchange and obtains an address and
2201 // prefix indicated in hints.
2202 requestIA(client, Hint(IAID(1), "2001:db8:1::1"));
2203 requestIA(client, Hint(IAID(2), "3001:0:0:10::/64"));
2204
2205 ASSERT_NO_THROW(client.doSARR());
2206
2207 // Make sure the client has obtained requested leases.
2208 ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:1::1"), IAID(1)));
2209 ASSERT_TRUE(client.hasLeaseForPrefix(IOAddress("3001:0:0:10::"), 64,
2210 IAID(2)));
2211
2212 // Reconfigure the server to make reservations for the second client.
2213 // The reservations include a prefix and address acquired by the
2214 // first client in the previous transaction.
2215 c = configString(*client_.getDuid(),
2216 Reservation("2001:db8:1::1"),
2217 Reservation("2001:db8:1::2"),
2218 Reservation("3001:0:0:9::/64"),
2219 Reservation("3001:0:0:10::/64"));
2220
2221 ASSERT_NO_THROW(configure(c, *client_.getServer()));
2222
2223 // Configure the second client to send two IA_NAs and two IA_PDs with
2224 // IAIDs from 1 to 4.
2225 client_.requestAddress(1);
2226 client_.requestAddress(2);
2227 client_.requestPrefix(3);
2228 client_.requestPrefix(4);
2229
2230 // Perform 4-way exchange.
2231 ASSERT_NO_THROW(do_solicit_request_());
2232
2233 // The client should have obtained 4 leases: two prefixes and two addresses.
2234 ASSERT_EQ(4, client_.getLeaseNum());
2235
2236 // The address "2001:db8:1::2" is reserved and available so the
2237 // server should have assigned it.
2238 ASSERT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1::2"),
2239 IAID(1)));
2240 // The address "2001:db8:1::1" was hijacked by another client so it
2241 // must not be assigned to this client.
2242 ASSERT_FALSE(client_.hasLeaseForAddress(IOAddress("2001:db8:1::1")));
2243 // This client should have got an address from the dynamic pool excluding
2244 // two addresses already assigned, i.e. excluding "2001:db8:1::1" and
2245 // "2001:db8:1::2".
2246 ASSERT_TRUE(client_.hasLeaseForAddressRange(IOAddress("2001:db8:1::3"),
2247 IOAddress("2001:db8:1::10")));
2248
2249 // Same story with prefixes.
2250 ASSERT_TRUE(client_.hasLeaseForPrefix(IOAddress("3001:0:0:9::"), 64,
2251 IAID(3)));
2252 ASSERT_FALSE(client_.hasLeaseForPrefix(IOAddress("3001:0:0:10::"), 64));
2253
2254
2255 // Now that the reservations have been made, the first client should get
2256 // non-reserved leases upon renewal. The server detects that the leases
2257 // are reserved for someone else.
2258 ASSERT_NO_THROW(client.doRenew());
2259
2260 // For those leases, the first client should get 0 lifetimes.
2261 ASSERT_TRUE(client.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1::1")));
2262 ASSERT_TRUE(client.hasLeaseWithZeroLifetimeForPrefix(IOAddress("3001:0:0:10::"), 64));
2263
2264 // The total number of leases should be 4 - two leases with zero lifetimes
2265 // and two leases with address and prefix from the dynamic pools, which
2266 // replace previously assigned leases. We don't care too much what those
2267 // leases are, though.
2268 EXPECT_EQ(4, client.getLeaseNum());
2269
2270 // The second client renews and the server should be now able to assign
2271 // all reserved leases to this client.
2272 ASSERT_NO_THROW(client_.doRenew());
2273
2274 // Client requests 4 leases, but there are additional two with zero
2275 // lifetimes to indicate that the client should not use the address
2276 // and prefix from the dynamic pools anymore.
2277 ASSERT_EQ(6, client_.getLeaseNum());
2278
2279 // Check that the client has all reserved leases.
2280 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1::2"),
2281 IAID(1)));
2282 EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1::1"),
2283 IAID(2)));
2284
2285 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3001:0:0:9::"), 64,
2286 IAID(3)));
2287 EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3001:0:0:10::"), 64,
2288 IAID(4)));
2289 }
2290
2291 // This test verifies a scenario in which a client trying to renew a
2292 // lease is refused this lease because it has been reserved to another
2293 // client. The client is assigned another available lease from a
2294 // dynamic pool by reusing an expired lease.
TEST_F(HostTest,conflictResolutionReuseExpired)2295 TEST_F(HostTest, conflictResolutionReuseExpired) {
2296 Dhcp6Client client1;
2297
2298 ASSERT_NO_THROW(configure(CONFIGS[6], *client1.getServer()));
2299
2300 // First client performs 4-way exchange and obtains an address and
2301 // prefix indicated in hints.
2302 requestIA(client1, Hint(IAID(1), "2001:db8:1::1"));
2303 requestIA(client1, Hint(IAID(2), "3000::/120"));
2304
2305 ASSERT_NO_THROW(client1.doSARR());
2306
2307 // Make sure the client has obtained requested leases.
2308 ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::1"), IAID(1)));
2309 ASSERT_TRUE(client1.hasLeaseForPrefix(IOAddress("3000::"), 120));
2310
2311 // Create another client which is assigned another lease.
2312 Dhcp6Client client2(client1.getServer());
2313
2314 // Second client performs 4-way exchange and obtains an address and
2315 // prefix indicated in hints.
2316 requestIA(client2, Hint(IAID(1), "2001:db8:1::2"));
2317 requestIA(client2, Hint(IAID(2), "3000::100/120"));
2318
2319 ASSERT_NO_THROW(client2.doSARR());
2320
2321 // Make sure the client has obtained requested leases.
2322 ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::2"), IAID(1)));
2323 ASSERT_TRUE(client2.hasLeaseForPrefix(IOAddress("3000::100"), 120));
2324
2325 // Fast forward time to simulate aging of leases. After that, both leases are
2326 // expired because their valid lifetime is 40s. The second argument indicates
2327 // that the leases should also be updated on the server.
2328 client1.fastFwdTime(60, true);
2329 client2.fastFwdTime(60, true);
2330
2331 // Reconfigure the server, so as the address 2001:db8:1::2 and prefix
2332 // 3000::10/120 is now reserved for another client.
2333 ASSERT_NO_THROW(configure(CONFIGS[7], *client1.getServer()));
2334
2335 client1.clearRequestedIAs();
2336 client2.clearRequestedIAs();
2337
2338 // Try to renew the address of 2001:db8:1::2 and prefix 3000::100/120.
2339 ASSERT_NO_THROW(client2.doRenew());
2340
2341 // The renewed address and prefix are now reserved for another client so
2342 // available leases should be allocated instead.
2343 EXPECT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::1")));
2344 EXPECT_TRUE(client2.hasLeaseForPrefix(IOAddress("3000::"), 120));
2345 // The previously allocated leases should now be returned with zero lifetimes.
2346 EXPECT_TRUE(client2.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1::2")));
2347 EXPECT_TRUE(client2.hasLeaseWithZeroLifetimeForPrefix(IOAddress("3000::100"), 120));
2348
2349 // We've had a bug in DHCPv6 server that reused lease (allocated previously to
2350 // a different client) was returned to the client reusing leases. This a big issue
2351 // because effectively a client reusing an expired lease would get this lease twice:
2352 // with non-zero lifetimes and the second time with zero lifetimes. This is seriously
2353 // confusing for the clients. This checks tha the bug has been eliminated.
2354 EXPECT_FALSE(client2.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1::1")));
2355 EXPECT_FALSE(client2.hasLeaseWithZeroLifetimeForPrefix(IOAddress("3000::"), 120));
2356 }
2357
2358 // Verifies fundamental Global vs Subnet host reservations for NA leases
TEST_F(HostTest,globalReservationsNA)2359 TEST_F(HostTest, globalReservationsNA) {
2360 Dhcp6Client client;
2361 ASSERT_NO_FATAL_FAILURE(configure(CONFIGS[8], *client.getServer()));
2362
2363 const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
2364 getCfgSubnets6()->getAll();
2365 ASSERT_EQ(2, subnets->size());
2366
2367 {
2368 SCOPED_TRACE("Global HR by DUID with reserved address");
2369 client.setDUID("01:02:03:04");
2370 client.requestAddress(1234, IOAddress("::"));
2371 // Should get global reserved address and reserved host name
2372 ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3001::1", "duid-host-fixed"));
2373 }
2374
2375 {
2376 SCOPED_TRACE("Global HR by DUID with dynamic address");
2377 client.clearConfig();
2378 client.setDUID("01:02:03:05");
2379 client.requestAddress(1234, IOAddress("::"));
2380 // Should get dynamic address and reserved host name
2381 ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:1::", "duid-host-dynamic"));
2382 }
2383
2384 {
2385 SCOPED_TRACE("Global HR by HW Address with dynamic address");
2386 client.clearConfig();
2387 client.setDUID("33:44:55:66");
2388 client.setLinkLocal(IOAddress("fe80::3a60:77ff:fed5:ffee"));
2389 client.requestAddress(1234, IOAddress("::"));
2390 // Should get dynamic address and hardware host name
2391 ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:1::1", "hw-host"));
2392 }
2393
2394 {
2395 SCOPED_TRACE("Default subnet reservations flags excludes global reservations");
2396 client.clearConfig();
2397 client.setInterface("eth1");
2398 client.setDUID("01:02:03:04");
2399 client.requestAddress(1234, IOAddress("::"));
2400 // Should get dynamic address and no host name
2401 ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:2::", ""));
2402 }
2403
2404 {
2405 SCOPED_TRACE("Subnet reservation over global");
2406 client.clearConfig();
2407 client.setInterface("eth1");
2408 client.setDUID("01:02:03:05");
2409 client.requestAddress(1234, IOAddress("::"));
2410 // Should get dynamic address and host name
2411 ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:2::1", "subnet-duid-host"));
2412 }
2413
2414 {
2415 SCOPED_TRACE("Subnet reservation preferred over global");
2416 // Patch the second subnet to both global and in-subnet.
2417 Subnet6Ptr subnet = CfgMgr::instance().getCurrentCfg()->
2418 getCfgSubnets6()->getSubnet(2);
2419 ASSERT_TRUE(subnet);
2420 subnet->setReservationsGlobal(true);
2421 subnet->setReservationsInSubnet(true);
2422 client.clearConfig();
2423 client.setInterface("eth1");
2424 client.setDUID("01:02:03:05");
2425 client.requestAddress(1234, IOAddress("::"));
2426 // Should get dynamic address and host name because it has preference
2427 ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:2::1", "subnet-duid-host"));
2428 }
2429 }
2430
2431 // Verifies fundamental Global vs Subnet host reservations for PD leases
TEST_F(HostTest,globalReservationsPD)2432 TEST_F(HostTest, globalReservationsPD) {
2433 Dhcp6Client client;
2434 ASSERT_NO_FATAL_FAILURE(configure(CONFIGS[9], *client.getServer()));
2435
2436 const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
2437 getCfgSubnets6()->getAll();
2438 ASSERT_EQ(2, subnets->size());
2439
2440 {
2441 SCOPED_TRACE("Global HR by DUID with reserved prefix");
2442 client.setDUID("01:02:03:04");
2443 client.requestPrefix(1);
2444 // Should get global reserved prefix and reserved host name
2445 ASSERT_NO_FATAL_FAILURE(sarrTest(client, "4000::100", "duid-host-fixed"));
2446 }
2447
2448 {
2449 SCOPED_TRACE("Global HR by DUID with dynamic prefix");
2450 client.clearConfig();
2451 client.setDUID("01:02:03:05");
2452 client.requestPrefix(1);
2453 // Should get dynamic prefix and reserved host name
2454 ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3000::", "duid-host-dynamic"));
2455 }
2456
2457 {
2458 SCOPED_TRACE("Default subnet reservations flags excludes global reservations");
2459 client.clearConfig();
2460 client.setInterface("eth1");
2461 client.setDUID("01:02:03:04");
2462 client.requestPrefix(1);
2463 // Should get dynamic prefix and no host name
2464 ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3001::", ""));
2465 }
2466
2467 {
2468 SCOPED_TRACE("Subnet reservation over global");
2469 client.clearConfig();
2470 client.setInterface("eth1");
2471 client.setDUID("01:02:03:05");
2472 client.requestPrefix(1);
2473 // Should get dynamic prefix and subnet reserved host name
2474 ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3001::100", "subnet-duid-host"));
2475 }
2476
2477 {
2478 SCOPED_TRACE("Subnet reservation preferred over global");
2479 // Patch the second subnet to both global and in-subnet.
2480 Subnet6Ptr subnet = CfgMgr::instance().getCurrentCfg()->
2481 getCfgSubnets6()->getSubnet(2);
2482 ASSERT_TRUE(subnet);
2483 subnet->setReservationsGlobal(true);
2484 subnet->setReservationsInSubnet(true);
2485 client.clearConfig();
2486 client.setInterface("eth1");
2487 client.setDUID("01:02:03:05");
2488 client.requestPrefix(1);
2489 // Should get dynamic prefix and subnet reserved host name
2490 // because it has preference over the global reservation.
2491 ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3001::100", "subnet-duid-host"));
2492 }
2493 }
2494
2495 // Verifies that client class specified in the global reservation
2496 // may be used to influence pool selection.
TEST_F(HostTest,clientClassGlobalPoolSelection)2497 TEST_F(HostTest, clientClassGlobalPoolSelection) {
2498 ASSERT_NO_FATAL_FAILURE(testGlobalClassSubnetPoolSelection(10));
2499 }
2500
2501 // Verifies that client class specified in the global reservation
2502 // may be used to influence subnet selection within shared network.
TEST_F(HostTest,clientClassGlobalSubnetSelection)2503 TEST_F(HostTest, clientClassGlobalSubnetSelection) {
2504 ASSERT_NO_FATAL_FAILURE(testGlobalClassSubnetPoolSelection(11));
2505 }
2506
2507 // Verifies that client class specified in the reservation may be
2508 // used to influence pool selection within a subnet.
TEST_F(HostTest,clientClassPoolSelection)2509 TEST_F(HostTest, clientClassPoolSelection) {
2510 ASSERT_NO_FATAL_FAILURE(testGlobalClassSubnetPoolSelection(12, "2001:db8:1::10",
2511 "2001:db8:1::20"));
2512 }
2513
2514 // Verifies that if the server is configured to allow for specifying
2515 // multiple reservations for the same IP address the first client
2516 // matching the reservation will be given this address. The second
2517 // client will be given a different lease.
TEST_F(HostTest,firstClientGetsReservedAddress)2518 TEST_F(HostTest, firstClientGetsReservedAddress) {
2519 // Create a client which has DUID matching the reservation.
2520 Dhcp6Client client1;
2521 client1.setDUID("01:02:03:04");
2522 ASSERT_NO_THROW(configure(CONFIGS[13], *client1.getServer()));
2523 // client1 performs 4-way exchange to get the reserved lease.
2524 requestIA(client1, Hint(IAID(1), "2001:db8:1::10"));
2525 ASSERT_NO_THROW(client1.doSARR());
2526
2527 // Make sure the client has obtained reserved lease.
2528 ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
2529
2530 // Create another client that has a reservation for the same
2531 // IP address.
2532 Dhcp6Client client2(client1.getServer());
2533 client2.setDUID("01:02:03:05");
2534 requestIA(client2, Hint(IAID(1), "2001:db8:1::10"));
2535
2536 // client2 performs 4-way exchange.
2537 ASSERT_NO_THROW(client2.doSARR());
2538
2539 // Make sure the client didn't get the reserved lease. This lease has been
2540 // already taken by the client1.
2541 EXPECT_FALSE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
2542
2543 // Make sure the client2 got a lease from the configured pool.
2544 auto leases = client2.getLeasesByAddressRange(IOAddress("2001:db8:1::10"),
2545 IOAddress("2001:db8:1::200"));
2546 EXPECT_EQ(1, leases.size());
2547
2548 // Verify that the client1 can renew the lease.
2549 ASSERT_NO_THROW(client1.doRenew());
2550 EXPECT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
2551
2552 // The client2 should also renew the lease.
2553 ASSERT_NO_THROW(client2.doRenew());
2554 EXPECT_FALSE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
2555 leases = client2.getLeasesByAddressRange(IOAddress("2001:db8:1::10"),
2556 IOAddress("2001:db8:1::200"));
2557 EXPECT_EQ(1, leases.size());
2558
2559 // If the client1 releases the reserved lease, the client2 should acquire it.
2560 ASSERT_NO_THROW(client1.doRelease());
2561 ASSERT_NO_THROW(client2.doRenew());
2562 EXPECT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
2563 }
2564
2565 // Verifies that if the server is configured to allow for specifying
2566 // multiple reservations for the same delegated prefix the first client
2567 // matching the reservation will be given this prefix. The second
2568 // client will be given a different lease.
TEST_F(HostTest,firstClientGetsReservedPrefix)2569 TEST_F(HostTest, firstClientGetsReservedPrefix) {
2570 // Create a client which has DUID matching the reservation.
2571 Dhcp6Client client1;
2572 client1.setDUID("01:02:03:04");
2573 ASSERT_NO_THROW(configure(CONFIGS[14], *client1.getServer()));
2574 // client1 performs 4-way exchange to get the reserved lease.
2575 client1.requestPrefix(1);
2576 ASSERT_NO_THROW(client1.doSARR());
2577
2578 // Make sure the client has obtained reserved lease.
2579 ASSERT_TRUE(client1.hasLeaseForPrefix(IOAddress("3000::5a:0"), 112, IAID(1)));
2580
2581 // Create another client that has a reservation for the same
2582 // IP address.
2583 Dhcp6Client client2(client1.getServer());
2584 client2.setDUID("01:02:03:05");
2585 client2.requestPrefix(1);
2586
2587 // client2 performs 4-way exchange.
2588 ASSERT_NO_THROW(client2.doSARR());
2589
2590 // Make sure the client didn't get the reserved lease. This lease has been
2591 // already taken by the client1.
2592 EXPECT_FALSE(client2.hasLeaseForPrefix(IOAddress("3000::5a:0"), 112, IAID(1)));
2593
2594 // Make sure the client2 got a lease from the configured pool.
2595 EXPECT_TRUE(client2.hasLeaseForPrefixPool(IOAddress("3000::"), 64, 112));
2596
2597 // Verify that the client1 can renew the lease.
2598 ASSERT_NO_THROW(client1.doRenew());
2599 EXPECT_TRUE(client1.hasLeaseForPrefix(IOAddress("3000::5a:0"), 112, IAID(1)));
2600
2601 // The client2 should also renew the lease.
2602 ASSERT_NO_THROW(client2.doRenew());
2603 EXPECT_TRUE(client2.hasLeaseForPrefixPool(IOAddress("3000::"), 64, 112));
2604
2605 // If the client1 releases the reserved lease, the client2 should acquire it.
2606 ASSERT_NO_THROW(client1.doRelease());
2607 ASSERT_NO_THROW(client2.doRenew());
2608 EXPECT_TRUE(client2.hasLeaseForPrefix(IOAddress("3000::5a:0"), 112, IAID(1)));
2609 }
2610
2611 /// This test verifies the case when two clients have reservations for
2612 /// the same IP address. The first client sends Solicit and is offered
2613 /// the reserved address. At the same time, the second client having
2614 /// the reservation for the same IP address performs 4-way exchange
2615 /// using the reserved address as a hint in Solicit.
2616 /// The client gets the lease for this address. This test verifies
2617 /// that the allocation engine correctly identifies that the second
2618 /// client has a reservation for this address.
TEST_F(HostTest,multipleClientsRace1)2619 TEST_F(HostTest, multipleClientsRace1) {
2620 ASSERT_NO_FATAL_FAILURE(testMultipleClientsRace("01:02:03:04", "01:02:03:05"));
2621 }
2622
2623 // This is a second variant of the multipleClientsRace1. The test is almost
2624 // the same but the client matching the second reservation sends Solicit
2625 // first and then the client having the first reservation performs 4-way
2626 // exchange. This is to ensure that the order in which reservations are
2627 // defined does not matter.
TEST_F(HostTest,multipleClientsRace2)2628 TEST_F(HostTest, multipleClientsRace2) {
2629 ASSERT_NO_FATAL_FAILURE(testMultipleClientsRace("01:02:03:05", "01:02:03:04"));
2630 }
2631
2632 } // end of anonymous namespace
2633