memfile_lease_mgr.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. // Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <dhcpsrv/cfgmgr.h>
  15. #include <dhcpsrv/dhcpsrv_log.h>
  16. #include <dhcpsrv/memfile_lease_mgr.h>
  17. #include <exceptions/exceptions.h>
  18. #include <iostream>
  19. using namespace isc::dhcp;
  20. Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
  21. : LeaseMgr(parameters) {
  22. // Get the lease files locations and open for IO.
  23. std::string file4 = initLeaseFilePath(V4);
  24. if (!file4.empty()) {
  25. lease_file4_.reset(new CSVLeaseFile4(file4));
  26. lease_file4_->open();
  27. load4();
  28. }
  29. std::string file6 = initLeaseFilePath(V6);
  30. if (!file6.empty()) {
  31. lease_file6_.reset(new CSVLeaseFile6(file6));
  32. lease_file6_->open();
  33. load6();
  34. }
  35. }
  36. Memfile_LeaseMgr::~Memfile_LeaseMgr() {
  37. if (lease_file4_) {
  38. lease_file4_->close();
  39. lease_file4_.reset();
  40. }
  41. if (lease_file6_) {
  42. lease_file6_->close();
  43. lease_file6_.reset();
  44. }
  45. }
  46. bool
  47. Memfile_LeaseMgr::addLease(const Lease4Ptr& lease) {
  48. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  49. DHCPSRV_MEMFILE_ADD_ADDR4).arg(lease->addr_.toText());
  50. if (getLease4(lease->addr_)) {
  51. // there is a lease with specified address already
  52. return (false);
  53. }
  54. // Try to write a lease to disk first. If this fails, the lease will
  55. // not be inserted to the memory and the disk and in-memory data will
  56. // remain consistent.
  57. if (lease_file4_) {
  58. lease_file4_->append(*lease);
  59. }
  60. storage4_.insert(lease);
  61. return (true);
  62. }
  63. bool
  64. Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
  65. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  66. DHCPSRV_MEMFILE_ADD_ADDR6).arg(lease->addr_.toText());
  67. if (getLease6(lease->type_, lease->addr_)) {
  68. // there is a lease with specified address already
  69. return (false);
  70. }
  71. // Try to write a lease to disk first. If this fails, the lease will
  72. // not be inserted to the memory and the disk and in-memory data will
  73. // remain consistent.
  74. if (lease_file6_) {
  75. lease_file6_->append(*lease);
  76. }
  77. storage6_.insert(lease);
  78. return (true);
  79. }
  80. Lease4Ptr
  81. Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
  82. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  83. DHCPSRV_MEMFILE_GET_ADDR4).arg(addr.toText());
  84. typedef Lease4Storage::nth_index<0>::type SearchIndex;
  85. const SearchIndex& idx = storage4_.get<0>();
  86. Lease4Storage::iterator l = idx.find(addr);
  87. if (l == storage4_.end()) {
  88. return (Lease4Ptr());
  89. } else {
  90. return (Lease4Ptr(new Lease4(**l)));
  91. }
  92. }
  93. Lease4Collection
  94. Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr) const {
  95. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  96. DHCPSRV_MEMFILE_GET_HWADDR).arg(hwaddr.toText());
  97. typedef Lease4Storage::nth_index<0>::type SearchIndex;
  98. Lease4Collection collection;
  99. const SearchIndex& idx = storage4_.get<0>();
  100. for(SearchIndex::const_iterator lease = idx.begin();
  101. lease != idx.end(); ++lease) {
  102. // Every Lease4 has a hardware address, so we can compare it
  103. if ((*lease)->hwaddr_ == hwaddr.hwaddr_) {
  104. collection.push_back((*lease));
  105. }
  106. }
  107. return (collection);
  108. }
  109. Lease4Ptr
  110. Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
  111. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  112. DHCPSRV_MEMFILE_GET_SUBID_HWADDR).arg(subnet_id)
  113. .arg(hwaddr.toText());
  114. // We are going to use index #1 of the multi index container.
  115. // We define SearchIndex locally in this function because
  116. // currently only this function uses this index.
  117. typedef Lease4Storage::nth_index<1>::type SearchIndex;
  118. // Get the index.
  119. const SearchIndex& idx = storage4_.get<1>();
  120. // Try to find the lease using HWAddr and subnet id.
  121. SearchIndex::const_iterator lease =
  122. idx.find(boost::make_tuple(hwaddr.hwaddr_, subnet_id));
  123. // Lease was not found. Return empty pointer to the caller.
  124. if (lease == idx.end()) {
  125. return (Lease4Ptr());
  126. }
  127. // Lease was found. Return it to the caller.
  128. return (Lease4Ptr(new Lease4(**lease)));
  129. }
  130. Lease4Collection
  131. Memfile_LeaseMgr::getLease4(const ClientId& client_id) const {
  132. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  133. DHCPSRV_MEMFILE_GET_CLIENTID).arg(client_id.toText());
  134. typedef Memfile_LeaseMgr::Lease4Storage::nth_index<0>::type SearchIndex;
  135. Lease4Collection collection;
  136. const SearchIndex& idx = storage4_.get<0>();
  137. for(SearchIndex::const_iterator lease = idx.begin();
  138. lease != idx.end(); ++ lease) {
  139. // client-id is not mandatory in DHCPv4. There can be a lease that does
  140. // not have a client-id. Dereferencing null pointer would be a bad thing
  141. if((*lease)->client_id_ && *(*lease)->client_id_ == client_id) {
  142. collection.push_back((*lease));
  143. }
  144. }
  145. return (collection);
  146. }
  147. Lease4Ptr
  148. Memfile_LeaseMgr::getLease4(const ClientId& client_id,
  149. const HWAddr& hwaddr,
  150. SubnetID subnet_id) const {
  151. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  152. DHCPSRV_MEMFILE_GET_CLIENTID_HWADDR_SUBID).arg(client_id.toText())
  153. .arg(hwaddr.toText())
  154. .arg(subnet_id);
  155. // We are going to use index #3 of the multi index container.
  156. // We define SearchIndex locally in this function because
  157. // currently only this function uses this index.
  158. typedef Lease4Storage::nth_index<3>::type SearchIndex;
  159. // Get the index.
  160. const SearchIndex& idx = storage4_.get<3>();
  161. // Try to get the lease using client id, hardware address and subnet id.
  162. SearchIndex::const_iterator lease =
  163. idx.find(boost::make_tuple(client_id.getClientId(), hwaddr.hwaddr_,
  164. subnet_id));
  165. if (lease == idx.end()) {
  166. // Lease was not found. Return empty pointer to the caller.
  167. return (Lease4Ptr());
  168. }
  169. // Lease was found. Return it to the caller.
  170. return (*lease);
  171. }
  172. Lease4Ptr
  173. Memfile_LeaseMgr::getLease4(const ClientId& client_id,
  174. SubnetID subnet_id) const {
  175. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  176. DHCPSRV_MEMFILE_GET_SUBID_CLIENTID).arg(subnet_id)
  177. .arg(client_id.toText());
  178. // We are going to use index #2 of the multi index container.
  179. // We define SearchIndex locally in this function because
  180. // currently only this function uses this index.
  181. typedef Lease4Storage::nth_index<2>::type SearchIndex;
  182. // Get the index.
  183. const SearchIndex& idx = storage4_.get<2>();
  184. // Try to get the lease using client id and subnet id.
  185. SearchIndex::const_iterator lease =
  186. idx.find(boost::make_tuple(client_id.getClientId(), subnet_id));
  187. // Lease was not found. Return empty pointer to the caller.
  188. if (lease == idx.end()) {
  189. return (Lease4Ptr());
  190. }
  191. // Lease was found. Return it to the caller.
  192. return (Lease4Ptr(new Lease4(**lease)));
  193. }
  194. Lease6Ptr
  195. Memfile_LeaseMgr::getLease6(Lease::Type /* not used yet */,
  196. const isc::asiolink::IOAddress& addr) const {
  197. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  198. DHCPSRV_MEMFILE_GET_ADDR6).arg(addr.toText());
  199. Lease6Storage::iterator l = storage6_.find(addr);
  200. if (l == storage6_.end()) {
  201. return (Lease6Ptr());
  202. } else {
  203. return (Lease6Ptr(new Lease6(**l)));
  204. }
  205. }
  206. Lease6Collection
  207. Memfile_LeaseMgr::getLeases6(Lease::Type /* not used yet */,
  208. const DUID& duid, uint32_t iaid) const {
  209. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  210. DHCPSRV_MEMFILE_GET_IAID_DUID).arg(iaid).arg(duid.toText());
  211. /// @todo Not implemented.
  212. return (Lease6Collection());
  213. }
  214. Lease6Collection
  215. Memfile_LeaseMgr::getLeases6(Lease::Type /* not used yet */,
  216. const DUID& duid, uint32_t iaid,
  217. SubnetID subnet_id) const {
  218. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  219. DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID)
  220. .arg(iaid).arg(subnet_id).arg(duid.toText());
  221. // We are going to use index #1 of the multi index container.
  222. // We define SearchIndex locally in this function because
  223. // currently only this function uses this index.
  224. typedef Lease6Storage::nth_index<1>::type SearchIndex;
  225. // Get the index.
  226. const SearchIndex& idx = storage6_.get<1>();
  227. // Try to get the lease using the DUID, IAID and Subnet ID.
  228. SearchIndex::const_iterator lease =
  229. idx.find(boost::make_tuple(duid.getDuid(), iaid, subnet_id));
  230. // Lease was not found. Return empty pointer.
  231. if (lease == idx.end()) {
  232. return (Lease6Collection());
  233. }
  234. // Lease was found, return it to the caller.
  235. /// @todo: allow multiple leases for a single duid+iaid+subnet_id tuple
  236. Lease6Collection collection;
  237. collection.push_back(Lease6Ptr(new Lease6(**lease)));
  238. return (collection);
  239. }
  240. void
  241. Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
  242. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  243. DHCPSRV_MEMFILE_UPDATE_ADDR4).arg(lease->addr_.toText());
  244. Lease4Storage::iterator lease_it = storage4_.find(lease->addr_);
  245. if (lease_it == storage4_.end()) {
  246. isc_throw(NoSuchLease, "failed to update the lease with address "
  247. << lease->addr_ << " - no such lease");
  248. }
  249. // Try to write a lease to disk first. If this fails, the lease will
  250. // not be inserted to the memory and the disk and in-memory data will
  251. // remain consistent.
  252. if (lease_file4_) {
  253. lease_file4_->append(*lease);
  254. }
  255. **lease_it = *lease;
  256. }
  257. void
  258. Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
  259. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  260. DHCPSRV_MEMFILE_UPDATE_ADDR6).arg(lease->addr_.toText());
  261. Lease6Storage::iterator lease_it = storage6_.find(lease->addr_);
  262. if (lease_it == storage6_.end()) {
  263. isc_throw(NoSuchLease, "failed to update the lease with address "
  264. << lease->addr_ << " - no such lease");
  265. }
  266. // Try to write a lease to disk first. If this fails, the lease will
  267. // not be inserted to the memory and the disk and in-memory data will
  268. // remain consistent.
  269. if (lease_file6_) {
  270. lease_file6_->append(*lease);
  271. }
  272. **lease_it = *lease;
  273. }
  274. bool
  275. Memfile_LeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {
  276. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  277. DHCPSRV_MEMFILE_DELETE_ADDR).arg(addr.toText());
  278. if (addr.isV4()) {
  279. // v4 lease
  280. Lease4Storage::iterator l = storage4_.find(addr);
  281. if (l == storage4_.end()) {
  282. // No such lease
  283. return (false);
  284. } else {
  285. if (lease_file4_) {
  286. // Copy the lease. The valid lifetime needs to be modified and
  287. // we don't modify the original lease.
  288. Lease4 lease_copy = **l;
  289. // Setting valid lifetime to 0 means that lease is being
  290. // removed.
  291. lease_copy.valid_lft_ = 0;
  292. lease_file4_->append(lease_copy);
  293. }
  294. storage4_.erase(l);
  295. return (true);
  296. }
  297. } else {
  298. // v6 lease
  299. Lease6Storage::iterator l = storage6_.find(addr);
  300. if (l == storage6_.end()) {
  301. // No such lease
  302. return (false);
  303. } else {
  304. if (lease_file6_) {
  305. // Copy the lease. The lifetimes need to be modified and we
  306. // don't modify the original lease.
  307. Lease6 lease_copy = **l;
  308. // Setting lifetimes to 0 means that lease is being removed.
  309. lease_copy.valid_lft_ = 0;
  310. lease_copy.preferred_lft_ = 0;
  311. lease_file6_->append(lease_copy);
  312. }
  313. storage6_.erase(l);
  314. return (true);
  315. }
  316. }
  317. }
  318. std::string
  319. Memfile_LeaseMgr::getDescription() const {
  320. return (std::string("This is a dummy memfile backend implementation.\n"
  321. "It does not offer any useful lease management and its only\n"
  322. "purpose is to test abstract lease manager API."));
  323. }
  324. void
  325. Memfile_LeaseMgr::commit() {
  326. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_COMMIT);
  327. }
  328. void
  329. Memfile_LeaseMgr::rollback() {
  330. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  331. DHCPSRV_MEMFILE_ROLLBACK);
  332. }
  333. std::string
  334. Memfile_LeaseMgr::getDefaultLeaseFilePath(Universe u) const {
  335. std::ostringstream s;
  336. s << CfgMgr::instance().getDataDir() << "/kea-leases";
  337. s << (u == V4 ? "4" : "6");
  338. s << ".csv";
  339. return (s.str());
  340. }
  341. std::string
  342. Memfile_LeaseMgr::getLeaseFilePath(Universe u) const {
  343. if (u == V4) {
  344. return (lease_file4_ ? lease_file4_->getFilename() : "");
  345. }
  346. return (lease_file6_ ? lease_file6_->getFilename() : "");
  347. }
  348. bool
  349. Memfile_LeaseMgr::persistLeases(Universe u) const {
  350. // Currently, if the lease file IO is not created, it means that writes to
  351. // disk have been explicitly disabled by the administrator. At some point,
  352. // there may be a dedicated ON/OFF flag implemented to control this.
  353. if (u == V4 && lease_file4_) {
  354. return (true);
  355. }
  356. return (u == V6 && lease_file6_);
  357. }
  358. std::string
  359. Memfile_LeaseMgr::initLeaseFilePath(Universe u) {
  360. std::string param_name = (u == V4 ? "leasefile4" : "leasefile6");
  361. std::string lease_file;
  362. try {
  363. lease_file = getParameter(param_name);
  364. } catch (const Exception& ex) {
  365. lease_file = getDefaultLeaseFilePath(u);
  366. }
  367. return (lease_file);
  368. }
  369. void
  370. Memfile_LeaseMgr::load4() {
  371. // If lease file hasn't been opened, we are working in non-persistent mode.
  372. // That's fine, just leave.
  373. if (!lease_file4_) {
  374. return;
  375. }
  376. // Remove existing leases (if any). We will recreate them based on the
  377. // data on disk.
  378. storage4_.clear();
  379. Lease4Ptr lease;
  380. do {
  381. /// @todo Currently we stop parsing on first failure. It is possible
  382. /// that only one (or a few) leases are bad, so in theory we could
  383. /// continue parsing but that would require some error counters to
  384. /// prevent endless loops. That is enhancement for later time.
  385. if (!lease_file4_->next(lease)) {
  386. isc_throw(DbOperationError, "Failed to parse the DHCPv6 lease in"
  387. " the lease file: " << lease_file4_->getReadMsg());
  388. }
  389. // If we got the lease, we update the internal container holding
  390. // leases. Otherwise, we reached the end of file and we leave.
  391. if (lease) {
  392. loadLease4(lease);
  393. }
  394. } while (lease);
  395. }
  396. void
  397. Memfile_LeaseMgr::loadLease4(Lease4Ptr& lease) {
  398. // Check if the lease already exists.
  399. Lease4Storage::iterator lease_it = storage4_.find(lease->addr_);
  400. // Lease doesn't exist.
  401. if (lease_it == storage4_.end()) {
  402. // Add the lease only if valid lifetime is greater than 0.
  403. // We use valid lifetime of 0 to indicate that lease should
  404. // be removed.
  405. if (lease->valid_lft_ > 0) {
  406. storage4_.insert(lease);
  407. }
  408. } else {
  409. // We use valid lifetime of 0 to indicate that the lease is
  410. // to be removed. In such case, erase the lease.
  411. if (lease->valid_lft_ == 0) {
  412. storage4_.erase(lease_it);
  413. } else {
  414. // Update existing lease.
  415. **lease_it = *lease;
  416. }
  417. }
  418. }
  419. void
  420. Memfile_LeaseMgr::load6() {
  421. // If lease file hasn't been opened, we are working in non-persistent mode.
  422. // That's fine, just leave.
  423. if (!lease_file6_) {
  424. return;
  425. }
  426. // Remove existing leases (if any). We will recreate them based on the
  427. // data on disk.
  428. storage6_.clear();
  429. Lease6Ptr lease;
  430. do {
  431. /// @todo Currently we stop parsing on first failure. It is possible
  432. /// that only one (or a few) leases are bad, so in theory we could
  433. /// continue parsing but that would require some error counters to
  434. /// prevent endless loops. That is enhancement for later time.
  435. if (!lease_file6_->next(lease)) {
  436. isc_throw(DbOperationError, "Failed to parse the DHCPv6 lease in"
  437. " the lease file: " << lease_file6_->getReadMsg());
  438. }
  439. // If we got the lease, we update the internal container holding
  440. // leases. Otherwise, we reached the end of file and we leave.
  441. if (lease) {
  442. loadLease6(lease);
  443. }
  444. } while (lease);
  445. }
  446. void
  447. Memfile_LeaseMgr::loadLease6(Lease6Ptr& lease) {
  448. // Check if the lease already exists.
  449. Lease6Storage::iterator lease_it = storage6_.find(lease->addr_);
  450. // Lease doesn't exist.
  451. if (lease_it == storage6_.end()) {
  452. // Add the lease only if valid lifetime is greater than 0.
  453. // We use valid lifetime of 0 to indicate that lease should
  454. // be removed.
  455. if (lease->valid_lft_ > 0) {
  456. storage6_.insert(lease);
  457. }
  458. } else {
  459. // We use valid lifetime of 0 to indicate that the lease is
  460. // to be removed. In such case, erase the lease.
  461. if (lease->valid_lft_ == 0) {
  462. storage6_.erase(lease_it);
  463. } else {
  464. // Update existing lease.
  465. **lease_it = *lease;
  466. }
  467. }
  468. }