1 // Copyright (C) 2012-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 
9 #include <dhcp/duid.h>
10 #include <dhcp/dhcp4.h>
11 #include <dhcp/dhcp6.h>
12 #include <dhcp/pkt4.h>
13 #include <dhcp/pkt6.h>
14 #include <dhcpsrv/host_mgr.h>
15 #include <dhcpsrv/lease_mgr.h>
16 #include <dhcpsrv/memfile_lease_mgr.h>
17 #include <hooks/hooks_manager.h>
18 #include <hooks/callout_handle.h>
19 #include <stats/stats_mgr.h>
20 
21 #include <dhcpsrv/testutils/test_utils.h>
22 #include <dhcpsrv/tests/alloc_engine_utils.h>
23 
24 #include <boost/shared_ptr.hpp>
25 #include <boost/scoped_ptr.hpp>
26 
27 #include <iostream>
28 #include <sstream>
29 #include <algorithm>
30 #include <set>
31 #include <time.h>
32 
33 using namespace std;
34 using namespace isc::hooks;
35 using namespace isc::asiolink;
36 using namespace isc::stats;
37 
38 namespace isc {
39 namespace dhcp {
40 namespace test {
41 
testStatistics(const std::string & stat_name,const int64_t exp_value,const SubnetID subnet_id)42 bool testStatistics(const std::string& stat_name, const int64_t exp_value,
43                     const SubnetID subnet_id) {
44     try {
45         std::string name = (subnet_id == SUBNET_ID_UNUSED ? stat_name :
46                             StatsMgr::generateName("subnet", subnet_id, stat_name));
47         ObservationPtr observation = StatsMgr::instance().getObservation(name);
48         if (observation) {
49             if (observation->getInteger().first != exp_value) {
50                 ADD_FAILURE()
51                     << "value of the observed statistics '"
52                     << name << "' ("
53                     << observation->getInteger().first << ") "
54                     << "doesn't match expected value (" << exp_value << ")";
55             }
56             return (observation->getInteger().first == exp_value);
57         } else {
58             ADD_FAILURE() << "Expected statistic " << name
59                           << " not found.";
60         }
61 
62     } catch (...) {
63         ;
64     }
65     return (false);
66 }
67 
getStatistics(const std::string & stat_name,const SubnetID subnet_id)68 int64_t getStatistics(const std::string& stat_name, const SubnetID subnet_id) {
69     try {
70         std::string name = (subnet_id == SUBNET_ID_UNUSED ? stat_name :
71                             StatsMgr::generateName("subnet", subnet_id, stat_name));
72         ObservationPtr observation = StatsMgr::instance().getObservation(name);
73         if (observation) {
74             return (observation->getInteger().first);
75         }
76     } catch (...) {
77         ;
78     }
79     return (0);
80 }
81 
82 void
testReuseLease4(const AllocEnginePtr & engine,Lease4Ptr & existing_lease,const std::string & addr,const bool fake_allocation,ExpectedResult exp_result,Lease4Ptr & result)83 AllocEngine4Test::testReuseLease4(const AllocEnginePtr& engine,
84                                   Lease4Ptr& existing_lease,
85                                   const std::string& addr,
86                                   const bool fake_allocation,
87                                   ExpectedResult exp_result,
88                                   Lease4Ptr& result) {
89     ASSERT_TRUE(engine);
90 
91     if (existing_lease) {
92         // If an existing lease was specified, we need to add it to the
93         // database. Let's wipe any leases for that address (if any). We
94         // ignore any errors (previous lease may not exist)
95         (void) LeaseMgrFactory::instance().deleteLease(existing_lease);
96 
97         // Let's add it.
98         ASSERT_TRUE(LeaseMgrFactory::instance().addLease(existing_lease));
99     }
100 
101     // A client comes along, asking specifically for a given address
102     AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_,
103                                     IOAddress(addr), false, false,
104                                     "", fake_allocation);
105     if (fake_allocation) {
106         ctx.query_.reset(new Pkt4(DHCPDISCOVER, 1234));
107     } else {
108         ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
109     }
110     result = engine->allocateLease4(ctx);
111 
112     switch (exp_result) {
113     case SHOULD_PASS:
114         ASSERT_TRUE(result);
115 
116         checkLease4(result);
117         break;
118 
119     case SHOULD_FAIL:
120         ASSERT_FALSE(result);
121         break;
122     }
123 }
124 
125 Lease4Ptr
generateDeclinedLease(const std::string & addr,time_t probation_period,int32_t expired)126 AllocEngine4Test::generateDeclinedLease(const std::string& addr,
127                                         time_t probation_period,
128                                         int32_t expired) {
129     // There's an assumption that hardware address is always present for IPv4
130     // packet (always non-null). Client-id is optional (may be null).
131     HWAddrPtr hwaddr(new HWAddr());
132     time_t now = time(NULL);
133     Lease4Ptr declined(new Lease4(addr, hwaddr, ClientIdPtr(), 495,
134                                   now, subnet_->getID()));
135     declined->decline(probation_period);
136     declined->cltt_ = now - probation_period + expired;
137     return (declined);
138 }
139 
AllocEngine6Test()140 AllocEngine6Test::AllocEngine6Test() {
141     CfgMgr::instance().clear();
142 
143     // This lease mgr needs to exist to before configuration commits.
144     factory_.create("type=memfile universe=6 persist=false");
145 
146     duid_ = DuidPtr(new DUID(std::vector<uint8_t>(8, 0x42)));
147     iaid_ = 42;
148 
149     // Create fresh instance of the HostMgr, and drop any previous HostMgr state.
150     HostMgr::instance().create();
151 
152     // Let's use odd hardware type to check if there is no Ethernet
153     // hardcoded anywhere.
154     const uint8_t mac[] = { 0, 1, 22, 33, 44, 55};
155     hwaddr_ = HWAddrPtr(new HWAddr(mac, sizeof(mac), HTYPE_FDDI));
156     // Initialize a subnet and short address pool.
157     initSubnet(IOAddress("2001:db8:1::"),
158                IOAddress("2001:db8:1::10"),
159                IOAddress("2001:db8:1::20"),
160                IOAddress("2001:db8:1:2::"),
161                64, 80);
162 
163     initFqdn("", false, false);
164 
165     StatsMgr::instance().resetAll();
166 }
167 
168 void
initSubnet(const asiolink::IOAddress & subnet,const asiolink::IOAddress & pool_start,const asiolink::IOAddress & pool_end,const asiolink::IOAddress & pd_pool_prefix,const uint8_t pd_pool_length,const uint8_t pd_delegated_length)169 AllocEngine6Test::initSubnet(const asiolink::IOAddress& subnet,
170                              const asiolink::IOAddress& pool_start,
171                              const asiolink::IOAddress& pool_end,
172                              const asiolink::IOAddress& pd_pool_prefix,
173                              const uint8_t pd_pool_length,
174                              const uint8_t pd_delegated_length) {
175     CfgMgr& cfg_mgr = CfgMgr::instance();
176 
177     subnet_ = Subnet6Ptr(new Subnet6(subnet, 56, 100, 200, 300, 400));
178     pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, pool_start, pool_end));
179 
180     subnet_->addPool(pool_);
181 
182     if (!pd_pool_prefix.isV6Zero()) {
183         pd_pool_ = Pool6Ptr(new Pool6(Lease::TYPE_PD, pd_pool_prefix,
184                                       pd_pool_length, pd_delegated_length));
185     }
186     subnet_->addPool(pd_pool_);
187 
188     cfg_mgr.getStagingCfg()->getCfgSubnets6()->add(subnet_);
189     cfg_mgr.commit();
190 }
191 
192 void
findReservation(AllocEngine & engine,AllocEngine::ClientContext6 & ctx)193 AllocEngine6Test::findReservation(AllocEngine& engine,
194     AllocEngine::ClientContext6& ctx) {
195     engine.findReservation(ctx);
196     // Let's check whether there's a hostname specified in the reservation
197     if (ctx.currentHost()) {
198         std::string hostname = ctx.currentHost()->getHostname();
199         // If there is, let's use it
200         if (!hostname.empty()) {
201             ctx.hostname_ = hostname;
202         }
203     }
204 }
205 
206 HostPtr
createHost6HWAddr(bool add_to_host_mgr,IPv6Resrv::Type type,HWAddrPtr & hwaddr,const asiolink::IOAddress & addr,uint8_t prefix_len)207 AllocEngine6Test::createHost6HWAddr(bool add_to_host_mgr, IPv6Resrv::Type type,
208                                     HWAddrPtr& hwaddr, const asiolink::IOAddress& addr,
209                                     uint8_t prefix_len) {
210     HostPtr host(new Host(&hwaddr->hwaddr_[0], hwaddr->hwaddr_.size(),
211                           Host::IDENT_HWADDR, SUBNET_ID_UNUSED, subnet_->getID(),
212                           asiolink::IOAddress("0.0.0.0")));
213     IPv6Resrv resv(type, addr, prefix_len);
214     host->addReservation(resv);
215 
216     if (add_to_host_mgr) {
217         CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
218         CfgMgr::instance().commit();
219     }
220     return (host);
221 }
222 
223 Lease6Collection
allocateTest(AllocEngine & engine,const Pool6Ptr & pool,const asiolink::IOAddress & hint,bool fake,bool in_pool)224 AllocEngine6Test::allocateTest(AllocEngine& engine, const Pool6Ptr& pool,
225                                const asiolink::IOAddress& hint, bool fake,
226                                bool in_pool) {
227     Lease::Type type = pool->getType();
228     uint8_t expected_len = pool->getLength();
229 
230     Pkt6Ptr query(new Pkt6(fake ? DHCPV6_SOLICIT : DHCPV6_REQUEST, 1234));
231 
232     AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "",
233                                     fake, query);
234     ctx.currentIA().iaid_ = iaid_;
235     ctx.currentIA().type_ = type;
236     ctx.currentIA().addHint(hint);
237 
238     Lease6Collection leases;
239 
240     findReservation(engine, ctx);
241     EXPECT_NO_THROW(leases = engine.allocateLeases6(ctx));
242 
243     for (Lease6Collection::iterator it = leases.begin(); it != leases.end(); ++it) {
244 
245         // Do all checks on the lease
246         checkLease6(duid_, *it, type, expected_len, in_pool, in_pool);
247 
248         // Check that context has been updated with allocated addresses or
249         // prefixes.
250         checkAllocatedResources(*it, ctx);
251 
252         // Check that the lease is indeed in LeaseMgr
253         Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(type,
254                                                                    (*it)->addr_);
255         if (!fake) {
256             // This is a real (REQUEST) allocation, the lease must be in the DB
257             EXPECT_TRUE(from_mgr) << "Lease " << from_mgr->addr_.toText()
258                                   << " returned by allocateLeases6(), "
259                                   << "but was not present in LeaseMgr";
260             if (!from_mgr) {
261                 return (leases);
262             }
263 
264             // Now check that the lease in LeaseMgr has the same parameters
265             detailCompareLease(*it, from_mgr);
266         } else {
267             // This is a fake (SOLICIT) allocation, the lease must not be in DB
268             EXPECT_FALSE(from_mgr) << "Lease " << from_mgr->addr_.toText()
269                                    << " returned by allocateLeases6(), "
270                                    << "was present in LeaseMgr (expected to be"
271                                    << " not present)";
272             if (from_mgr) {
273                 return (leases);
274             }
275         }
276     }
277 
278     return (leases);
279 }
280 
281 Lease6Ptr
simpleAlloc6Test(const Pool6Ptr & pool,const IOAddress & hint,bool fake,bool in_pool)282 AllocEngine6Test::simpleAlloc6Test(const Pool6Ptr& pool, const IOAddress& hint,
283                                    bool fake, bool in_pool) {
284     return (simpleAlloc6Test(pool, duid_, hint, fake, in_pool));
285 }
286 
287 Lease6Ptr
simpleAlloc6Test(const Pool6Ptr & pool,const IOAddress & hint,uint32_t preferred,uint32_t valid,uint32_t exp_preferred,uint32_t exp_valid)288 AllocEngine6Test::simpleAlloc6Test(const Pool6Ptr& pool, const IOAddress& hint,
289                                    uint32_t preferred, uint32_t valid,
290                                    uint32_t exp_preferred, uint32_t exp_valid) {
291     Lease::Type type = pool->getType();
292     uint8_t expected_len = pool->getLength();
293 
294     boost::scoped_ptr<AllocEngine> engine;
295     EXPECT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
296                                                  100)));
297     // We can't use ASSERT macros in non-void methods
298     EXPECT_TRUE(engine);
299     if (!engine) {
300         return (Lease6Ptr());
301     }
302 
303     Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234));
304 
305     AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, query);
306     ctx.hwaddr_ = hwaddr_;
307     ctx.addHostIdentifier(Host::IDENT_HWADDR, hwaddr_->hwaddr_);
308     ctx.currentIA().iaid_ = iaid_;
309     ctx.currentIA().type_ = type;
310     ctx.currentIA().addHint(hint, expected_len, preferred, valid);
311     subnet_->setPreferred(Triplet<uint32_t>(200, 300, 400));
312     subnet_->setValid(Triplet<uint32_t>(300, 400, 500));
313 
314     // Set some non-standard callout status to make sure it doesn't affect the
315     // allocation.
316     ctx.callout_handle_ = HooksManager::createCalloutHandle();
317     ctx.callout_handle_->setStatus(CalloutHandle::NEXT_STEP_SKIP);
318 
319     findReservation(*engine, ctx);
320     Lease6Ptr lease;
321     EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
322 
323     // Check that we got a lease
324     EXPECT_TRUE(lease);
325     if (!lease) {
326         return (Lease6Ptr());
327     }
328 
329     // Do all checks on the lease
330     checkLease6(duid_, lease, type, expected_len, true, true);
331 
332     // Check expected preferred and valid lifetimes.
333     EXPECT_EQ(exp_preferred, lease->preferred_lft_);
334     EXPECT_EQ(exp_valid, lease->valid_lft_);
335 
336     return (lease);
337 }
338 
339 Lease6Ptr
simpleAlloc6Test(const Pool6Ptr & pool,const DuidPtr & duid,const IOAddress & hint,bool fake,bool in_pool)340 AllocEngine6Test::simpleAlloc6Test(const Pool6Ptr& pool, const DuidPtr& duid,
341                                    const IOAddress& hint, bool fake, bool in_pool) {
342     Lease::Type type = pool->getType();
343     uint8_t expected_len = pool->getLength();
344 
345     boost::scoped_ptr<AllocEngine> engine;
346     EXPECT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
347                                                  100)));
348     // We can't use ASSERT macros in non-void methods
349     EXPECT_TRUE(engine);
350     if (!engine) {
351         return (Lease6Ptr());
352     }
353 
354     Pkt6Ptr query(new Pkt6(fake ? DHCPV6_SOLICIT : DHCPV6_REQUEST, 1234));
355 
356     AllocEngine::ClientContext6 ctx(subnet_, duid, false, false, "", fake, query);
357     ctx.hwaddr_ = hwaddr_;
358     ctx.addHostIdentifier(Host::IDENT_HWADDR, hwaddr_->hwaddr_);
359     ctx.currentIA().iaid_ = iaid_;
360     ctx.currentIA().type_ = type;
361     ctx.currentIA().addHint(hint);
362 
363     // Set some non-standard callout status to make sure it doesn't affect the
364     // allocation.
365     ctx.callout_handle_ = HooksManager::createCalloutHandle();
366     ctx.callout_handle_->setStatus(CalloutHandle::NEXT_STEP_SKIP);
367 
368     findReservation(*engine, ctx);
369     Lease6Ptr lease;
370     EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
371 
372     // Check that we got a lease
373     EXPECT_TRUE(lease);
374     if (!lease) {
375         return (Lease6Ptr());
376     }
377 
378     // Do all checks on the lease
379     checkLease6(duid, lease, type, expected_len, in_pool, in_pool);
380 
381     // Check that the lease is indeed in LeaseMgr
382     Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(type, lease->addr_);
383     if (!fake) {
384         // This is a real (REQUEST) allocation, the lease must be in the DB
385         EXPECT_TRUE(from_mgr);
386         if (!from_mgr) {
387             return (Lease6Ptr());
388         }
389 
390         // Now check that the lease in LeaseMgr has the same parameters
391         detailCompareLease(lease, from_mgr);
392     } else {
393         // This is a fake (SOLICIT) allocation, the lease must not be in DB
394         EXPECT_FALSE(from_mgr);
395         if (from_mgr) {
396             return (Lease6Ptr());
397         }
398     }
399 
400     return (lease);
401 }
402 
403 Lease6Collection
renewTest(AllocEngine & engine,const Pool6Ptr & pool,AllocEngine::HintContainer & hints,bool in_pool)404 AllocEngine6Test::renewTest(AllocEngine& engine, const Pool6Ptr& pool,
405                             AllocEngine::HintContainer& hints,
406                             bool in_pool) {
407 
408     Lease::Type type = pool->getType();
409     uint8_t expected_len = pool->getLength();
410 
411     Pkt6Ptr query(new Pkt6(DHCPV6_RENEW, 1234));
412     AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "",
413                                     false, query);
414     ctx.currentIA().hints_ = hints;
415     ctx.currentIA().iaid_ = iaid_;
416     ctx.currentIA().type_ = type;
417 
418     findReservation(engine, ctx);
419     Lease6Collection leases = engine.renewLeases6(ctx);
420 
421     for (Lease6Collection::iterator it = leases.begin(); it != leases.end(); ++it) {
422 
423         // Do all checks on the lease
424         checkLease6(duid_, *it, type, expected_len, in_pool, in_pool);
425 
426         // Check that context has been updated with allocated addresses or
427         // prefixes.
428         checkAllocatedResources(*it, ctx);
429 
430         // Check that the lease is indeed in LeaseMgr
431         Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(type,
432                                                                    (*it)->addr_);
433 
434         // This is a real (REQUEST) allocation, the lease must be in the DB
435         EXPECT_TRUE(from_mgr) << "Lease " << from_mgr->addr_.toText()
436                               << " returned by allocateLeases6(), "
437                               << "but was not present in LeaseMgr";
438         if (!from_mgr) {
439             return (leases);
440         }
441 
442         // Now check that the lease in LeaseMgr has the same parameters
443         detailCompareLease(*it, from_mgr);
444     }
445 
446     return (leases);
447 }
448 
449 void
allocWithUsedHintTest(Lease::Type type,IOAddress used_addr,IOAddress requested,uint8_t expected_pd_len)450 AllocEngine6Test::allocWithUsedHintTest(Lease::Type type, IOAddress used_addr,
451                                         IOAddress requested,
452                                         uint8_t expected_pd_len) {
453     boost::scoped_ptr<AllocEngine> engine;
454     ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
455     ASSERT_TRUE(engine);
456 
457     // Let's create a lease and put it in the LeaseMgr
458     DuidPtr duid2 = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0xff)));
459     time_t now = time(NULL);
460     Lease6Ptr used(new Lease6(type, used_addr,
461                               duid2, 1, 2, now, subnet_->getID()));
462     ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
463 
464     // Another client comes in and request an address that is in pool, but
465     // unfortunately it is used already. The same address must not be allocated
466     // twice.
467 
468     Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234));
469     AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false,
470                                     query);
471     ctx.currentIA().iaid_ = iaid_;
472     ctx.currentIA().type_ = type;
473     ctx.currentIA().addHint(requested);
474 
475     Lease6Ptr lease;
476     EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
477 
478     // Check that we got a lease
479     ASSERT_TRUE(lease);
480 
481     // Allocated address must be different
482     EXPECT_NE(used_addr, lease->addr_);
483 
484     // We should NOT get what we asked for, because it is used already
485     EXPECT_NE(requested, lease->addr_);
486 
487     // Do all checks on the lease
488     checkLease6(duid_, lease, type, expected_pd_len);
489 
490     // Check that the lease is indeed in LeaseMgr
491     Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
492                                                                lease->addr_);
493     ASSERT_TRUE(from_mgr);
494 
495     // Now check that the lease in LeaseMgr has the same parameters
496     detailCompareLease(lease, from_mgr);
497 }
498 
499 void
allocBogusHint6(Lease::Type type,asiolink::IOAddress hint,uint8_t expected_pd_len)500 AllocEngine6Test::allocBogusHint6(Lease::Type type, asiolink::IOAddress hint,
501                                   uint8_t expected_pd_len) {
502     boost::scoped_ptr<AllocEngine> engine;
503     ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
504     ASSERT_TRUE(engine);
505 
506     // Client would like to get a 3000::abc lease, which does not belong to any
507     // supported lease. Allocation engine should ignore it and carry on
508     // with the normal allocation
509 
510     Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234));
511     AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false,
512                                     query);
513     ctx.currentIA().iaid_ = iaid_;
514     ctx.currentIA().type_ = type;
515     ctx.currentIA().addHint(hint);
516 
517     Lease6Ptr lease;
518     EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
519 
520     // Check that we got a lease
521     ASSERT_TRUE(lease);
522 
523     // We should NOT get what we asked for, because it is used already
524     EXPECT_NE(hint, lease->addr_);
525 
526     // Do all checks on the lease
527     checkLease6(duid_, lease, type, expected_pd_len);
528 
529     // Check that the lease is indeed in LeaseMgr
530     Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
531                                                                lease->addr_);
532     ASSERT_TRUE(from_mgr);
533 
534     // Now check that the lease in LeaseMgr has the same parameters
535     detailCompareLease(lease, from_mgr);
536 }
537 
538 void
testReuseLease6(const AllocEnginePtr & engine,Lease6Ptr & existing_lease,const std::string & addr,const bool fake_allocation,ExpectedResult exp_result,Lease6Ptr & result)539 AllocEngine6Test::testReuseLease6(const AllocEnginePtr& engine,
540                                   Lease6Ptr& existing_lease,
541                                   const std::string& addr,
542                                   const bool fake_allocation,
543                                   ExpectedResult exp_result,
544                                   Lease6Ptr& result) {
545     ASSERT_TRUE(engine);
546 
547     if (existing_lease) {
548         // If an existing lease was specified, we need to add it to the
549         // database. Let's wipe any leases for that address (if any). We
550         // ignore any errors (previous lease may not exist)
551         (void) LeaseMgrFactory::instance().deleteLease(existing_lease);
552 
553         // Let's add it.
554         ASSERT_TRUE(LeaseMgrFactory::instance().addLease(existing_lease));
555     }
556 
557     // A client comes along, asking specifically for a given address
558 
559     Pkt6Ptr query(new Pkt6(fake_allocation ? DHCPV6_SOLICIT : DHCPV6_REQUEST, 1234));
560     AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "",
561                                     fake_allocation, query);
562     ctx.currentIA().iaid_ = iaid_;
563     ctx.currentIA().addHint(IOAddress(addr));
564 
565     Lease6Collection leases;
566 
567     leases = engine->allocateLeases6(ctx);
568 
569     switch (exp_result) {
570     case SHOULD_PASS:
571         ASSERT_FALSE(leases.empty());
572         ASSERT_EQ(1, leases.size());
573         result = leases[0];
574 
575         checkLease6(duid_, result, Lease::TYPE_NA, 128);
576         break;
577 
578     case SHOULD_FAIL:
579         ASSERT_TRUE(leases.empty());
580         break;
581     }
582 }
583 
584 Lease6Ptr
generateDeclinedLease(const std::string & addr,time_t probation_period,int32_t expired)585 AllocEngine6Test::generateDeclinedLease(const std::string& addr,
586                                         time_t probation_period,
587                                         int32_t expired) {
588     Lease6Ptr declined(new Lease6(Lease::TYPE_NA, IOAddress(addr),
589                        duid_, iaid_, 100, 100, subnet_->getID()));
590 
591     time_t now = time(NULL);
592     declined->decline(probation_period);
593     declined->cltt_ = now - probation_period + expired;
594     return (declined);
595 }
596 
597 void
initSubnet(const asiolink::IOAddress & pool_start,const asiolink::IOAddress & pool_end)598 AllocEngine4Test::initSubnet(const asiolink::IOAddress& pool_start,
599                              const asiolink::IOAddress& pool_end) {
600     CfgMgr& cfg_mgr = CfgMgr::instance();
601 
602     subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
603     pool_ = Pool4Ptr(new Pool4(pool_start, pool_end));
604     subnet_->addPool(pool_);
605 
606     cfg_mgr.getStagingCfg()->getCfgSubnets4()->add(subnet_);
607 }
608 
AllocEngine4Test()609 AllocEngine4Test::AllocEngine4Test() {
610 
611     CfgMgr::instance().clear();
612 
613     // This lease mgr needs to exist to before configuration commits.
614     factory_.create("type=memfile universe=4 persist=false");
615 
616     // Create fresh instance of the HostMgr, and drop any previous HostMgr state.
617     HostMgr::instance().create();
618 
619     clientid_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, 0x44)));
620     clientid2_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, 0x56)));
621 
622     uint8_t mac[] = { 0, 1, 22, 33, 44, 55};
623 
624     // Let's use odd hardware type to check if there is no Ethernet
625     // hardcoded anywhere.
626     hwaddr_ = HWAddrPtr(new HWAddr(mac, sizeof(mac), HTYPE_FDDI));
627 
628     // Allocate different MAC address for the tests that require two
629     // different MAC addresses.
630     ++mac[sizeof(mac) - 1];
631     hwaddr2_ = HWAddrPtr(new HWAddr(mac, sizeof (mac), HTYPE_FDDI));
632 
633     // instantiate cfg_mgr
634     CfgMgr& cfg_mgr = CfgMgr::instance();
635 
636     initSubnet(IOAddress("192.0.2.100"), IOAddress("192.0.2.109"));
637     cfg_mgr.commit();
638 
639 
640     // Create a default context. Note that remaining parameters must be
641     // assigned when needed.
642     ctx_.subnet_ = subnet_;
643     ctx_.clientid_ = clientid_;
644     ctx_.hwaddr_ = hwaddr_;
645     ctx_.callout_handle_ = HooksManager::createCalloutHandle();
646     ctx_.query_.reset(new Pkt4(DHCPREQUEST, 1234));
647 
648     StatsMgr::instance().resetAll();
649 }
650 
651 }  // namespace test
652 }  // namespace dhcp
653 }  // namespace isc
654