BIND 10 trac2340, updated. e78384f8c6aca75a41ea000d22ecc7648513ad02 Merge branch 'trac2340' of ssh://git.bind10.isc.org/var/bind10/git/bind10 into trac2340
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Oct 11 17:36:53 UTC 2012
The branch, trac2340 has been updated
via e78384f8c6aca75a41ea000d22ecc7648513ad02 (commit)
via bc03b9cc89d6c3cad7308b884679125ab547b5cb (commit)
via 55be177fc4f7537143ab6ef5a728bd44bdf9d783 (commit)
via 16823263f5bc357de97f8b5d72f7b4d046583d23 (commit)
via ecdf1aeb4bfd97f636cc081cce30cc3394b38d11 (commit)
via b6501267d7058d8ed879eb4ce63f3d502ccebcc1 (commit)
via 47cfab4fa97829309b1c6093d65c27a142b1c87a (commit)
via bd7ef43a90c7e6f3a9b7140d0cacb2459dcd4091 (commit)
via aea67d494996a4b86a1671591e4cfa0ed1cbee77 (commit)
via 52ba8a9314e28f0f2f39510e66c2dc03531c47e1 (commit)
via ed72f2bf21f13a214106d222f6537a43f6f3318d (commit)
via ff2fabced6d1b9e88a2c6c2da66573ad96ae4e00 (commit)
via dda8b3fa72979fd24d5c3bdca6709408b5bafedb (commit)
via 35bdd068cf6192eba30d94d6a7a73751be4220ff (commit)
via 1645116db47739bc194d10db67a3a085b1ac551d (commit)
via 6207e0ccf7924b0976a21ffb7f901d946a273c41 (commit)
via e3079eb5ceeeca83507f6dfbf712b374661c3935 (commit)
via 5097c34950518370eabcade6cb71ba952bfeefd4 (commit)
via 9f77979fd649eaa9ec1cc3e9ce5b80059e2df3a5 (commit)
via a969883cd42fef3c3782fea117c156b76014df25 (commit)
via 214377d8511c7f8fdb8b8c8052bcb301aad1d06f (commit)
via c76f74659b3bc90b28f4af8940bd47193b92a28a (commit)
via 64bcd98477cfc62851a21aa64ced28d0cff92201 (commit)
via 0fc7d94b29ecc8a267d32047636d6525a3133612 (commit)
via 5703d87a9e031873305da04b88fb49ac5172c3c1 (commit)
via 4d27a4533c2cbdcb3c9e74c12d03024733e79895 (commit)
via a6cafe644f6a9413ba7f917e741b82cc292d3577 (commit)
via 52272e7986c23da3a0b6c4897f94245bfb408420 (commit)
via ed2aceb01d516724a4f289343c4ad1c65b4322b4 (commit)
via b15be74974e7e1d4f9acc0590e8853a064e3b6bf (commit)
via d7e42bb0c48c961c320ba1bf4324c49b9c43c19a (commit)
via 919fe74ccbeecf5d546b60f017c3e9e1b073655a (commit)
via f44918fd6cd6c3357609c82865a1e6c4a0e4d44a (commit)
via 44b1d42219a1787165a01497c21fec2661ba8277 (commit)
via 3efb1402e7d62755971c8e1440d31f85f14053e3 (commit)
via a3953a556b472084d669dcb629fb801dec67c5dd (commit)
via ea4149ff70f0a90ed995a04e41e4fa06664278c4 (commit)
via 7b2aa97d01af2934b408caa6044cbfab4c6679f6 (commit)
via e84770a80501161a4de8ca0fd9d821b0ce7c7da9 (commit)
via fa5076be0c7037c239c00fb7c2c53d02bdc87260 (commit)
via b31ee9e4712a22bd04637aa3222863ab0eb3c2b1 (commit)
via 45ae6bad11071f2b416c267bf2e71f2208487dda (commit)
via a270e0425f64f0fca563b7d49708325250911b96 (commit)
via 0a23277c5bcbd35467652610f7feb2b7f7c65a0b (commit)
via bb347f194134acc2a3d1e7f2c6d6b4f0d56d2a17 (commit)
via 40083686017562d13d812240499a8090383bfa11 (commit)
via a841ad0aec2fa5d0966dc43b3036ff99b5f3ae42 (commit)
via a25609c439090aeb21c01b487a2070b4df8d435b (commit)
via b2eedd0aebf2739acfb5e83363667fd2c1101f7d (commit)
via fa2026935d4738b6b5b7365d2fab53f9dea09cc4 (commit)
via dd752b34220a5b6a07a4d2c057169c6b88394c32 (commit)
via b675d21e2e7b1864b32824c97e180abf47c1f42e (commit)
via fe0e9a269f318aae152fb4b55437b45609bfd6cc (commit)
via 666c34d9e2c70936c264bd0432f874a95af42a1a (commit)
via 4686e5da4ecc7801a232a1858bf11f124aca3ee7 (commit)
via 4e5ca3a84b4c02ffef3bf8b6c6360b05c8600a4e (commit)
via cdbc11cf13f6cc69498b56a23c61748ed67f3631 (commit)
via 0dca4820d8473e8e1db07b49ef54d52d250e9209 (commit)
via 0edff937af7a4fcb6565d2b7ad14e0484b3905b1 (commit)
via ecb43490182626c4e62cded9d02ac9a94feb4cfa (commit)
via 83cdd8bb5d8cb846bfc85e65b33fc57fa56939b7 (commit)
via dc506d0714924ad48c3cd6a93c181ddd663f0059 (commit)
via b2cb1e1e337281fe923f1065fa19eac896d63b15 (commit)
via 4da98b699e5d73acbf7f0a01799b3a006aec4832 (commit)
via 6f008e19162fe3ae3911db0f770d6d38612bcba0 (commit)
via e0f618ac8f36e7fa8dbeab6164d40fd838178831 (commit)
via bb21aa5022e544357f9faa327278680acf5f16e0 (commit)
via f38d24a77f7a146b6a37f912c98af268df40f5e7 (commit)
via da22b37709978a87d276b1d88a92b401ae9a2084 (commit)
via 0e9c2a4c688d85c32e671a1564dd65818b1a6043 (commit)
via f7c0410f7d2f1c3a06f886b548713bae6e78e9fb (commit)
via 13089ae122acefb8d2a632174da4e4dd53ce4473 (commit)
via dd83505acac98d122777883a304465f69ecd03ec (commit)
via 06c667cd025d42798dbce055a24ada9e601f8c35 (commit)
via c66fe1c8ad169c7bd0bc15c0cbe2357194acfaa4 (commit)
via 1eb3ce6df757a23ff59b71469e0f19329893d8c7 (commit)
via 9334389794384c62c517d646608fb23a1abeb40d (commit)
via 3d98322d24b54475ce801880a5d17a27dc8f57ef (commit)
via 1c4ec91a6f44300af78f4964496cf000c97e93f8 (commit)
via b41cca56e918501b7a84cfe31067f786ed1d065e (commit)
via c3a2105cbd7516aada1b954184b699e1ae8200ee (commit)
via 347e333b52c7589ad5bf4fb9cc6f4ff6474b510d (commit)
via fac39dc29a4f858bfe6d1c48f76737926a043f32 (commit)
via adb92afc6f7d0ceda51780577ebe4c2487745cad (commit)
via c28be089b929185c72aba5fe90c5f8d355c833ac (commit)
via 998645aaeb5a7369ae94e71f84d40512ffee996b (commit)
via 55d94bb5f735252542908e9565d7a49c9a6e0966 (commit)
via 3e2a372012e633d017a97029d13894e743199741 (commit)
via 5cc254b16bd0120a7bacd33f90936333fbecfd79 (commit)
via b05952bb39bc7f038e65c5e61aca711278096dee (commit)
via b770f510961784b1cbf766a1b40fb026788d8cb0 (commit)
via 9ef297b7faf705148c7aed37df6c796e55660062 (commit)
via a017390f15c132fdb08f244f2e111ae6964e4cc4 (commit)
via 6fc2942362354dd4960a25d644095f6eb44b6023 (commit)
via 1426bb5c63cd7d79a4a16aedf619aff5ea2394aa (commit)
via 73f22adb3400726277f06f9d1f8760e43bcc133f (commit)
via 0375b6599cabcefe4e9cf1b326f54b3519bde8b3 (commit)
via 50f42396efa039096dd74c13425d1a2bc0efc978 (commit)
via 64bba5b1c6a4155e8179217c10e998fbe3c2822c (commit)
via 7ad6e5687c4835d70422ee09d1bfdb032979060a (commit)
via a78e560343b41f0f692c7903c938b2b2b24bf56b (commit)
via de5fd0b12800235b15ee02cbed8e862ea6c974ad (commit)
via 028bed9014b15facf1a29d3d4a822c9d14fc6411 (commit)
via 4784ca566b009035404a5abf1759c2eedf5a7515 (commit)
via df196f7609757253c4f2f918cd91012bb3af1163 (commit)
via 5fadea676fc73e068977173bb62b58d04fedf52c (commit)
via 532ac3d0054f6a11b91ee369964f3a84dabc6040 (commit)
via e2d1490eb82b26c501df4d0ed7323478b46a1cca (commit)
via a1983f43686919fae5dfb05ad8e6da07e5534111 (commit)
via 56dd56426342f9fa3d63c436f35ba86208512ee0 (commit)
via 08d6f75709a7669481b92fc0b2e4176174bc0f48 (commit)
via 1517f32c9e68baacfc68c2aab412b29045d846b9 (commit)
via 5e39872cc6dc260c91596ee31f1601dbf53de503 (commit)
via ebfe8a5ab083e3ec1ead648709bfba801fb617a5 (commit)
via 9a9260c2589a8468b73f2ecc16929acd66aeb81c (commit)
via 46c03d26e27417bdce132b90eef18686443bd5a7 (commit)
via d5a5e815fc96116ee205256b9cba7c11752f0692 (commit)
via 574a6f8834ffa1ef3faddc637257efcde4eae445 (commit)
via 5b9ab4bc5c038d3fe6e12a0cf90c33e5f54d0f45 (commit)
via 43636d3f31d1684984eb5337b91a418dd1725fbe (commit)
via 938d8b3145666d6f7d7084668b0ee665b3458e4a (commit)
via 680279e6e9ac7a15d23b8a4d6d03a391166a7c8b (commit)
via ff837bb1fc512920556a796c40cacc20407b165c (commit)
via 7e7171deec8d2a31147a9d5700f4315e2ea3e87b (commit)
via 4a6553ba36f68f141e7420b070ad6d621f9a8465 (commit)
via e2a552fcaa6fcc1f0d39defd990bd5a35a4c73a3 (commit)
via e3cc1803c6fb2aa3373528b6095eb9cf6e8b24d1 (commit)
via fb86b2f215ca1a08440c5c200f22af7747c9de2a (commit)
via 5ee024c32a3ce4afd33d0d5d4df59fcde90d739d (commit)
via 0b7e9646307a6e58d3e1df60c68cbac5dbcbfecb (commit)
via 01eb4277b933cb0537204d98b9200550ee3eb641 (commit)
via 5ff43d80fb8eaae5ac2621a5a754cf94204149de (commit)
via 2c7936f05e6e2055016cdf7f4c915a80f465cde5 (commit)
via a49d8187d7b89c1f40b520b4af324096eb69fa5d (commit)
from 73aebe53f210471b768d79b1f24ee154c56c8554 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit e78384f8c6aca75a41ea000d22ecc7648513ad02
Merge: bc03b9c 73aebe5
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Oct 11 10:35:09 2012 -0700
Merge branch 'trac2340' of ssh://git.bind10.isc.org/var/bind10/git/bind10 into trac2340
with fixing Conflicts:
commit bc03b9cc89d6c3cad7308b884679125ab547b5cb
Merge: 55be177 0375b65
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Oct 11 10:22:29 2012 -0700
Merge branch 'master' into trac2340
with fixing conflicts in
ChangeLog
examples/README
commit 55be177fc4f7537143ab6ef5a728bd44bdf9d783
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Oct 11 09:41:47 2012 -0700
[2340] removed a bogus 'test' within a test(1) expression.
commit 16823263f5bc357de97f8b5d72f7b4d046583d23
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Oct 10 13:50:21 2012 -0700
[master] changelog for #2339
commit ecdf1aeb4bfd97f636cc081cce30cc3394b38d11
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Oct 9 13:17:59 2012 -0700
[2339] changed the search order of python executable: seek python3.x first.
this works around a bit awkward installation setup where there's a link
from "python3" to "python3.x" but not from "python3-config" to the
corresponding "python3.x-config". That happens for recent versions of
Homebrew.
commit b6501267d7058d8ed879eb4ce63f3d502ccebcc1
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Oct 10 20:42:46 2012 +0200
Compilation fix: usual static_cast<X*>(NULL)
Sunstudio is unhappy with plain NULL inside EXPECT_EQ and thinks it is
int. This makes it think otherwise.
commit 47cfab4fa97829309b1c6093d65c27a142b1c87a
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Oct 10 20:28:16 2012 +0200
Remove extra comma at the end of enum
This should fix compilation issue on sunstudio.
commit bd7ef43a90c7e6f3a9b7140d0cacb2459dcd4091
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Oct 10 09:32:40 2012 -0700
[master] added changelog for #2244
commit aea67d494996a4b86a1671591e4cfa0ed1cbee77
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Oct 10 09:31:30 2012 -0700
[master] a minor grammar fix to changelog entry.
commit 52ba8a9314e28f0f2f39510e66c2dc03531c47e1
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Oct 9 11:11:51 2012 -0700
[2244] missing update: Component.running() was renamed is_running().
commit ed72f2bf21f13a214106d222f6537a43f6f3318d
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 8 16:14:16 2012 -0700
[2244] renamed BaseComponent.is_failed() to is_restarting().
so it sounds more natural as an English term.
commit ff2fabced6d1b9e88a2c6c2da66573ad96ae4e00
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 8 15:49:24 2012 -0700
[2244] fixed a typo in a log message.
commit dda8b3fa72979fd24d5c3bdca6709408b5bafedb
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Oct 4 22:19:27 2012 -0700
[2244] rename Componet.running() is_running() for consistency.
this branch introduced is_failed() (and failed() was already defined for
a different a purpose), so for consistency it would be better to name
the running version is_xxx too.
commit 35bdd068cf6192eba30d94d6a7a73751be4220ff
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Oct 4 22:11:45 2012 -0700
[2244] cleanup: reordered log message file
commit 1645116db47739bc194d10db67a3a085b1ac551d
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Oct 4 22:10:40 2012 -0700
[2244] make sure restarting components only when they are in config.
this should fix the main problem of this ticket.
commit 6207e0ccf7924b0976a21ffb7f901d946a273c41
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Oct 4 21:08:55 2012 -0700
[2244] a minor editorial fix to the previous comment update
commit e3079eb5ceeeca83507f6dfbf712b374661c3935
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Oct 4 20:53:37 2012 -0700
[2244] added comment about has_comonent as it may not be very obvious.
commit 5097c34950518370eabcade6cb71ba952bfeefd4
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Oct 4 17:55:57 2012 -0700
[2244] added a simple has_component() method to configurtor.
should be pretty trivial, so added a couple of test cases as part of
other tests.
commit 9f77979fd649eaa9ec1cc3e9ce5b80059e2df3a5
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Oct 4 17:38:43 2012 -0700
[2244] make sure configurtor's build_plan() handles 'failed' component.
this fixes the test case introduced at the beginning of the branch.
commit a969883cd42fef3c3782fea117c156b76014df25
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Oct 4 17:37:09 2012 -0700
[2244] introduced a new "Failed" state of Component.
commit 214377d8511c7f8fdb8b8c8052bcb301aad1d06f
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Oct 4 17:27:15 2012 -0700
[2244] added a test case that reproduces one aspect of the problem.
the configurator should be able to delete a component to be removed
even if the it's failing (unexpectedly). The current implementation
doesn't handle that condition correctly.
commit c76f74659b3bc90b28f4af8940bd47193b92a28a
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Oct 9 13:28:08 2012 -0700
[2204] removed an obsolete comment that only made sense for the previous code.
commit 64bcd98477cfc62851a21aa64ced28d0cff92201
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Oct 9 13:26:20 2012 -0700
[2204] added notes about future extensions of incremental datasrc config update
commit 0fc7d94b29ecc8a267d32047636d6525a3133612
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 8 17:29:15 2012 -0700
[2204] grammar fix in documentation
commit 5703d87a9e031873305da04b88fb49ac5172c3c1
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 8 17:27:23 2012 -0700
[2204] updated test comments without using "rollback".
as the new code actually doesn't do rollback operation internally,
even though the observable effect is the same.
commit 4d27a4533c2cbdcb3c9e74c12d03024733e79895
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 8 16:56:10 2012 -0700
[2204] updated comments about releasing old data source client lists
the previous one was not really accurate and was confusing.
commit a6cafe644f6a9413ba7f917e741b82cc292d3577
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Oct 5 17:04:28 2012 -0700
[2204] cleanup: removed unused func, and renamed "ClientList" with "DataSrc".
getClientListClasses() was removed. It's not used anymore.
a few methods named with "ClientList" were renamed with adding "DataSrc".
The resulting names are a bit long, but since there's no namespace
qualification, simply saying "client" can be confusing (it could be
interpreted to mean DNS clients, for example).
commit 52272e7986c23da3a0b6c4897f94245bfb408420
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Oct 5 16:52:37 2012 -0700
[2204] regression fix: make sure the datasrc config is installed to server.
commit ed2aceb01d516724a4f289343c4ad1c65b4322b4
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Oct 5 16:48:03 2012 -0700
[2204] removed server function/template param from configureDataSourceGeneric.
This is pure cleanup. This function already doesn't use the server.
commit b15be74974e7e1d4f9acc0590e8853a064e3b6bf
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Oct 5 16:40:10 2012 -0700
[2204] extracted swapDataSrcClientLists() from configureDataSource().
now configureDataSource() can take time.
commit d7e42bb0c48c961c320ba1bf4324c49b9c43c19a
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Oct 5 16:02:01 2012 -0700
[2204] completely replaced setClientList with swapDataSrcClientLists.
the test cases using setClientList were updated so they use
swapDataSrcClientLists (some of them work as a test for the "swap" itself).
now we don't need setClientList, so it was removed.
commit 919fe74ccbeecf5d546b60f017c3e9e1b073655a
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Oct 5 15:15:18 2012 -0700
[2204] simplify configureDataSource by always creating a new lists and swap.
so we don't have to worry about what are in the current lists or rollback
operations.
swapDataSrcClientLists() is newly introduced for AuthSrv. No direc tests
yet (technically bad in terms TDD but the definition is very simple), which
will be provided in the next step.
the lock is now moved inside swapDataSrcClientLists().
note: even though this version builds everything, the amount of work
should be mostly the same because the only save is to create the empty
ClientList when the new and old have the same class of client. The expensive
part is ClientList::configure(). This version doesn't need any more call
to configure() than the old version.
commit f44918fd6cd6c3357609c82865a1e6c4a0e4d44a
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Oct 5 14:03:52 2012 -0700
[2204] changed internal representation of auth_srv's "client_lists_" to ptrs.
this will be necessary later in this branch.
also renamed the member variable "datasrc_client_lists_" as the mere "client"
can be ambiguous.
commit 44b1d42219a1787165a01497c21fec2661ba8277
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Oct 10 11:58:17 2012 +0200
[2292] Add a TODO about re-adding tests
Planned for merge #2268
commit 3efb1402e7d62755971c8e1440d31f85f14053e3
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Oct 9 14:11:25 2012 +0200
[2292] Clarify test
And make it slightly stronger (it now checks something that should be
mostly obvious too, but who knows, with software).
commit a3953a556b472084d669dcb629fb801dec67c5dd
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Oct 9 14:07:13 2012 +0200
[2292] Pass the old zone back
Instead of releasing it directly. While the internal release was more
convenient, it didn't allow for swapping things fast under a mutex and
then spending the time releasing it unlocked.
commit ea4149ff70f0a90ed995a04e41e4fa06664278c4
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Oct 9 13:39:30 2012 +0200
[2292] Don't pass SegmentObjectHolder
It is supposed to be mostly private. Use it internally only.
commit 7b2aa97d01af2934b408caa6044cbfab4c6679f6
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 8 11:32:18 2012 -0700
[2292] minor cleanups: constify, indentation
commit e84770a80501161a4de8ca0fd9d821b0ce7c7da9
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Sun Oct 7 17:19:12 2012 +0200
[2292] Update tests
They don't need the mutable versions to work, but they used them anyway.
commit fa5076be0c7037c239c00fb7c2c53d02bdc87260
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Sun Oct 7 17:18:33 2012 +0200
[2292] Re-add version of find removed by accident
This one was not mutable, it just took Name as an argument.
commit b31ee9e4712a22bd04637aa3222863ab0eb3c2b1
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Sun Oct 7 17:03:18 2012 +0200
[2292] Drop tests for InMemoryClient::add
As the method was removed.
commit 45ae6bad11071f2b416c267bf2e71f2208487dda
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Sun Oct 7 16:50:50 2012 +0200
[2292] Remove unused template parameters
The domain tree no longer supports the mutable find versions, so we
don't need the template parameters allowing for them.
commit a270e0425f64f0fca563b7d49708325250911b96
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Sun Oct 7 16:38:23 2012 +0200
[2292] Remove mutable find methods
They are currently used in test code only (so we'll need to update the
tests to compile). The real code seams clean now.
commit 0a23277c5bcbd35467652610f7feb2b7f7c65a0b
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Sun Oct 7 16:13:56 2012 +0200
[2292] Remove the setZoneData method
Currently, the content of zone is passed to the addZone method. No way
to change it later, but the addZone overwrites the old value if called
again.
This should hopefully allow for removal of mutable find methods from the
tree.
commit bb347f194134acc2a3d1e7f2c6d6b4f0d56d2a17
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Oct 2 21:05:33 2012 +0200
[2292] Get rid of the const_cast
It was needed when extracting data from a domain tree chain. The chain
now can hold mutable pointers too, so we use that (and some amount of
template bureaucracy) to avoid the cast.
While the interface changed (on the core find function, it is not
possible to pass const node chain and have a mutable node get out), it
doesn't seem to influence the current code. Also, it is a private
interface anyway, so it should be safe.
commit 40083686017562d13d812240499a8090383bfa11
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Oct 2 20:22:23 2012 +0200
[2292] Parametrize constness of the chain
commit a841ad0aec2fa5d0966dc43b3036ff99b5f3ae42
Author: Mukund Sivaraman <muks at isc.org>
Date: Tue Oct 9 10:41:32 2012 +0530
[master] Set lockfile path for DHCP tests
commit a25609c439090aeb21c01b487a2070b4df8d435b
Author: Mukund Sivaraman <muks at isc.org>
Date: Tue Oct 9 10:35:21 2012 +0530
[master] Update .gitignore files
commit b2eedd0aebf2739acfb5e83363667fd2c1101f7d
Author: Mukund Sivaraman <muks at isc.org>
Date: Tue Oct 9 10:21:48 2012 +0530
[master] Remove empty GNU-style dist files
commit fa2026935d4738b6b5b7365d2fab53f9dea09cc4
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 8 14:12:02 2012 -0700
[master] define dbutil_test.sh as noinst_SCRIPTS to auto-regenerate on modify.
this will prevent surprising test failure on an incrementally updated dev
tree. okayed on jabber.
commit dd752b34220a5b6a07a4d2c057169c6b88394c32
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 8 14:11:39 2012 -0700
[master] added changelog for #1870
commit b675d21e2e7b1864b32824c97e180abf47c1f42e
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Oct 3 14:12:39 2012 -0700
[1870] avoid using "no" keyword as a configured value for "bind10-include".
commit fe0e9a269f318aae152fb4b55437b45609bfd6cc
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Oct 3 12:21:40 2012 -0700
[1870] removed unnecessary call to AX_BOOST_INCLUDE.
since AC_REQUIRE internally does it.
commit 666c34d9e2c70936c264bd0432f874a95af42a1a
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 1 21:13:02 2012 -0700
[1870] removed rrsetlist.h from the libdns___include_HEADERS
it will be cleaned up and should better be excluded from the publicly
visible list.
commit 4686e5da4ecc7801a232a1858bf11f124aca3ee7
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 1 15:31:27 2012 -0700
[1870] some more doc cleanups
commit 4e5ca3a84b4c02ffef3bf8b6c6360b05c8600a4e
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 1 15:26:25 2012 -0700
[1870] provided top level README
commit cdbc11cf13f6cc69498b56a23c61748ed67f3631
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 1 15:12:52 2012 -0700
[1870] separated BIND 10 common libs and DNS lib
so that we can eventually selectively choose module specific libraries.
commit 0dca4820d8473e8e1db07b49ef54d52d250e9209
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 1 15:12:15 2012 -0700
[1870] removed src/bin/host/Makefile from toplevel configure.ac.
commit 0edff937af7a4fcb6565d2b7ad14e0484b3905b1
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Sep 28 21:24:11 2012 -0700
[1870] introduced separate m4 files for dependencies.
commit ecb43490182626c4e62cded9d02ac9a94feb4cfa
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Sep 28 16:39:38 2012 -0700
[1870] make sure install some more headers under dns/ and util/
there may be more, but at least this makes (b10-)host compile as a 3rd party
app.
commit 83cdd8bb5d8cb846bfc85e65b33fc57fa56939b7
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Sep 28 16:37:47 2012 -0700
[1870] moved src/bin/host under example/
(at least for now) there's no way to transform xml doc to other formats.
only xml is provided for reference.
commit dc506d0714924ad48c3cd6a93c181ddd663f0059
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Sep 28 16:32:11 2012 -0700
[1870] created a separate dir to store example "3rd party" apps using BIND 10.
commit b2cb1e1e337281fe923f1065fa19eac896d63b15
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Oct 5 10:12:42 2012 -0700
[2203] renamed datasrc_configurator to datasrc_config; it represents it better.
commit 4da98b699e5d73acbf7f0a01799b3a006aec4832
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Oct 3 22:58:06 2012 -0700
[2203] forotten cleanup: removed now-unused header file.
commit 6f008e19162fe3ae3911db0f770d6d38612bcba0
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Oct 3 17:28:41 2012 -0700
[2203] a piggy back fix: prevent redundant initial data configuration.
this addresses the issue described in #2291. Still not really clean,
but thanks to boost::bind we can centralize all the code logic in the
callback, so I think it's now less likely that we forget cleaning it up
when the hack is not necessary.
commit e0f618ac8f36e7fa8dbeab6164d40fd838178831
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Oct 3 17:17:36 2012 -0700
[2203] changed configurator class to a simple function.
as it's now completely stateless and can work independently.
the common specialization for the main implementation is defined in a
new created .cc file.
commit bb21aa5022e544357f9faa327278680acf5f16e0
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Oct 3 15:44:29 2012 -0700
[2203] pass server obj to configurator's reconfigure().
now the configurator class is completely stateless.
commit f38d24a77f7a146b6a37f912c98af268df40f5e7
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Oct 3 15:24:22 2012 -0700
[2203] refactoring 2nd step: configurator can now be a separate object.
i.e., it's not a singleton any more.
testReconfigure() method isn't needed any more because it doesn't hold
CC session internally.
DatasrcConfiguratorTest.initialization test currently fails and is
disabled for now. The plan is to make the class completely stateless,
at which point we don't even have to think about initialization or cleanup,
and then the test will be able to be removed.
commit da22b37709978a87d276b1d88a92b401ae9a2084
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Oct 2 20:38:31 2012 -0700
[2203] changed the callback type of addRemoteConfig to boost::function.
this will make it more convenient, e.g., by allowing the caller to pass
boost::bind encapsulating a class object and a class method.
boost::function is upper compatible to function pointer, so it doesn't
ensure source-level compatibility.
the functor overhead shouldn't matter in this context, and since this module
already uses boost::function this change doesn't introduce additional
dependency.
commit 0e9c2a4c688d85c32e671a1564dd65818b1a6043
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Oct 2 20:24:57 2012 -0700
[2203] refactoring 1st step: move session obj outside of datasrc configurator.
commit f7c0410f7d2f1c3a06f886b548713bae6e78e9fb
Author: Mukund Sivaraman <muks at isc.org>
Date: Mon Oct 8 12:36:20 2012 +0530
[1899] Allow other RRtypes in nsec3 table (for RRSIGs)
* The unique constraint on NSEC3 owner per zone is now removed
* NSEC3 RRSIGs are now returned next to their RR set
* Test was adjusted to check for RRSIGs too
commit 13089ae122acefb8d2a632174da4e4dd53ce4473
Author: Mukund Sivaraman <muks at isc.org>
Date: Mon Oct 1 01:23:58 2012 +0530
[1899] Add another unittest to check that NSEC3 RRs are being returned
commit dd83505acac98d122777883a304465f69ecd03ec
Author: Mukund Sivaraman <muks at isc.org>
Date: Mon Oct 1 01:16:39 2012 +0530
[1899] Break up UNION SQL query into two and merge manually
Also drop unnecessary columns and ORDER BYs.
commit 06c667cd025d42798dbce055a24ada9e601f8c35
Author: Mukund Sivaraman <muks at isc.org>
Date: Mon Oct 1 00:45:45 2012 +0530
[1899] Add a unique constraint to nsec3 table
This is to check that only one NSEC3 RR exists per owner name in a
zone. The code to fix #1899 would depend on this assertion.
commit c66fe1c8ad169c7bd0bc15c0cbe2357194acfaa4
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Oct 8 16:41:33 2012 +0000
[master] add std:: for memset(). sunstudio requires this with <cstring>
commit 1eb3ce6df757a23ff59b71469e0f19329893d8c7
Author: Jelte Jansen <jelte at isc.org>
Date: Mon Oct 8 09:41:11 2012 +0200
[2275] fix strncpy in socketrequestortest
commit 9334389794384c62c517d646608fb23a1abeb40d
Author: Jelte Jansen <jelte at isc.org>
Date: Fri Oct 5 12:10:56 2012 +0200
[2275] address review comments
commit 3d98322d24b54475ce801880a5d17a27dc8f57ef
Author: Jelte Jansen <jelte at isc.org>
Date: Thu Oct 4 15:57:43 2012 +0200
[2275] valgrind fixes: uninitialized memory
commit 1c4ec91a6f44300af78f4964496cf000c97e93f8
Author: Jelte Jansen <jelte at isc.org>
Date: Thu Oct 4 12:21:04 2012 +0200
[2275] valgrind fixes: uninitialized memory
commit b41cca56e918501b7a84cfe31067f786ed1d065e
Author: Jelte Jansen <jelte at isc.org>
Date: Thu Oct 4 11:44:46 2012 +0200
[2275] use const char* for test globals
commit c3a2105cbd7516aada1b954184b699e1ae8200ee
Author: Jelte Jansen <jelte at isc.org>
Date: Wed Oct 3 16:54:08 2012 +0200
[2275] valgrind fix: initialize memory in labelsequence test
commit 347e333b52c7589ad5bf4fb9cc6f4ff6474b510d
Author: Jelte Jansen <jelte at isc.org>
Date: Wed Oct 3 16:42:08 2012 +0200
[2275] valgrind fix: store singleton instance in auto_ptr
commit fac39dc29a4f858bfe6d1c48f76737926a043f32
Author: Jelte Jansen <jelte at isc.org>
Date: Wed Oct 3 16:11:51 2012 +0200
[2275] valgrind fix: close db in test case
commit adb92afc6f7d0ceda51780577ebe4c2487745cad
Author: Mukund Sivaraman <muks at isc.org>
Date: Mon Oct 8 14:42:55 2012 +0530
[master] Add libb10-cc.la to tests Makefile.am
commit c28be089b929185c72aba5fe90c5f8d355c833ac
Author: Jelte Jansen <jelte at isc.org>
Date: Tue Oct 2 09:41:38 2012 +0200
[2278] Add temporary suppression for false positives
commit 998645aaeb5a7369ae94e71f84d40512ffee996b
Author: Jelte Jansen <jelte at isc.org>
Date: Thu Sep 27 16:28:25 2012 +0200
[2278] remove a bit of dead code
commit 55d94bb5f735252542908e9565d7a49c9a6e0966
Author: Jelte Jansen <jelte at isc.org>
Date: Thu Sep 27 16:00:48 2012 +0200
[2278] A number of cppcheck fixes
and whitespace things, while i was there
commit 3e2a372012e633d017a97029d13894e743199741
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Oct 10 11:02:24 2012 -0700
[2340] corrected the position of closing 'fi' for an 'if GXX = yes'.
commit 5cc254b16bd0120a7bacd33f90936333fbecfd79
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Oct 9 16:43:16 2012 -0700
[2340] added comment about why we need to explicitly define empty dtor.
commit b05952bb39bc7f038e65c5e61aca711278096dee
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Sun Oct 7 23:53:26 2012 -0700
[2340] added workaround for the clang++ "unused arguments" warn/error.
by specifying -Qunused-arguments. Also, as a cleanup for better organization
I moved compiler specific settings to earlier part of configure.ac, where
this workaround was added.
commit b770f510961784b1cbf766a1b40fb026788d8cb0
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Sun Oct 7 21:20:52 2012 -0700
[2340] Revert "[2340] specify thread flag as part CPPFLAGS, not LDFLAGS."
This reverts commit daf81c8846bf0b4e4308068a019c96beb09c5199.
I believe the sense of the change is correct, but it has effects on
other OSes, so it's probably better to use clang specific workaround
(will commit it later).
commit 9ef297b7faf705148c7aed37df6c796e55660062
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Sun Oct 7 21:19:23 2012 -0700
[2340] Revert "[2340] specify -pthread in CXXFLAGS and via system-indepedent variable."
This reverts commit d62a1e4250c88e765b3cd7f77fe9a948db0a565d.
I believe the sense of the change is correct, but it has effects on
other OSes, so it's probably better to use clang specific workaround
(will commit it later).
commit a017390f15c132fdb08f244f2e111ae6964e4cc4
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Sun Oct 7 14:12:02 2012 -0700
[2340] specify -pthread in CXXFLAGS and via system-indepedent variable.
specifying it in LDFLAGS would trigger build error with some versions of clang.
hardcoding "-pthread" is less portable.
commit 6fc2942362354dd4960a25d644095f6eb44b6023
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Sun Oct 7 12:34:55 2012 -0700
[2340] removed an effectively unused variable. clang would complain.
commit 1426bb5c63cd7d79a4a16aedf619aff5ea2394aa
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Sun Oct 7 12:20:34 2012 -0700
[2340] specify thread flag as part CPPFLAGS, not LDFLAGS.
newer version of clang treats the latter as a fatal error.
commit 73f22adb3400726277f06f9d1f8760e43bcc133f
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Sun Oct 7 10:13:58 2012 -0700
[2340] explictly define destructor of mostly empty template class.
without this new versions of clang++ seem to complain that instantiation of
the class results in an unused variable.
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 27 +
configure.ac | 2 +-
doc/devel/02-dhcp.dox | 23 -
doc/devel/mainpage.dox | 5 +
doc/guide/bind10-guide.xml | 99 ++-
examples/README | 2 +-
src/bin/auth/auth_config.h | 2 +-
src/bin/dhcp6/Makefile.am | 2 +
src/bin/dhcp6/config_parser.cc | 797 ++++++++++++++++++++
src/bin/dhcp6/config_parser.h | 147 ++++
src/bin/dhcp6/ctrl_dhcp6_srv.cc | 30 +-
src/bin/dhcp6/dhcp6.dox | 79 ++
src/bin/dhcp6/dhcp6.spec | 92 ++-
src/bin/dhcp6/dhcp6_messages.mes | 20 +
src/bin/dhcp6/dhcp6_srv.cc | 7 +
src/bin/dhcp6/tests/Makefile.am | 3 +
src/bin/dhcp6/tests/config_parser_unittest.cc | 243 ++++++
src/lib/datasrc/memory/memory_client.cc | 1 -
src/lib/datasrc/memory_datasrc.cc | 1 -
.../datasrc/tests/memory/memory_client_unittest.cc | 1 -
src/lib/datasrc/tests/memory_datasrc_unittest.cc | 1 -
src/lib/dhcp/Makefile.am | 2 +
src/lib/dhcp/addr_utilities.cc | 105 ++-
src/lib/dhcp/cfgmgr.cc | 33 +
src/lib/dhcp/cfgmgr.h | 47 +-
src/lib/dhcp/duid.cc | 90 +++
src/lib/dhcp/duid.h | 98 +++
src/lib/dhcp/lease_mgr.cc | 68 ++
src/lib/dhcp/lease_mgr.h | 480 ++++++++++++
src/lib/dhcp/pool.cc | 33 +-
src/lib/dhcp/pool.h | 27 +
src/lib/dhcp/subnet.cc | 44 ++
src/lib/dhcp/subnet.h | 51 ++
src/lib/dhcp/tests/Makefile.am | 2 +
src/lib/dhcp/tests/addr_utilities_unittest.cc | 65 +-
src/lib/dhcp/tests/cfgmgr_unittest.cc | 36 +
src/lib/dhcp/tests/duid_unittest.cc | 169 +++++
src/lib/dhcp/tests/lease_mgr_unittest.cc | 296 ++++++++
src/lib/dhcp/tests/pool_unittest.cc | 73 ++
src/lib/dhcp/tests/subnet_unittest.cc | 82 +-
src/lib/dhcp/triplet.h | 5 +
src/lib/dns/Makefile.am | 1 -
src/lib/dns/rrsetlist.cc | 60 --
src/lib/dns/rrsetlist.h | 132 ----
src/lib/dns/tests/Makefile.am | 2 +-
src/lib/dns/tests/rrsetlist_unittest.cc | 188 -----
46 files changed, 3325 insertions(+), 448 deletions(-)
create mode 100644 src/bin/dhcp6/config_parser.cc
create mode 100644 src/bin/dhcp6/config_parser.h
create mode 100644 src/bin/dhcp6/dhcp6.dox
create mode 100644 src/bin/dhcp6/tests/config_parser_unittest.cc
create mode 100644 src/lib/dhcp/duid.cc
create mode 100644 src/lib/dhcp/duid.h
create mode 100644 src/lib/dhcp/lease_mgr.cc
create mode 100644 src/lib/dhcp/lease_mgr.h
create mode 100644 src/lib/dhcp/tests/duid_unittest.cc
create mode 100644 src/lib/dhcp/tests/lease_mgr_unittest.cc
delete mode 100644 src/lib/dns/rrsetlist.cc
delete mode 100644 src/lib/dns/rrsetlist.h
delete mode 100644 src/lib/dns/tests/rrsetlist_unittest.cc
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 47ad2cb..b421f01 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+492. [func] tomek
+ libdhcpsrv: The DHCP Configuration Manager is now able to store
+ information about IPv4 subnets and pools. It is still not possible
+ to configure that information. Such capability will be implemented
+ in a near future.
+ (Trac #2237, git a78e560343b41f0f692c7903c938b2b2b24bf56b)
+
+491. [func] tomek
+ b10-dhcp6: Configuration for DHCPv6 has been implemented.
+ Currently it is possible to configure IPv6 subnets and pools
+ within those subnets, global and per subnet values of renew,
+ rebind, preferred and valid lifetimes. Configured parameters
+ are accepted, but are not used yet by the allocation engine yet.
+ (Trac #2269, git 028bed9014b15facf1a29d3d4a822c9d14fc6411)
+
+490. [func] tomek
+ libdhcpsrv: An abstract API for lease database has been
+ implemented. It offers a common interface to all concrete
+ database backends.
+ (Trac #2140, git df196f7609757253c4f2f918cd91012bb3af1163)
+
+489. [func] muks
+ The isc::dns::RRsetList class has been removed. It was now unused
+ inside the BIND 10 codebase, and the interface was considered
+ prone to misuse.
+ (Trac #2266, git 532ac3d0054f6a11b91ee369964f3a84dabc6040)
+
488. [build] jinmei
On configure, changed the search order for Python executable.
It first ties more specific file names such as "python3.2" before
diff --git a/configure.ac b/configure.ac
index 4cea7ae..72c7be2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -360,7 +360,7 @@ fi
# Python 3.2 has an unused parameter in one of its headers. This
# has been reported, but not fixed as of yet, so we check if we need
# to set -Wno-unused-parameter.
-if test "X$GXX" = "Xyes" -a test $werror_ok = 1; then
+if test "X$GXX" = "Xyes" -a $werror_ok = 1; then
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS=${PYTHON_INCLUDES}
CXXFLAGS_SAVED="$CXXFLAGS"
diff --git a/doc/devel/02-dhcp.dox b/doc/devel/02-dhcp.dox
index 5217f73..a4bbff9 100644
--- a/doc/devel/02-dhcp.dox
+++ b/doc/devel/02-dhcp.dox
@@ -57,29 +57,6 @@
* that does not support msgq. That is useful for embedded environments.
* It may also be useful in validation.
*
- * @page dhcpv6 DHCPv6 Server Component
- *
- * BIND10 offers DHCPv6 server implementation. It is implemented as
- * b10-dhcp6 component. Its primary code is located in
- * isc::dhcp::Dhcpv6Srv class. It uses \ref libdhcp extensively,
- * especially lib::dhcp::Pkt6, isc::dhcp::Option and
- * isc::dhcp::IfaceMgr classes. Currently this code offers skeleton
- * functionality, i.e. it is able to receive and process incoming
- * requests and trasmit responses. However, it does not have database
- * management, so it returns only one, hardcoded lease to whoever asks
- * for it.
- *
- * DHCPv6 server component does not support relayed traffic yet, as
- * support for relay decapsulation is not implemented yet.
- *
- * DHCPv6 server component does not use BIND10 logging yet.
- *
- * @section dhcpv6Session BIND10 message queue integration
- *
- * DHCPv4 server component is now integrated with BIND10 message queue.
- * It follows the same principle as DHCPv4. See \ref dhcpv4Session for
- * details.
- *
* @page libdhcp libdhcp++
*
* @section libdhcpIntro Libdhcp++ Library Introduction
diff --git a/doc/devel/mainpage.dox b/doc/devel/mainpage.dox
index ca9d881..0da5287 100644
--- a/doc/devel/mainpage.dox
+++ b/doc/devel/mainpage.dox
@@ -15,12 +15,17 @@
* <a href="http://bind10.isc.org/">BIND10 webpage (http://bind10.isc.org)</a>
*
* @section DNS
+ * - Authoritative DNS (todo)
+ * - Recursive resolver (todo)
* - @subpage DataScrubbing
*
* @section DHCP
* - @subpage dhcpv4
* - @subpage dhcpv4Session
* - @subpage dhcpv6
+ * - @subpage dhcpv6-session
+ * - @subpage dhcpv6-config-parser
+ * - @subpage dhcpv6-config-inherit
* - @subpage libdhcp
* - @subpage libdhcpIntro
* - @subpage libdhcpIfaceMgr
diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml
index 2e66ad5..6065616 100644
--- a/doc/guide/bind10-guide.xml
+++ b/doc/guide/bind10-guide.xml
@@ -2751,13 +2751,13 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
<title>DHCPv4 Server Configuration</title>
<para>
The DHCPv4 server does not have a lease database implemented yet
- nor any support for configuration, so every time the same set
+ nor any support for configuration, so the same set
of configuration options (including the same fixed address)
will be assigned every time.
</para>
<para>
At this stage of development, the only way to alter the server
- configuration is to tweak its source code. To do so, please
+ configuration is to modify its source code. To do so, please
edit src/bin/dhcp4/dhcp4_srv.cc file and modify following
parameters and recompile:
<screen>
@@ -2944,16 +2944,95 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
<section id="dhcp6-config">
<title>DHCPv6 Server Configuration</title>
<para>
- The DHCPv6 server does not have lease database implemented yet
- or any support for configuration, so every time the same set
- of configuration options (including the same fixed address)
- will be assigned every time.
+ Once the server is started, it can be configured. To view the
+ current configuration, use the following command in <command>bindctl</command>:
+ <screen>
+ > <userinput>config show Dhcp6</userinput></screen>
+ When starting Dhcp6 daemon for the first time, the default configuration
+ will be available. It will look similar to this:
+ <screen>
+> <userinput>config show Dhcp6</userinput>
+Dhcp6/interface "eth0" string (default)
+Dhcp6/renew-timer 1000 integer (default)
+Dhcp6/rebind-timer 2000 integer (default)
+Dhcp6/preferred-lifetime 3000 integer (default)
+Dhcp6/valid-lifetime 4000 integer (default)
+Dhcp6/subnet6 [] list (default)</screen>
</para>
+
<para>
- At this stage of development, the only way to alter server
- configuration is to tweak its source code. To do so, please
- edit src/bin/dhcp6/dhcp6_srv.cc file, modify the following
- parameters and recompile:
+ To change one of the parameters, simply follow
+ the usual <command>bindctl</command> procedure. For example, to make the
+ leases longer, change their valid-lifetime parameter:
+ <screen>
+> <userinput>config set Dhcp6/valid-lifetime 7200</userinput>
+> <userinput>config commit</userinput></screen>
+ Please note that most Dhcp6 parameters are of global scope
+ and apply to all defined subnets, unless they are overridden on a
+ per-subnet basis.
+ </para>
+
+ <para>
+ The essential role of DHCPv6 server is address assignment. The server
+ has to be configured with at least one subnet and one pool of dynamic
+ addresses to be managed. For example, assume that the server
+ is connected to a network segment that uses the 2001:db8:1::/64
+ prefix. The Administrator of that network has decided that addresses from range
+ 2001:db8:1::1 to 2001:db8:1::ffff are going to be managed by the Dhcp6
+ server. Such a configuration can be achieved in the following way:
+ <screen>
+> <userinput>config add Dhcp6/subnet6</userinput>
+> <userinput>config set Dhcp6/subnet6[0]/subnet "2001:db8:1::/64"</userinput>
+> <userinput>config set Dhcp6/subnet6[0]/pool [ "2001:db8:1::0 - 2001:db8:1::ffff" ]</userinput>
+> <userinput>config commit</userinput></screen>
+ Note that subnet is defined as a simple string, but the pool parameter
+ is actually a list of pools: for this reason, the pool definition is
+ enclosed in square brackets, even though only one range of addresses
+ is specified.</para>
+ <para>It is possible to define more than one pool in a
+ subnet: continuing the previous example, further assume that
+ 2001:db8:1:0:5::/80 should be also be managed by the server. It could be written as
+ 2001:db8:1:0:5:: to 2001:db8:1::5:ffff:ffff:ffff, but typing so many 'f's
+ is cumbersome. It can be expressed more simply as 2001:db8:1:0:5::/80. Both
+ formats are supported by Dhcp6 and can be mixed in the pool list.
+ For example, one could define the following pools:
+ <screen>
+> <userinput>config set Dhcp6/subnet6[0]/pool [ "2001:db8:1::1 - 2001:db8:1::ffff", "2001:db8:1:0:5::/80" ]</userinput>
+> <userinput>config commit</userinput></screen>
+ The number of pools is not limited, but for performance reasons it is recommended to
+ use as few as possible.
+ </para>
+ <para>
+ The server may be configured to serve more than one subnet. To add a second subnet,
+ use a command similar to the following:
+ <screen>
+> <userinput>config add Dhcp6/subnet6</userinput>
+> <userinput>config set Dhcp6/subnet6[1]/subnet "2001:db8:beef::/48"</userinput>
+> <userinput>config set Dhcp6/subnet6[1]/pool [ "2001:db8:beef::/48" ]</userinput>
+> <userinput>config commit</userinput></screen>
+ Arrays are counted from 0. subnet[0] refers to the subnet defined in the
+ previous example. The <command>config add Dhcp6/subnet6</command> adds
+ another (second) subnet. It can be referred to as
+ <command>Dhcp6/subnet6[1]</command>. In this example, we allow server to
+ dynamically assign all addresses available in the whole subnet. Although
+ very wasteful, it is certainly a valid configuration to dedicate the
+ whole /48 subnet for that purpose.
+ </para>
+ <para>
+ When configuring a DHCPv6 server using prefix/length notation, please pay
+ attention to the boundary values. When specifying that the server should use
+ a given pool, it will be able to allocate also first (typically network
+ address) address from that pool. For example for pool 2001:db8::/64 the
+ 2001:db8:: address may be assigned as well. If you want to avoid this,
+ please use min-max notation.
+ </para>
+
+ <para>
+ Note: Although configuration is now accepted, it is not internally used
+ by they server yet. At this stage of development, the only way to alter
+ server configuration is to modify its source code. To do so, please edit
+ src/bin/dhcp6/dhcp6_srv.cc file, modify the following parameters and
+ recompile:
<screen>
const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd";
const uint32_t HARDCODED_T1 = 1500; // in seconds
diff --git a/examples/README b/examples/README
index 12dbbba..65f777b 100644
--- a/examples/README
+++ b/examples/README
@@ -7,7 +7,7 @@ this directory.
On the top (sub) directory (where this README file is stored), we
provide a sample configure.ac and Makefile.am files for GNU automake
-environments with helper autoconf macros to detect the available and
+environments with helper autoconf macros to detect the availability and
location of BIND 10 header files and library objects.
You can use the configure.ac and Makefile.am files with macros under
diff --git a/src/bin/auth/auth_config.h b/src/bin/auth/auth_config.h
index 6f18810..8e816a3 100644
--- a/src/bin/auth/auth_config.h
+++ b/src/bin/auth/auth_config.h
@@ -93,7 +93,7 @@ public:
/// that corresponds to this derived class and prepares a new value to
/// apply to the server.
/// In the above example, the derived class for the identifier "param1"
- /// would be passed an data \c Element storing an integer whose value
+ /// would be passed a data \c Element storing an integer whose value
/// is 10, and would record that value internally;
/// the derived class for the identifier "param2" would be passed a
/// map element and (after parsing) convert it into some internal
diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am
index 4dec4e7..68aadea 100644
--- a/src/bin/dhcp6/Makefile.am
+++ b/src/bin/dhcp6/Makefile.am
@@ -46,6 +46,7 @@ pkglibexec_PROGRAMS = b10-dhcp6
b10_dhcp6_SOURCES = main.cc
b10_dhcp6_SOURCES += ctrl_dhcp6_srv.cc ctrl_dhcp6_srv.h
+b10_dhcp6_SOURCES += config_parser.cc config_parser.h
b10_dhcp6_SOURCES += dhcp6_log.cc dhcp6_log.h
b10_dhcp6_SOURCES += dhcp6_srv.cc dhcp6_srv.h
@@ -62,6 +63,7 @@ b10_dhcp6_LDADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcpsrv.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
diff --git a/src/bin/dhcp6/config_parser.cc b/src/bin/dhcp6/config_parser.cc
new file mode 100644
index 0000000..dbffc40
--- /dev/null
+++ b/src/bin/dhcp6/config_parser.cc
@@ -0,0 +1,797 @@
+// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <stdint.h>
+#include <iostream>
+#include <vector>
+#include <map>
+#include <boost/foreach.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+#include <asiolink/io_address.h>
+#include <cc/data.h>
+#include <config/ccsession.h>
+#include <log/logger_support.h>
+#include <dhcp/triplet.h>
+#include <dhcp/pool.h>
+#include <dhcp/subnet.h>
+#include <dhcp/cfgmgr.h>
+#include <dhcp6/config_parser.h>
+#include <dhcp6/dhcp6_log.h>
+
+using namespace std;
+using namespace isc::data;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+
+/// @brief auxiliary type used for storing element name and its parser
+typedef pair<string, ConstElementPtr> ConfigPair;
+
+/// @brief a factory method that will create a parser for a given element name
+typedef DhcpConfigParser* ParserFactory(const std::string& config_id);
+
+/// @brief a collection of factories that creates parsers for specified element names
+typedef std::map<std::string, ParserFactory*> FactoryMap;
+
+/// @brief a collection of elements that store uint32 values (e.g. renew-timer = 900)
+typedef std::map<string, uint32_t> Uint32Storage;
+
+/// @brief a collection of elements that store string values
+typedef std::map<string, string> StringStorage;
+
+/// @brief a collection of pools
+///
+/// That type is used as intermediate storage, when pools are parsed, but there is
+/// no subnet object created yet to store them.
+typedef std::vector<Pool6Ptr> PoolStorage;
+
+/// @brief Global uint32 parameters that will be used as defaults.
+Uint32Storage uint32_defaults;
+
+/// @brief global string parameters that will be used as defaults.
+StringStorage string_defaults;
+
+/// @brief a dummy configuration parser
+///
+/// It is a debugging parser. It does not configure anything,
+/// will accept any configuration and will just print it out
+/// on commit. Useful for debugging existing configurations and
+/// adding new ones.
+class DebugParser : public DhcpConfigParser {
+public:
+
+ /// @brief Constructor
+ ///
+ /// See \ref DhcpConfigParser class for details.
+ ///
+ /// @param param_name name of the parsed parameter
+ DebugParser(const std::string& param_name)
+ :param_name_(param_name) {
+ }
+
+ /// @brief builds parameter value
+ ///
+ /// See \ref DhcpConfigParser class for details.
+ ///
+ /// @param new_config pointer to the new configuration
+ virtual void build(ConstElementPtr new_config) {
+ std::cout << "Build for token: [" << param_name_ << "] = ["
+ << value_->str() << "]" << std::endl;
+ value_ = new_config;
+ }
+
+ /// @brief pretends to apply the configuration
+ ///
+ /// This is a method required by base class. It pretends to apply the
+ /// configuration, but in fact it only prints the parameter out.
+ ///
+ /// See \ref DhcpConfigParser class for details.
+ virtual void commit() {
+ // Debug message. The whole DebugParser class is used only for parser
+ // debugging, and is not used in production code. It is very convenient
+ // to keep it around. Please do not turn this cout into logger calls.
+ std::cout << "Commit for token: [" << param_name_ << "] = ["
+ << value_->str() << "]" << std::endl;
+ }
+
+ /// @brief factory that constructs DebugParser objects
+ ///
+ /// @param param_name name of the parameter to be parsed
+ static DhcpConfigParser* Factory(const std::string& param_name) {
+ return (new DebugParser(param_name));
+ }
+
+protected:
+ /// name of the parsed parameter
+ std::string param_name_;
+
+ /// pointer to the actual value of the parameter
+ ConstElementPtr value_;
+};
+
+/// @brief Configuration parser for uint32 parameters
+///
+/// This class is a generic parser that is able to handle any uint32 integer
+/// type. By default it stores the value in external global container
+/// (uint32_defaults). If used in smaller scopes (e.g. to parse parameters
+/// in subnet config), it can be pointed to a different storage, using
+/// setStorage() method. This class follows the parser interface, laid out
+/// in its base class, \ref DhcpConfigParser.
+///
+/// For overview of usability of this generic purpose parser, see
+/// \ref dhcpv6-config-inherit page.
+class Uint32Parser : public DhcpConfigParser {
+public:
+
+ /// @brief constructor for Uint32Parser
+ /// @param param_name name of the configuration parameter being parsed
+ Uint32Parser(const std::string& param_name)
+ :storage_(&uint32_defaults), param_name_(param_name) {
+ }
+
+ /// @brief builds parameter value
+ ///
+ /// Parses configuration entry and stores it in a storage. See
+ /// \ref setStorage() for details.
+ ///
+ /// @param value pointer to the content of parsed values
+ virtual void build(ConstElementPtr value) {
+ try {
+ value_ = boost::lexical_cast<uint32_t>(value->str());
+ } catch (const boost::bad_lexical_cast &) {
+ isc_throw(BadValue, "Failed to parse value " << value->str()
+ << " as unsigned 32-bit integer.");
+ }
+ storage_->insert(pair<string, uint32_t>(param_name_, value_));
+ }
+
+ /// @brief does nothing
+ ///
+ /// This method is required for all parser. The value itself
+ /// is not commited anywhere. Higher level parsers are expected to
+ /// use values stored in the storage, e.g. renew-timer for a given
+ /// subnet is stored in subnet-specific storage. It is not commited
+ /// here, but is rather used by \ref Subnet6Parser when constructing
+ /// the subnet.
+ virtual void commit() {
+ }
+
+ /// @brief factory that constructs Uint32Parser objects
+ ///
+ /// @param param_name name of the parameter to be parsed
+ static DhcpConfigParser* Factory(const std::string& param_name) {
+ return (new Uint32Parser(param_name));
+ }
+
+ /// @brief sets storage for value of this parameter
+ ///
+ /// See \ref dhcpv6-config-inherit for details.
+ ///
+ /// @param storage pointer to the storage container
+ void setStorage(Uint32Storage* storage) {
+ storage_ = storage;
+ }
+
+protected:
+ /// pointer to the storage, where parsed value will be stored
+ Uint32Storage* storage_;
+
+ /// name of the parameter to be parsed
+ std::string param_name_;
+
+ /// the actual parsed value
+ uint32_t value_;
+};
+
+/// @brief Configuration parser for string parameters
+///
+/// This class is a generic parser that is able to handle any string
+/// parameter. By default it stores the value in external global container
+/// (string_defaults). If used in smaller scopes (e.g. to parse parameters
+/// in subnet config), it can be pointed to a different storage, using
+/// setStorage() method. This class follows the parser interface, laid out
+/// in its base class, \ref DhcpConfigParser.
+///
+/// For overview of usability of this generic purpose parser, see
+/// \ref dhcpv6-config-inherit page.
+class StringParser : public DhcpConfigParser {
+public:
+
+ /// @brief constructor for StringParser
+ /// @param param_name name of the configuration parameter being parsed
+ StringParser(const std::string& param_name)
+ :storage_(&string_defaults), param_name_(param_name) {
+ }
+
+ /// @brief parses parameter value
+ ///
+ /// Parses configuration entry and stored it in storage. See
+ /// \ref setStorage() for details.
+ ///
+ /// @param value pointer to the content of parsed values
+ virtual void build(ConstElementPtr value) {
+ value_ = value->str();
+ boost::erase_all(value_, "\"");
+ storage_->insert(pair<string, string>(param_name_, value_));
+ }
+
+ /// @brief does nothing
+ ///
+ /// This method is required for all parser. The value itself
+ /// is not commited anywhere. Higher level parsers are expected to
+ /// use values stored in the storage, e.g. renew-timer for a given
+ /// subnet is stored in subnet-specific storage. It is not commited
+ /// here, but is rather used by its parent parser when constructing
+ /// an object, e.g. the subnet.
+ virtual void commit() {
+ }
+
+ /// @brief factory that constructs StringParser objects
+ ///
+ /// @param param_name name of the parameter to be parsed
+ static DhcpConfigParser* Factory(const std::string& param_name) {
+ return (new StringParser(param_name));
+ }
+
+ /// @brief sets storage for value of this parameter
+ ///
+ /// See \ref dhcpv6-config-inherit for details.
+ ///
+ /// @param storage pointer to the storage container
+ void setStorage(StringStorage* storage) {
+ storage_ = storage;
+ }
+
+protected:
+ /// pointer to the storage, where parsed value will be stored
+ StringStorage* storage_;
+
+ /// name of the parameter to be parsed
+ std::string param_name_;
+
+ /// the actual parsed value
+ std::string value_;
+};
+
+
+/// @brief parser for interface list definition
+///
+/// This parser handles Dhcp6/interface entry.
+/// It contains a list of network interfaces that the server listens on.
+/// In particular, it can contain an entry called "all" or "any" that
+/// designates all interfaces.
+///
+/// It is useful for parsing Dhcp6/interface parameter.
+class InterfaceListConfigParser : public DhcpConfigParser {
+public:
+
+ /// @brief constructor
+ ///
+ /// As this is a dedicated parser, it must be used to parse
+ /// "interface" parameter only. All other types will throw exception.
+ ///
+ /// @param param_name name of the configuration parameter being parsed
+ InterfaceListConfigParser(const std::string& param_name) {
+ if (param_name != "interface") {
+ isc_throw(NotImplemented, "Internal error. Interface configuration "
+ "parser called for the wrong parameter: " << param_name);
+ }
+ }
+
+ /// @brief parses parameters value
+ ///
+ /// Parses configuration entry (list of parameters) and stores it in
+ /// storage. See \ref setStorage() for details.
+ ///
+ /// @param value pointer to the content of parsed values
+ virtual void build(ConstElementPtr value) {
+ BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
+ interfaces_.push_back(iface->str());
+ }
+ }
+
+ /// @brief commits interfaces list configuration
+ virtual void commit() {
+ /// @todo: Implement per interface listening. Currently always listening
+ /// on all interfaces.
+ }
+
+ /// @brief factory that constructs InterfaceListConfigParser objects
+ ///
+ /// @param param_name name of the parameter to be parsed
+ static DhcpConfigParser* Factory(const std::string& param_name) {
+ return (new InterfaceListConfigParser(param_name));
+ }
+
+protected:
+ /// contains list of network interfaces
+ vector<string> interfaces_;
+};
+
+/// @brief parser for pool definition
+///
+/// This parser handles pool definitions, i.e. a list of entries of one
+/// of two syntaxes: min-max and prefix/len. Pool6 objects are created
+/// and stored in chosen PoolStorage container.
+///
+/// As there are no default values for pool, setStorage() must be called
+/// before build(). Otherwise exception will be thrown.
+///
+/// It is useful for parsing Dhcp6/subnet6[X]/pool parameters.
+class PoolParser : public DhcpConfigParser {
+public:
+
+ /// @brief constructor.
+ PoolParser(const std::string& /*param_name*/)
+ :pools_(NULL) {
+ // ignore parameter name, it is always Dhcp6/subnet6[X]/pool
+ }
+
+ /// @brief parses the actual list
+ ///
+ /// This method parses the actual list of interfaces.
+ /// No validation is done at this stage, everything is interpreted as
+ /// interface name.
+ void build(ConstElementPtr pools_list) {
+ // setStorage() should have been called before build
+ if (!pools_) {
+ isc_throw(NotImplemented, "Parser logic error. No pool storage set,"
+ " but pool parser asked to parse pools");
+ }
+
+ BOOST_FOREACH(ConstElementPtr text_pool, pools_list->listValue()) {
+
+ // That should be a single pool representation. It should contain
+ // text is form prefix/len or first - last. Note that spaces
+ // are allowed
+ string txt = text_pool->stringValue();
+
+ // first let's remove any whitespaces
+ boost::erase_all(txt, " "); // space
+ boost::erase_all(txt, "\t"); // tabulation
+
+ // Is this prefix/len notation?
+ size_t pos = txt.find("/");
+ if (pos != string::npos) {
+ IOAddress addr("::");
+ uint8_t len = 0;
+ try {
+ addr = IOAddress(txt.substr(0, pos));
+
+ // start with the first character after /
+ string prefix_len = txt.substr(pos + 1);
+
+ // It is lexical cast to int and then downcast to uint8_t.
+ // Direct cast to uint8_t (which is really an unsigned char)
+ // will result in interpreting the first digit as output
+ // value and throwing exception if length is written on two
+ // digits (because there are extra characters left over).
+
+ // No checks for values over 128. Range correctness will
+ // be checked in Pool6 constructor.
+ len = boost::lexical_cast<int>(prefix_len);
+ } catch (...) {
+ isc_throw(Dhcp6ConfigError, "Failed to parse pool "
+ "definition: " << text_pool->stringValue());
+ }
+
+ Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, addr, len));
+ pools_->push_back(pool);
+ continue;
+ }
+
+ // Is this min-max notation?
+ pos = txt.find("-");
+ if (pos != string::npos) {
+ // using min-max notation
+ IOAddress min(txt.substr(0,pos - 1));
+ IOAddress max(txt.substr(pos + 1));
+
+ Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, min, max));
+
+ pools_->push_back(pool);
+ continue;
+ }
+
+ isc_throw(Dhcp6ConfigError, "Failed to parse pool definition:"
+ << text_pool->stringValue() <<
+ ". Does not contain - (for min-max) nor / (prefix/len)");
+ }
+ }
+
+ /// @brief sets storage for value of this parameter
+ ///
+ /// See \ref dhcpv6-config-inherit for details.
+ ///
+ /// @param storage pointer to the storage container
+ void setStorage(PoolStorage* storage) {
+ pools_ = storage;
+ }
+
+ /// @brief does nothing.
+ ///
+ /// This method is required for all parser. The value itself
+ /// is not commited anywhere. Higher level parsers (for subnet) are expected
+ /// to use values stored in the storage.
+ virtual void commit() {}
+
+ /// @brief factory that constructs PoolParser objects
+ ///
+ /// @param param_name name of the parameter to be parsed
+ static DhcpConfigParser* Factory(const std::string& param_name) {
+ return (new PoolParser(param_name));
+ }
+
+protected:
+ /// @brief pointer to the actual Pools storage
+ ///
+ /// That is typically a storage somewhere in Subnet parser
+ /// (an upper level parser).
+ PoolStorage* pools_;
+};
+
+/// @brief this class parses a single subnet
+///
+/// This class parses the whole subnet definition. It creates parsers
+/// for received configuration parameters as needed.
+class Subnet6ConfigParser : public DhcpConfigParser {
+public:
+
+ /// @brief constructor
+ Subnet6ConfigParser(const std::string& ) {
+ // The parameter should always be "subnet", but we don't check here
+ // against it in case some wants to reuse this parser somewhere.
+ }
+
+ /// @brief parses parameter value
+ ///
+ /// @param subnet pointer to the content of subnet definition
+ void build(ConstElementPtr subnet) {
+
+ BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
+
+ ParserPtr parser(createSubnet6ConfigParser(param.first));
+
+ // if this is an Uint32 parser, tell it to store the values
+ // in values_, rather than in global storage
+ boost::shared_ptr<Uint32Parser> uintParser =
+ boost::dynamic_pointer_cast<Uint32Parser>(parser);
+ if (uintParser) {
+ uintParser->setStorage(&uint32_values_);
+ } else {
+
+ boost::shared_ptr<StringParser> stringParser =
+ boost::dynamic_pointer_cast<StringParser>(parser);
+ if (stringParser) {
+ stringParser->setStorage(&string_values_);
+ } else {
+
+ boost::shared_ptr<PoolParser> poolParser =
+ boost::dynamic_pointer_cast<PoolParser>(parser);
+ if (poolParser) {
+ poolParser->setStorage(&pools_);
+ }
+ }
+ }
+
+ parser->build(param.second);
+ parsers_.push_back(parser);
+ }
+
+ // Ok, we now have subnet parsed
+ }
+
+ /// @brief commits received configuration.
+ ///
+ /// This method does most of the configuration. Many other parsers are just
+ /// storing the values that are actually consumed here. Pool definitions
+ /// created in other parsers are used here and added to newly created Subnet6
+ /// objects. Subnet6 are then added to DHCP CfgMgr.
+ void commit() {
+
+ StringStorage::const_iterator it = string_values_.find("subnet");
+ if (it == string_values_.end()) {
+ isc_throw(Dhcp6ConfigError,
+ "Mandatory subnet definition in subnet missing");
+ }
+ string subnet_txt = it->second;
+ boost::erase_all(subnet_txt, " ");
+ boost::erase_all(subnet_txt, "\t");
+
+ size_t pos = subnet_txt.find("/");
+ if (pos == string::npos) {
+ isc_throw(Dhcp6ConfigError,
+ "Invalid subnet syntax (prefix/len expected):" << it->second);
+ }
+ IOAddress addr(subnet_txt.substr(0, pos));
+ uint8_t len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
+
+ Triplet<uint32_t> t1 = getParam("renew-timer");
+ Triplet<uint32_t> t2 = getParam("rebind-timer");
+ Triplet<uint32_t> pref = getParam("preferred-lifetime");
+ Triplet<uint32_t> valid = getParam("valid-lifetime");
+
+ /// @todo: Convert this to logger once the parser is working reliably
+ stringstream tmp;
+ tmp << addr.toText() << "/" << (int)len
+ << " with params t1=" << t1 << ", t2=" << t2 << ", pref="
+ << pref << ", valid=" << valid;
+
+ LOG_INFO(dhcp6_logger, DHCP6_CONFIG_NEW_SUBNET).arg(tmp.str());
+
+ Subnet6Ptr subnet(new Subnet6(addr, len, t1, t2, pref, valid));
+
+ for (PoolStorage::iterator it = pools_.begin(); it != pools_.end(); ++it) {
+ subnet->addPool6(*it);
+ }
+
+ CfgMgr::instance().addSubnet6(subnet);
+ }
+
+protected:
+
+ /// @brief creates parsers for entries in subnet definition
+ ///
+ /// @todo Add subnet-specific things here (e.g. subnet-specific options)
+ ///
+ /// @param config_id name od the entry
+ /// @return parser object for specified entry name
+ DhcpConfigParser* createSubnet6ConfigParser(const std::string& config_id) {
+ FactoryMap factories;
+
+ factories.insert(pair<string, ParserFactory*>(
+ "preferred-lifetime", Uint32Parser::Factory));
+ factories.insert(pair<string, ParserFactory*>(
+ "valid-lifetime", Uint32Parser::Factory));
+ factories.insert(pair<string, ParserFactory*>(
+ "renew-timer", Uint32Parser::Factory));
+ factories.insert(pair<string, ParserFactory*>(
+ "rebind-timer", Uint32Parser::Factory));
+
+ factories.insert(pair<string, ParserFactory*>(
+ "subnet", StringParser::Factory));
+
+ factories.insert(pair<string, ParserFactory*>(
+ "pool", PoolParser::Factory));
+
+ FactoryMap::iterator f = factories.find(config_id);
+ if (f == factories.end()) {
+ // Used for debugging only.
+ // return new DebugParser(config_id);
+
+ isc_throw(NotImplemented,
+ "Parser error: Subnet6 parameter not supported: "
+ << config_id);
+ }
+ return (f->second(config_id));
+ }
+
+ /// @brief returns value for a given parameter (after using inheritance)
+ ///
+ /// This method implements inheritance. For a given parameter name, it first
+ /// checks if there is a global value for it and overwrites it with specific
+ /// value if such value was defined in subnet.
+ ///
+ /// @param name name of the parameter
+ /// @return triplet with the parameter name
+ Triplet<uint32_t> getParam(const std::string& name) {
+ uint32_t value = 0;
+ bool found = false;
+ Uint32Storage::iterator global = uint32_defaults.find(name);
+ if (global != uint32_defaults.end()) {
+ value = global->second;
+ found = true;
+ }
+
+ Uint32Storage::iterator local = uint32_values_.find(name);
+ if (local != uint32_values_.end()) {
+ value = local->second;
+ found = true;
+ }
+
+ if (found) {
+ return (Triplet<uint32_t>(value));
+ } else {
+ isc_throw(Dhcp6ConfigError, "Mandatory parameter " << name
+ << " missing (no global default and no subnet-"
+ << "specific value)");
+ }
+ }
+
+ /// storage for subnet-specific uint32 values
+ Uint32Storage uint32_values_;
+
+ /// storage for subnet-specific integer values
+ StringStorage string_values_;
+
+ /// storage for pools belonging to this subnet
+ PoolStorage pools_;
+
+ /// parsers are stored here
+ ParserCollection parsers_;
+};
+
+/// @brief this class parses list of subnets
+///
+/// This is a wrapper parser that handles the whole list of Subnet6
+/// definitions. It iterates over all entries and creates Subnet6ConfigParser
+/// for each entry.
+class Subnets6ListConfigParser : public DhcpConfigParser {
+public:
+
+ /// @brief constructor
+ ///
+ Subnets6ListConfigParser(const std::string&) {
+ /// parameter name is ignored
+ }
+
+ /// @brief parses contents of the list
+ ///
+ /// Iterates over all entries on the list and creates Subnet6ConfigParser
+ /// for each entry.
+ ///
+ /// @param subnets_list pointer to a list of IPv6 subnets
+ void build(ConstElementPtr subnets_list) {
+
+ // No need to define FactoryMap here. There's only one type
+ // used: Subnet6ConfigParser
+
+ BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
+
+ ParserPtr parser(new Subnet6ConfigParser("subnet"));
+ parser->build(subnet);
+ subnets_.push_back(parser);
+ }
+
+ }
+
+ /// @brief commits subnets definitions.
+ ///
+ /// Iterates over all Subnet6 parsers. Each parser contains definitions
+ /// of a single subnet and its parameters and commits each subnet separately.
+ void commit() {
+ // @todo: Implement more subtle reconfiguration than toss
+ // the old one and replace with the new one.
+
+ // remove old subnets
+ CfgMgr::instance().deleteSubnets6();
+
+ BOOST_FOREACH(ParserPtr subnet, subnets_) {
+ subnet->commit();
+ }
+
+ }
+
+ /// @brief Returns Subnet6ListConfigParser object
+ /// @param param_name name of the parameter
+ /// @return Subnets6ListConfigParser object
+ static DhcpConfigParser* Factory(const std::string& param_name) {
+ return (new Subnets6ListConfigParser(param_name));
+ }
+
+ /// @brief collection of subnet parsers.
+ ParserCollection subnets_;
+};
+
+/// @brief creates global parsers
+///
+/// This method creates global parsers that parse global parameters, i.e.
+/// those that take format of Dhcp6/param1, Dhcp6/param2 and so forth.
+///
+/// @param config_id pointer to received global configuration entry
+/// @return parser for specified global DHCPv6 parameter
+DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
+ FactoryMap factories;
+
+ //
+ factories.insert(pair<string, ParserFactory*>(
+ "preferred-lifetime", Uint32Parser::Factory));
+ factories.insert(pair<string, ParserFactory*>(
+ "valid-lifetime", Uint32Parser::Factory));
+ factories.insert(pair<string, ParserFactory*>(
+ "renew-timer", Uint32Parser::Factory));
+ factories.insert(pair<string, ParserFactory*>(
+ "rebind-timer", Uint32Parser::Factory));
+
+ factories.insert(pair<string, ParserFactory*>(
+ "interface", InterfaceListConfigParser::Factory));
+ factories.insert(pair<string, ParserFactory*>(
+ "subnet6", Subnets6ListConfigParser::Factory));
+
+ factories.insert(pair<string, ParserFactory*>(
+ "version", StringParser::Factory));
+
+ FactoryMap::iterator f = factories.find(config_id);
+ if (f == factories.end()) {
+ // Used for debugging only.
+ // return new DebugParser(config_id);
+
+ isc_throw(NotImplemented,
+ "Parser error: Global configuration parameter not supported: "
+ << config_id);
+ }
+ return (f->second(config_id));
+}
+
+/// @brief configures DHCPv6 server
+///
+/// This function is called every time a new configuration is received. The extra
+/// parameter is a reference to DHCPv6 server component. It is currently not used
+/// and CfgMgr::instance() is accessed instead.
+///
+/// This method does not throw. It catches all exceptions and returns them as
+/// reconfiguration statuses. It may return the following response codes:
+/// 0 - configuration successful
+/// 1 - malformed configuration (parsing failed)
+/// 2 - logical error (parsing was successful, but the values are invalid)
+///
+/// @param config_set a new configuration for DHCPv6 server
+/// @return answer that contains result of reconfiguration
+ConstElementPtr
+configureDhcp6Server(Dhcpv6Srv& , ConstElementPtr config_set) {
+ if (!config_set) {
+ isc_throw(Dhcp6ConfigError,
+ "Null pointer is passed to configuration parser");
+ }
+
+ /// @todo: append most essential info here (like "2 new subnets configured")
+ string config_details;
+
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_START).arg(config_set->str());
+
+ ParserCollection parsers;
+ try {
+ BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
+
+ ParserPtr parser(createGlobalDhcpConfigParser(config_pair.first));
+ parser->build(config_pair.second);
+ parsers.push_back(parser);
+ }
+ } catch (const isc::Exception& ex) {
+ ConstElementPtr answer = isc::config::createAnswer(1,
+ string("Configuration parsing failed:") + ex.what());
+ return (answer);
+ } catch (...) {
+ // for things like bad_cast in boost::lexical_cast
+ ConstElementPtr answer = isc::config::createAnswer(1,
+ string("Configuration parsing failed"));
+ }
+
+ try {
+ BOOST_FOREACH(ParserPtr parser, parsers) {
+ parser->commit();
+ }
+ }
+ catch (const isc::Exception& ex) {
+ ConstElementPtr answer = isc::config::createAnswer(2,
+ string("Configuration commit failed:") + ex.what());
+ return (answer);
+ } catch (...) {
+ // for things like bad_cast in boost::lexical_cast
+ ConstElementPtr answer = isc::config::createAnswer(2,
+ string("Configuration commit failed"));
+ }
+
+ LOG_INFO(dhcp6_logger, DHCP6_CONFIG_COMPLETE).arg(config_details);
+
+ ConstElementPtr answer = isc::config::createAnswer(0, "Configuration commited.");
+ return (answer);
+}
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
diff --git a/src/bin/dhcp6/config_parser.h b/src/bin/dhcp6/config_parser.h
new file mode 100644
index 0000000..6758c99
--- /dev/null
+++ b/src/bin/dhcp6/config_parser.h
@@ -0,0 +1,147 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+#include <exceptions/exceptions.h>
+#include <cc/data.h>
+
+#ifndef DHCP6_CONFIG_PARSER_H
+#define DHCP6_CONFIG_PARSER_H
+
+namespace isc {
+namespace dhcp {
+
+class Dhcpv6Srv;
+
+/// An exception that is thrown if an error occurs while configuring an
+/// \c Dhcpv6Srv object.
+class Dhcp6ConfigError : public isc::Exception {
+public:
+
+/// @brief constructor
+///
+/// @param file name of the file, where exception occurred
+/// @param line line of the file, where exception occurred
+/// @param what text description of the issue that caused exception
+Dhcp6ConfigError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+class DhcpConfigParser {
+ ///
+ /// \name Constructors and Destructor
+ ///
+ /// Note: The copy constructor and the assignment operator are
+ /// intentionally defined as private to make it explicit that this is a
+ /// pure base class.
+ //@{
+private:
+ DhcpConfigParser(const DhcpConfigParser& source);
+ DhcpConfigParser& operator=(const DhcpConfigParser& source);
+protected:
+ /// \brief The default constructor.
+ ///
+ /// This is intentionally defined as \c protected as this base class should
+ /// never be instantiated (except as part of a derived class).
+ DhcpConfigParser() {}
+public:
+ /// The destructor.
+ virtual ~DhcpConfigParser() {}
+ //@}
+
+ /// \brief Prepare configuration value.
+ ///
+ /// This method parses the "value part" of the configuration identifier
+ /// that corresponds to this derived class and prepares a new value to
+ /// apply to the server.
+ ///
+ /// This method must validate the given value both in terms of syntax
+ /// and semantics of the configuration, so that the server will be
+ /// validly configured at the time of \c commit(). Note: the given
+ /// configuration value is normally syntactically validated, but the
+ /// \c build() implementation must also expect invalid input. If it
+ /// detects an error it may throw an exception of a derived class
+ /// of \c isc::Exception.
+ ///
+ /// Preparing a configuration value will often require resource
+ /// allocation. If it fails, it may throw a corresponding standard
+ /// exception.
+ ///
+ /// This method is not expected to be called more than once in the
+ /// life of the object. Although multiple calls are not prohibited
+ /// by the interface, the behavior is undefined.
+ ///
+ /// \param config_value The configuration value for the identifier
+ /// corresponding to the derived class.
+ virtual void build(isc::data::ConstElementPtr config_value) = 0;
+
+ /// \brief Apply the prepared configuration value to the server.
+ ///
+ /// This method is expected to be exception free, and, as a consequence,
+ /// it should normally not involve resource allocation.
+ /// Typically it would simply perform exception free assignment or swap
+ /// operation on the value prepared in \c build().
+ /// In some cases, however, it may be very difficult to meet this
+ /// condition in a realistic way, while the failure case should really
+ /// be very rare. In such a case it may throw, and, if the parser is
+ /// called via \c configureDhcp6Server(), the caller will convert the
+ /// exception as a fatal error.
+ ///
+ /// This method is expected to be called after \c build(), and only once.
+ /// The result is undefined otherwise.
+ virtual void commit() = 0;
+};
+
+/// @brief a pointer to configuration parser
+typedef boost::shared_ptr<DhcpConfigParser> ParserPtr;
+
+/// @brief a collection of parsers
+///
+/// This container is used to store pointer to parsers for a given scope.
+typedef std::vector<ParserPtr> ParserCollection;
+
+
+/// \brief Configure an \c Dhcpv6Srv object with a set of configuration values.
+///
+/// This function parses configuration information stored in \c config_set
+/// and configures the \c server by applying the configuration to it.
+/// It provides the strong exception guarantee as long as the underlying
+/// derived class implementations of \c DhcpConfigParser meet the assumption,
+/// that is, it ensures that either configuration is fully applied or the
+/// state of the server is intact.
+///
+/// If a syntax or semantics level error happens during the configuration
+/// (such as malformed configuration or invalid configuration parameter),
+/// this function throws an exception of class \c Dhcp6ConfigError.
+/// If the given configuration requires resource allocation and it fails,
+/// a corresponding standard exception will be thrown.
+/// Other exceptions may also be thrown, depending on the implementation of
+/// the underlying derived class of \c Dhcp6ConfigError.
+/// In any case the strong guarantee is provided as described above except
+/// in the very rare cases where the \c commit() method of a parser throws
+/// an exception. If that happens this function converts the exception
+/// into a \c FatalError exception and rethrows it. This exception is
+/// expected to be caught at the highest level of the application to terminate
+/// the program gracefully.
+///
+/// \param server The \c Dhcpv6Srv object to be configured.
+/// \param config_set A JSON style configuration to apply to \c server.
+isc::data::ConstElementPtr
+configureDhcp6Server(Dhcpv6Srv& server,
+ isc::data::ConstElementPtr config_set);
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
+
+#endif // DHCP6_CONFIG_PARSER_H
diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
index 4afb203..7370583 100644
--- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc
+++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
@@ -25,6 +25,7 @@
#include <dhcp6/ctrl_dhcp6_srv.h>
#include <dhcp6/dhcp6_log.h>
#include <dhcp6/spec_config.h>
+#include <dhcp6/config_parser.h>
#include <dhcp/iface_mgr.h>
#include <exceptions/exceptions.h>
#include <util/buffer.h>
@@ -47,8 +48,15 @@ ConstElementPtr
ControlledDhcpv6Srv::dhcp6ConfigHandler(ConstElementPtr new_config) {
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_UPDATE)
.arg(new_config->str());
- ConstElementPtr answer = isc::config::createAnswer(0,
- "Thank you for sending config.");
+
+ if (server_) {
+ return (configureDhcp6Server(*server_, new_config));
+ }
+
+ // That should never happen as we install config_handler after we instantiate
+ // the server.
+ ConstElementPtr answer = isc::config::createAnswer(1,
+ "Configuration rejected, server is during startup/shutdown phase.");
return (answer);
}
@@ -86,7 +94,7 @@ void ControlledDhcpv6Srv::sessionReader(void) {
}
void ControlledDhcpv6Srv::establishSession() {
-
+
string specfile;
if (getenv("B10_FROM_BUILD")) {
specfile = string(getenv("B10_FROM_BUILD")) +
@@ -96,15 +104,27 @@ void ControlledDhcpv6Srv::establishSession() {
}
/// @todo: Check if session is not established already. Throw, if it is.
-
+
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_CCSESSION_STARTING)
.arg(specfile);
cc_session_ = new Session(io_service_.get_io_service());
config_session_ = new ModuleCCSession(specfile, *cc_session_,
- dhcp6ConfigHandler,
+ NULL,
dhcp6CommandHandler, false);
config_session_->start();
+ // We initially create ModuleCCSession() without configHandler, as
+ // the session module is too eager to send partial configuration.
+ // We want to get the full configuration, so we explicitly call
+ // getFullConfig() and then pass it to our configHandler.
+ config_session_->setConfigHandler(dhcp6ConfigHandler);
+
+ try {
+ configureDhcp6Server(*this, config_session_->getFullConfig());
+ } catch (const Dhcp6ConfigError& ex) {
+ LOG_ERROR(dhcp6_logger, DHCP6_CONFIG_LOAD_FAIL).arg(ex.what());
+ }
+
/// Integrate the asynchronous I/O model of BIND 10 configuration
/// control with the "select" model of the DHCP server. This is
/// fully explained in \ref dhcpv6Session.
diff --git a/src/bin/dhcp6/dhcp6.dox b/src/bin/dhcp6/dhcp6.dox
new file mode 100644
index 0000000..fe842de
--- /dev/null
+++ b/src/bin/dhcp6/dhcp6.dox
@@ -0,0 +1,79 @@
+/**
+ @page dhcpv6 DHCPv6 Server Component
+
+ BIND10 offers DHCPv6 server implementation. It is implemented as
+ b10-dhcp6 component. Its primary code is located in
+ isc::dhcp::Dhcpv6Srv class. It uses \ref libdhcp extensively,
+ especially lib::dhcp::Pkt6, isc::dhcp::Option and
+ isc::dhcp::IfaceMgr classes. Currently this code offers skeleton
+ functionality, i.e. it is able to receive and process incoming
+ requests and trasmit responses. However, it does not have database
+ management, so it returns only one, hardcoded lease to whoever asks
+ for it.
+
+ DHCPv6 server component does not support relayed traffic yet, as
+ support for relay decapsulation is not implemented yet.
+
+ DHCPv6 server component does not use BIND10 logging yet.
+
+ @section dhcpv6-session BIND10 message queue integration
+
+ DHCPv4 server component is now integrated with BIND10 message queue.
+ It follows the same principle as DHCPv4. See \ref dhcpv4Session for
+ details.
+
+ @section dhcpv6-config-parser Configuration Parser in DHCPv6
+
+ b10-dhcp6 component uses BIND10 cfgmgr for commands and configuration. During
+ initial configuration (See \ref
+ isc::dhcp::ControlledDhcpv6Srv::establishSession()), the configuration handler
+ callback is installed (see isc::dhcp::ControlledDhcpv6Srv::dhcp6ConfigHandler().
+ It is called every time there is a new configuration. In particular, it is
+ called every time during daemon start process. It contains a
+ isc::data::ConstElementPtr to a new configuration. This simple handler calls
+ \ref isc::dhcp::configureDhcp6Server() method that processes received configuration.
+
+ This method iterates over list of received configuration elements and creates a
+ list of parsers for each received entry. Parser is an object that is derived
+ from a \ref isc::dhcp::Dhcp6ConfigParser class. Once a parser is created
+ (constructor), its value is set (using build() method). Once all parsers are
+ build, the configuration is then applied ("commited") and commit() method is
+ called.
+
+ All parsers are defined in src/bin/dhcp6/config_parser.cc file. Some of them
+ are generic (e.g. \ref isc::dhcp::Uint32Parser that is able to handle any
+ unsigned 32 bit integer), but some are very specialized (e.g. \ref
+ isc::dhcp::Subnets6ListConfigParser parses definitions of Subnet6 lists). In
+ some cases, e.g. subnet6 definitions, the configuration entry is not a simple
+ value, but a map or a list itself. In such case, the parser iterates over all
+ elements and creates parsers for a given scope. This process may be repeated
+ (sort of) recursively.
+
+ @section dhcpv6-config-inherit DHCPv6 Configuration Inheritance
+
+ One notable useful features of DHCP configuration is its parameter inheritance.
+ For example, renew-timer value may be specified at a global scope and it then
+ applies to all subnets. However, some subnets may have it overwritten with more
+ specific values that takes precedence over global values that are considered
+ defaults. Some parsers (e.g. \ref isc::dhcp::Uint32Parser and \ref
+ isc::dhcp::StringParser) implement that inheritance. By default, they store
+ values in global uint32_defaults and string_defaults storages. However, it is
+ possible to instruct them to store parsed values in more specific
+ storages. That capability is used, e.g. in \ref isc::dhcp::Subnet6ConfigParser
+ that has its own storage that is unique for each subnet. Finally, during commit
+ phase (commit() method), appropriate parsers can use apply parameter inheritance.
+
+ Debugging configuration parser may be confusing. Therefore there is a special
+ class called \ref isc::dhcp::DummyParser. It does not configure anything, but just
+ accepts any parameter of any type. If requested to commit configuration, it will
+ print out received parameter name and its value. This class is not currently used,
+ but it is convenient to have it every time a new parameter is added to DHCP
+ configuration. For that purpose it should be left in the code.
+
+ Parameter inheritance is done during reconfiguration phase, as reconfigurations
+ are rare, so extra logic here is not a problem. On the other hand, values of
+ those parameters may be used thousands times per second, so its use must be as
+ simple as possible. In fact, currently the code has to call Subnet6->getT1() and
+ do not implement any fancy inheritance logic.
+
+ */
diff --git a/src/bin/dhcp6/dhcp6.spec b/src/bin/dhcp6/dhcp6.spec
index 2a82a2d..f35f606 100644
--- a/src/bin/dhcp6/dhcp6.spec
+++ b/src/bin/dhcp6/dhcp6.spec
@@ -4,9 +4,97 @@
"module_description": "DHCPv6 server daemon",
"config_data": [
{ "item_name": "interface",
- "item_type": "string",
+ "item_type": "list",
"item_optional": false,
- "item_default": "eth0"
+ "item_default": [ "all" ],
+ "list_item_spec":
+ {
+ "item_name": "interface_name",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": "all"
+ }
+ } ,
+
+ { "item_name": "renew-timer",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 1000
+ },
+
+ { "item_name": "rebind-timer",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 2000
+ },
+
+ { "item_name": "preferred-lifetime",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 3000
+ },
+
+ { "item_name": "valid-lifetime",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 4000
+ },
+
+ { "item_name": "subnet6",
+ "item_type": "list",
+ "item_optional": false,
+ "item_default": [],
+ "list_item_spec":
+ {
+ "item_name": "single-subnet6",
+ "item_type": "map",
+ "item_optional": false,
+ "item_default": {},
+ "map_item_spec": [
+
+ { "item_name": "subnet",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": ""
+ },
+
+ { "item_name": "renew-timer",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 1000
+ },
+
+ { "item_name": "rebind-timer",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 2000
+ },
+
+ { "item_name": "preferred-lifetime",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 3000
+ },
+
+ { "item_name": "valid-lifetime",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 7200
+ },
+ { "item_name": "pool",
+ "item_type": "list",
+ "item_optional": false,
+ "item_default": [],
+ "list_item_spec":
+ {
+ "item_name": "type",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": ""
+ }
+ }
+ ]
+ }
}
],
"commands": [
diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes
index 1564940..2399c19 100644
--- a/src/bin/dhcp6/dhcp6_messages.mes
+++ b/src/bin/dhcp6/dhcp6_messages.mes
@@ -109,3 +109,23 @@ processed any command-line switches and is starting.
This is a debug message issued during the IPv6 DHCP server startup.
It lists some information about the parameters with which the server
is running.
+
+% DHCP6_CONFIG_LOAD_FAIL failed to load configuration: %1
+This critical error message indicates that the initial DHCPv6
+configuration has failed. The server will start, but nothing will be
+served until the configuration has been corrected.
+
+% DHCP6_CONFIG_START DHCPv6 server is processing the following configuration: %1
+This is a debug message that is issued every time the server receives a
+configuration. That happens start up and also when a server configuration
+change is committed by the administrator.
+
+% DHCP6_CONFIG_NEW_SUBNET A new subnet has been added to configuration: %1
+This is an informational message reporting that the configuration has
+been extended to include the specified subnet.
+
+% DHCP6_CONFIG_COMPLETE DHCPv6 server has completed configuration: %1
+This is an informational message announcing the successful processing of a
+new configuration. it is output during server startup, and when an updated
+configuration is committed by the administrator. Additional information
+may be provided.
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 54fa2b5..7c57a61 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -42,6 +42,13 @@ const uint32_t HARDCODED_VALID_LIFETIME = 7200; // in seconds
const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1";
Dhcpv6Srv::Dhcpv6Srv(uint16_t port) {
+ if (port == 0) {
+ // used for testing purposes. Some tests, e.g. configuration parser,
+ // require Dhcpv6Srv object, but they don't really need it to do
+ // anything. This speed up and simplifies the tests.
+ return;
+ }
+
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET).arg(port);
// First call to instance() will create IfaceMgr (it's a singleton)
diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am
index de87582..1629ae6 100644
--- a/src/bin/dhcp6/tests/Makefile.am
+++ b/src/bin/dhcp6/tests/Makefile.am
@@ -46,9 +46,11 @@ TESTS += dhcp6_unittests
dhcp6_unittests_SOURCES = dhcp6_unittests.cc
dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
dhcp6_unittests_SOURCES += ctrl_dhcp6_srv_unittest.cc
+dhcp6_unittests_SOURCES += config_parser_unittest.cc
dhcp6_unittests_SOURCES += ../dhcp6_srv.h ../dhcp6_srv.cc
dhcp6_unittests_SOURCES += ../dhcp6_log.h ../dhcp6_log.cc
dhcp6_unittests_SOURCES += ../ctrl_dhcp6_srv.cc
+dhcp6_unittests_SOURCES += ../config_parser.cc ../config_parser.h
nodist_dhcp6_unittests_SOURCES = ../dhcp6_messages.h ../dhcp6_messages.cc
if USE_CLANGPP
@@ -62,6 +64,7 @@ dhcp6_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
dhcp6_unittests_LDADD = $(GTEST_LDADD)
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcpsrv.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc
new file mode 100644
index 0000000..22592e8
--- /dev/null
+++ b/src/bin/dhcp6/tests/config_parser_unittest.cc
@@ -0,0 +1,243 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include <dhcp6/dhcp6_srv.h>
+#include <dhcp6/config_parser.h>
+#include <config/ccsession.h>
+#include <dhcp/subnet.h>
+#include <dhcp/cfgmgr.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::data;
+using namespace isc::config;
+
+namespace {
+
+class Dhcp6ParserTest : public ::testing::Test {
+public:
+ Dhcp6ParserTest()
+ :rcode_(-1) {
+ // Open port 0 means to not do anything at all. We don't want to
+ // deal with sockets here, just check if configuration handling
+ // is sane.
+ srv_ = new Dhcpv6Srv(0);
+ }
+
+ ~Dhcp6ParserTest() {
+ delete srv_;
+ };
+
+ Dhcpv6Srv* srv_;
+
+ int rcode_;
+ ConstElementPtr comment_;
+};
+
+// Goal of this test is a verification if a very simple config update
+// with just a bumped version number. That's the simplest possible
+// config update.
+TEST_F(Dhcp6ParserTest, version) {
+
+ ConstElementPtr x;
+
+ EXPECT_NO_THROW(x = configureDhcp6Server(*srv_,
+ Element::fromJSON("{\"version\": 0}")));
+
+ // returned value must be 0 (configuration accepted)
+ ASSERT_TRUE(x);
+ comment_ = parseAnswer(rcode_, x);
+ EXPECT_EQ(0, rcode_);
+}
+
+/// The goal of this test is to verify that the code accepts only
+/// valid commands and malformed or unsupported parameters are rejected.
+TEST_F(Dhcp6ParserTest, bogus_command) {
+
+ ConstElementPtr x;
+
+ EXPECT_NO_THROW(x = configureDhcp6Server(*srv_,
+ Element::fromJSON("{\"bogus\": 5}")));
+
+ // returned value must be 1 (configuration parse error)
+ ASSERT_TRUE(x);
+ comment_ = parseAnswer(rcode_, x);
+ EXPECT_EQ(1, rcode_);
+}
+
+/// The goal of this test is to verify if wrongly defined subnet will
+/// be rejected. Properly defined subnet must include at least one
+/// pool definition.
+TEST_F(Dhcp6ParserTest, empty_subnet) {
+
+ ConstElementPtr status;
+
+ EXPECT_NO_THROW(status = configureDhcp6Server(*srv_,
+ Element::fromJSON("{ \"interface\": [ \"all\" ],"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ ], "
+ "\"valid-lifetime\": 4000 }")));
+
+ // returned value should be 0 (success)
+ ASSERT_TRUE(status);
+ comment_ = parseAnswer(rcode_, status);
+ EXPECT_EQ(0, rcode_);
+}
+
+/// The goal of this test is to verify if defined subnet uses global
+/// parameter timer definitions.
+TEST_F(Dhcp6ParserTest, subnet_global_defaults) {
+
+ ConstElementPtr status;
+
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pool\": [ \"2001:db8:1::1 - 2001:db8:1::ffff\" ],"
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }";
+ cout << config << endl;
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
+
+ // check if returned status is OK
+ ASSERT_TRUE(status);
+ comment_ = parseAnswer(rcode_, status);
+ EXPECT_EQ(0, rcode_);
+
+ // Now check if the configuration was indeed handled and we have
+ // expected pool configured.
+ Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(1000, subnet->getT1());
+ EXPECT_EQ(2000, subnet->getT2());
+ EXPECT_EQ(3000, subnet->getPreferred());
+ EXPECT_EQ(4000, subnet->getValid());
+}
+
+// This test checks if it is possible to override global values
+// on a per subnet basis.
+TEST_F(Dhcp6ParserTest, subnet_local) {
+
+ ConstElementPtr status;
+
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pool\": [ \"2001:db8:1::1 - 2001:db8:1::ffff\" ],"
+ " \"renew-timer\": 1, "
+ " \"rebind-timer\": 2, "
+ " \"preferred-lifetime\": 3,"
+ " \"valid-lifetime\": 4,"
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }";
+ cout << config << endl;
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
+
+ // returned value should be 0 (configuration success)
+ ASSERT_TRUE(status);
+ comment_ = parseAnswer(rcode_, status);
+ EXPECT_EQ(0, rcode_);
+
+ Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(1, subnet->getT1());
+ EXPECT_EQ(2, subnet->getT2());
+ EXPECT_EQ(3, subnet->getPreferred());
+ EXPECT_EQ(4, subnet->getValid());
+}
+
+// Test verifies that a subnet with pool values that do not belong to that
+// pool are rejected.
+TEST_F(Dhcp6ParserTest, pool_out_of_subnet) {
+
+ ConstElementPtr status;
+
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pool\": [ \"4001:db8:1::/80\" ],"
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }";
+ cout << config << endl;
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
+
+ // returned value must be 2 (values error)
+ // as the pool does not belong to that subnet
+ ASSERT_TRUE(status);
+ comment_ = parseAnswer(rcode_, status);
+ EXPECT_EQ(2, rcode_);
+}
+
+// Goal of this test is to verify if pools can be defined
+// using prefix/length notation. There is no separate test for min-max
+// notation as it was tested in several previous tests.
+TEST_F(Dhcp6ParserTest, pool_prefix_len) {
+
+ ConstElementPtr x;
+
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pool\": [ \"2001:db8:1::/80\" ],"
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }";
+ cout << config << endl;
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(x = configureDhcp6Server(*srv_, json));
+
+ // returned value must be 1 (configuration parse error)
+ ASSERT_TRUE(x);
+ comment_ = parseAnswer(rcode_, x);
+ EXPECT_EQ(0, rcode_);
+
+ Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(1000, subnet->getT1());
+ EXPECT_EQ(2000, subnet->getT2());
+ EXPECT_EQ(3000, subnet->getPreferred());
+ EXPECT_EQ(4000, subnet->getValid());
+}
+
+};
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index 1609611..f421347 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -34,7 +34,6 @@
#include <dns/nsec3hash.h>
#include <dns/rdataclass.h>
#include <dns/rrclass.h>
-#include <dns/rrsetlist.h>
#include <dns/masterload.h>
#include <boost/function.hpp>
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index 53cf077..686dd94 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -20,7 +20,6 @@
#include <dns/nsec3hash.h>
#include <dns/rdataclass.h>
#include <dns/rrclass.h>
-#include <dns/rrsetlist.h>
#include <dns/masterload.h>
#include <datasrc/memory_datasrc.h>
diff --git a/src/lib/datasrc/tests/memory/memory_client_unittest.cc b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
index 004f663..c5b6c10 100644
--- a/src/lib/datasrc/tests/memory/memory_client_unittest.cc
+++ b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
@@ -22,7 +22,6 @@
#include <dns/nsec3hash.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
-#include <dns/rrsetlist.h>
#include <dns/rrttl.h>
#include <dns/masterload.h>
diff --git a/src/lib/datasrc/tests/memory_datasrc_unittest.cc b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
index 958c9e1..5223d83 100644
--- a/src/lib/datasrc/tests/memory_datasrc_unittest.cc
+++ b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
@@ -22,7 +22,6 @@
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rrclass.h>
-#include <dns/rrsetlist.h>
#include <dns/rrttl.h>
#include <dns/masterload.h>
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index 4c22b35..6585a38 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -16,6 +16,7 @@ CLEANFILES = *.gcno *.gcda
lib_LTLIBRARIES = libb10-dhcp++.la libb10-dhcpsrv.la
libb10_dhcp___la_SOURCES =
libb10_dhcp___la_SOURCES += libdhcp++.cc libdhcp++.h
+libb10_dhcp___la_SOURCES += lease_mgr.cc lease_mgr.h
libb10_dhcp___la_SOURCES += iface_mgr.cc iface_mgr.h
libb10_dhcp___la_SOURCES += iface_mgr_linux.cc
libb10_dhcp___la_SOURCES += iface_mgr_bsd.cc
@@ -28,6 +29,7 @@ libb10_dhcp___la_SOURCES += option4_addrlst.cc option4_addrlst.h
libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
+libb10_dhcp___la_SOURCES += duid.cc duid.h
libb10_dhcpsrv_la_SOURCES = cfgmgr.cc cfgmgr.h
libb10_dhcpsrv_la_SOURCES += pool.cc pool.h
diff --git a/src/lib/dhcp/addr_utilities.cc b/src/lib/dhcp/addr_utilities.cc
index ad72833..de1e8b4 100644
--- a/src/lib/dhcp/addr_utilities.cc
+++ b/src/lib/dhcp/addr_utilities.cc
@@ -13,17 +13,39 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <string.h>
+#include <exceptions/exceptions.h>
#include <dhcp/addr_utilities.h>
using namespace isc::asiolink;
-namespace isc {
-namespace dhcp {
-
-isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+namespace {
+
+/// @brief mask used for first/last address calculation in a IPv4 prefix
+///
+/// Using a static mask is faster than calculating it dynamically every time.
+const uint32_t bitMask4[] = { 0xffffffff, 0x7fffffff, 0x3fffffff, 0x1fffffff,
+ 0x0fffffff, 0x07ffffff, 0x03ffffff, 0x01ffffff,
+ 0x00ffffff, 0x007fffff, 0x003fffff, 0x001fffff,
+ 0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff,
+ 0x0000ffff, 0x00007fff, 0x00003fff, 0x00001fff,
+ 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff,
+ 0x000000ff, 0x0000007f, 0x0000003f, 0x0000001f,
+ 0x0000000f, 0x00000007, 0x00000003, 0x00000001,
+ 0x00000000 };
+
+/// @brief mask used for first/last address calculation in a IPv6 prefix
+const uint8_t bitMask6[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+
+/// @brief calculates the first IPv6 address in a IPv6 prefix
+///
+/// Note: This is a private function. Do not use it directly.
+/// Please use firstAddrInPrefix() instead.
+///
+/// @param prefix IPv6 prefix
+/// @param len prefix length
+isc::asiolink::IOAddress firstAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
uint8_t len) {
- const static uint8_t bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
uint8_t packed[V6ADDRESS_LEN];
// First we copy the whole address as 16 bytes.
@@ -36,7 +58,7 @@ isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefi
// Get the appropriate mask. It has relevant bits (those that should
// stay) set and irrelevant (those that should be wiped) cleared.
- uint8_t mask = bitMask[len % 8];
+ uint8_t mask = bitMask6[len % 8];
// Let's leave only whatever the mask says should not be cleared.
packed[len / 8] = packed[len / 8] & mask;
@@ -55,10 +77,50 @@ isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefi
return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
}
-isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+/// @brief calculates the first IPv4 address in a IPv4 prefix
+///
+/// Note: This is a private function. Do not use it directly.
+/// Please use firstAddrInPrefix() instead.
+///
+/// @param prefix IPv4 prefix
+/// @param len netmask length (0-32)
+isc::asiolink::IOAddress firstAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+ uint32_t addr = prefix;
+ if (len > 32) {
+ isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4");
+ }
+
+ return (IOAddress(addr & (~bitMask4[len])));
+}
+
+/// @brief calculates the last IPv4 address in a IPv4 prefix
+///
+/// Note: This is a private function. Do not use it directly.
+/// Please use firstAddrInPrefix() instead.
+///
+/// @param prefix IPv4 prefix that we calculate first address for
+/// @param len netmask length (0-32)
+isc::asiolink::IOAddress lastAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+ uint32_t addr = prefix;
+ if (len>32) {
+ isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4");
+ }
+
+ return (IOAddress(addr | bitMask4[len]));
+}
+
+/// @brief calculates the last IPv6 address in a IPv6 prefix
+///
+/// Note: This is a private function. Do not use it directly.
+/// Please use lastAddrInPrefix() instead.
+///
+/// @param prefix IPv6 prefix that we calculate first address for
+/// @param len netmask length (0-128)
+isc::asiolink::IOAddress lastAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
uint8_t len) {
- const static uint8_t bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
uint8_t packed[V6ADDRESS_LEN];
// First we copy the whole address as 16 bytes.
@@ -70,10 +132,10 @@ isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix
if (len % 8 != 0) {
// Get the appropriate mask. It has relevant bits (those that should
// stay) set and irrelevant (those that should be set to 1) cleared.
- uint8_t mask = bitMask[len % 8];
+ uint8_t mask = bitMask6[len % 8];
// Let's set those irrelevant bits with 1. It would be perhaps
- // easier to not use negation here and invert bitMask content. However,
+ // easier to not use negation here and invert bitMask6 content. However,
// with this approach, we can use the same mask in first and last
// address calculations.
packed[len / 8] = packed[len / 8] | ~mask;
@@ -92,5 +154,28 @@ isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix
return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
}
+}; // end of anonymous namespace
+
+namespace isc {
+namespace dhcp {
+
+isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+ if (prefix.getFamily() == AF_INET) {
+ return firstAddrInPrefix4(prefix, len);
+ } else {
+ return firstAddrInPrefix6(prefix, len);
+ }
+}
+
+isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+ if (prefix.getFamily() == AF_INET) {
+ return lastAddrInPrefix4(prefix, len);
+ } else {
+ return lastAddrInPrefix6(prefix, len);
+ }
+}
+
};
};
diff --git a/src/lib/dhcp/cfgmgr.cc b/src/lib/dhcp/cfgmgr.cc
index 15e3ad9..d06544c 100644
--- a/src/lib/dhcp/cfgmgr.cc
+++ b/src/lib/dhcp/cfgmgr.cc
@@ -68,6 +68,39 @@ void CfgMgr::addSubnet6(const Subnet6Ptr& subnet) {
subnets6_.push_back(subnet);
}
+Subnet4Ptr
+CfgMgr::getSubnet4(const isc::asiolink::IOAddress& hint) {
+
+ // If there's only one subnet configured, let's just use it
+ // The idea is to keep small deployments easy. In a small network - one
+ // router that also runs DHCPv6 server. Users specifies a single pool and
+ // expects it to just work. Without this, the server would complain that it
+ // doesn't have IP address on its interfaces that matches that
+ // configuration. Such requirement makes sense in IPv4, but not in IPv6.
+ // The server does not need to have a global address (using just link-local
+ // is ok for DHCPv6 server) from the pool it serves.
+ if (subnets4_.size() == 1) {
+ return (subnets4_[0]);
+ }
+
+ // If there is more than one, we need to choose the proper one
+ for (Subnet4Collection::iterator subnet = subnets4_.begin();
+ subnet != subnets4_.end(); ++subnet) {
+ if ((*subnet)->inRange(hint)) {
+ return (*subnet);
+ }
+ }
+
+ // sorry, we don't support that subnet
+ return (Subnet4Ptr());
+}
+
+void CfgMgr::addSubnet4(const Subnet4Ptr& subnet) {
+ /// @todo: Check that this new subnet does not cross boundaries of any
+ /// other already defined subnet.
+ subnets4_.push_back(subnet);
+}
+
CfgMgr::CfgMgr() {
}
diff --git a/src/lib/dhcp/cfgmgr.h b/src/lib/dhcp/cfgmgr.h
index 5b73f2b..2911d05 100644
--- a/src/lib/dhcp/cfgmgr.h
+++ b/src/lib/dhcp/cfgmgr.h
@@ -72,7 +72,7 @@ public:
/// accessing it.
static CfgMgr& instance();
- /// @brief get subnet by address
+ /// @brief get IPv6 subnet by address
///
/// Finds a matching subnet, based on an address. This can be used
/// in two cases: when trying to find an appropriate lease based on
@@ -83,7 +83,7 @@ public:
/// @param hint an address that belongs to a searched subnet
Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint);
- /// @brief get subnet by interface-id
+ /// @brief get IPv6 subnet by interface-id
///
/// Another possibility to find a subnet is based on interface-id.
///
@@ -91,13 +91,44 @@ public:
/// @todo This method is not currently supported.
Subnet6Ptr getSubnet6(OptionPtr interface_id);
- /// @brief adds a subnet6
+ /// @brief adds an IPv6 subnet
void addSubnet6(const Subnet6Ptr& subnet);
/// @todo: Add subnet6 removal routines. Currently it is not possible
/// to remove subnets. The only case where subnet6 removal would be
/// needed is a dynamic server reconfiguration - a use case that is not
/// planned to be supported any time soon.
+
+ /// @brief removes all subnets
+ ///
+ /// This method removes all existing subnets. It is used during
+ /// reconfiguration - old configuration is wiped and new definitions
+ /// are used to recreate subnets.
+ ///
+ /// @todo Implement more intelligent approach. Note that comparison
+ /// between old and new configuration is tricky. For example: is
+ /// 2000::/64 and 2000::/48 the same subnet or is it something
+ /// completely new?
+ void deleteSubnets6() {
+ subnets6_.clear();
+ }
+
+ /// @brief get IPv4 subnet by address
+ ///
+ /// Finds a matching subnet, based on an address. This can be used
+ /// in two cases: when trying to find an appropriate lease based on
+ /// a) relay link address (that must be the address that is on link)
+ /// b) our global address on the interface the message was received on
+ /// (for directly connected clients)
+ ///
+ /// @param hint an address that belongs to a searched subnet
+ Subnet4Ptr getSubnet4(const isc::asiolink::IOAddress& hint);
+
+ /// @brief adds a subnet4
+ void addSubnet4(const Subnet4Ptr& subnet);
+
+ /// @brief removes all IPv4 subnets
+ void removeSubnets4();
protected:
/// @brief Protected constructor.
@@ -111,13 +142,21 @@ protected:
/// @brief virtual desctructor
virtual ~CfgMgr();
- /// @brief a container for Subnet6
+ /// @brief a container for IPv6 subnets.
///
/// That is a simple vector of pointers. It does not make much sense to
/// optimize access time (e.g. using a map), because typical search
/// pattern will use calling inRange() method on each subnet until
/// a match is found.
Subnet6Collection subnets6_;
+
+ /// @brief a container for IPv4 subnets.
+ ///
+ /// That is a simple vector of pointers. It does not make much sense to
+ /// optimize access time (e.g. using a map), because typical search
+ /// pattern will use calling inRange() method on each subnet until
+ /// a match is found.
+ Subnet4Collection subnets4_;
};
} // namespace isc::dhcp
diff --git a/src/lib/dhcp/duid.cc b/src/lib/dhcp/duid.cc
new file mode 100644
index 0000000..db7ba25
--- /dev/null
+++ b/src/lib/dhcp/duid.cc
@@ -0,0 +1,90 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <vector>
+#include <exceptions/exceptions.h>
+#include <stdint.h>
+#include <util/io_utilities.h>
+#include <dhcp/duid.h>
+
+namespace isc {
+namespace dhcp {
+
+DUID::DUID(const std::vector<uint8_t>& duid) {
+ if (duid.size() > MAX_DUID_LEN) {
+ isc_throw(OutOfRange, "DUID too large");
+ } else {
+ duid_ = duid;
+ }
+}
+
+DUID::DUID(const uint8_t * data, size_t len) {
+ if (len > MAX_DUID_LEN) {
+ isc_throw(OutOfRange, "DUID too large");
+ }
+
+ duid_ = std::vector<uint8_t>(data, data + len);
+}
+
+const std::vector<uint8_t> DUID::getDuid() const {
+ return (duid_);
+}
+
+DUID::DUIDType DUID::getType() const {
+ if (duid_.size() < 2) {
+ return (DUID_UNKNOWN);
+ }
+ uint16_t type = (duid_[0] << 8) + duid_[1];
+ if (type < DUID_MAX) {
+ return (static_cast<DUID::DUIDType>(type));
+ } else {
+ return (DUID_UNKNOWN);
+ }
+}
+
+bool DUID::operator == (const DUID& other) const {
+ return (this->duid_ == other.duid_);
+}
+
+bool DUID::operator != (const DUID& other) const {
+ return (this->duid_ != other.duid_);
+}
+
+/// constructor based on vector<uint8_t>
+ClientId::ClientId(const std::vector<uint8_t>& clientid)
+ :DUID(clientid) {
+}
+
+/// constructor based on C-style data
+ClientId::ClientId(const uint8_t *clientid, size_t len)
+ :DUID(clientid, len) {
+}
+
+/// @brief returns a copy of client-id data
+const std::vector<uint8_t> ClientId::getClientId() const {
+ return (duid_);
+}
+
+// compares two client-ids
+bool ClientId::operator == (const ClientId& other) const {
+ return (this->duid_ == other.duid_);
+}
+
+// compares two client-ids
+bool ClientId::operator != (const ClientId& other) const {
+ return (this->duid_ != other.duid_);
+}
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
diff --git a/src/lib/dhcp/duid.h b/src/lib/dhcp/duid.h
new file mode 100644
index 0000000..53257db
--- /dev/null
+++ b/src/lib/dhcp/duid.h
@@ -0,0 +1,98 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <stdint.h>
+#include <unistd.h>
+#include <vector>
+#include <asiolink/io_address.h>
+
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Holds DUID (DHCPv6 Unique Identifier)
+///
+/// This class holds DUID, that is used in client-id, server-id and
+/// several other options. It is used to identify DHCPv6 entity.
+class DUID {
+ public:
+ /// @brief maximum duid size
+ /// As defined in RFC3315, section 9.1
+ static const size_t MAX_DUID_LEN = 128;
+
+ /// @brief specifies DUID type
+ typedef enum {
+ DUID_UNKNOWN = 0, ///< invalid/unknown type
+ DUID_LLT = 1, ///< link-layer + time, see RFC3315, section 9.2
+ DUID_EN = 2, ///< enterprise-id, see RFC3315, section 9.3
+ DUID_LL = 3, ///< link-layer, see RFC3315, section 9.4
+ DUID_UUID = 4, ///< UUID, see RFC6355
+ DUID_MAX ///< not a real type, just maximum defined value + 1
+ } DUIDType;
+
+ /// @brief creates a DUID
+ DUID(const std::vector<uint8_t>& duid);
+
+ /// @brief creates a DUID
+ DUID(const uint8_t *duid, size_t len);
+
+ /// @brief returns a const reference to the actual DUID value
+ ///
+ /// Note: For safety reasons, this method returns a copy of data as
+ /// otherwise the reference would be only valid as long as the object that
+ /// returned it. In any case, this method should be used only sporadically.
+ /// If there are frequent uses, we must implement some other method
+ /// (e.g. storeSelf()) that will avoid data copying.
+ const std::vector<uint8_t> getDuid() const;
+
+ /// @brief returns DUID type
+ DUIDType getType() const;
+
+ // compares two DUIDs
+ bool operator == (const DUID& other) const;
+
+ // compares two DUIDs
+ bool operator != (const DUID& other) const;
+
+ protected:
+ /// the actual content of the DUID
+ std::vector<uint8_t> duid_;
+};
+
+/// @brief Holds Client identifier or client IPv4 address
+///
+/// This class is intended to be a generic IPv4 client identifier. It can hold
+/// a client-id
+class ClientId : DUID {
+ public:
+
+ /// constructor based on vector<uint8_t>
+ ClientId(const std::vector<uint8_t>& clientid);
+
+ /// constructor based on C-style data
+ ClientId(const uint8_t *clientid, size_t len);
+
+ /// @brief returns reference to the client-id data
+ ///
+ const std::vector<uint8_t> getClientId() const;
+
+ // compares two client-ids
+ bool operator == (const ClientId& other) const;
+
+ // compares two client-ids
+ bool operator != (const ClientId& other) const;
+};
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
diff --git a/src/lib/dhcp/lease_mgr.cc b/src/lib/dhcp/lease_mgr.cc
new file mode 100644
index 0000000..d09bd58
--- /dev/null
+++ b/src/lib/dhcp/lease_mgr.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <sstream>
+#include <iostream>
+#include <map>
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <algorithm>
+#include <iterator>
+#include <exceptions/exceptions.h>
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string.hpp>
+#include "lease_mgr.h"
+
+using namespace std;
+
+using namespace isc::dhcp;
+
+LeaseMgr::LeaseMgr(const std::string& dbconfig) {
+
+ if (dbconfig.length() == 0) {
+ return;
+ }
+
+ vector<string> tokens;
+
+ // we need to pass a string to is_any_of, not just char *. Otherwise there
+ // are cryptic warnings on Debian6 running g++ 4.4 in /usr/include/c++/4.4
+ // /bits/stl_algo.h:2178 "array subscript is above array bounds"
+ boost::split(tokens, dbconfig, boost::is_any_of( string("\t ") ));
+ BOOST_FOREACH(std::string token, tokens) {
+ size_t pos = token.find("=");
+ if (pos != string::npos) {
+ string name = token.substr(0, pos);
+ string value = token.substr(pos + 1, -1);
+ parameters_.insert(pair<string,string>(name, value));
+ } else {
+ isc_throw(InvalidParameter, "Cannot parse " << token
+ << ", expected format is name=value");
+ }
+
+ }
+}
+
+std::string LeaseMgr::getParameter(const std::string& name) const {
+ std::map<std::string, std::string>::const_iterator param
+ = parameters_.find(name);
+ if (param == parameters_.end()) {
+ isc_throw(BadValue, "Parameter not found");
+ }
+ return (param->second);
+}
+
+LeaseMgr::~LeaseMgr() {
+}
diff --git a/src/lib/dhcp/lease_mgr.h b/src/lib/dhcp/lease_mgr.h
new file mode 100644
index 0000000..4b7a1af
--- /dev/null
+++ b/src/lib/dhcp/lease_mgr.h
@@ -0,0 +1,480 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+#include <fstream>
+#include <vector>
+#include <map>
+#include <asiolink/io_address.h>
+#include <boost/shared_ptr.hpp>
+#include <dhcp/option.h>
+#include <dhcp/duid.h>
+
+/// @file dhcp/lease_mgr.h
+/// @brief An abstract API for lease database
+///
+/// This file contains declarations of Lease4, Lease6 and LeaseMgr classes.
+/// They are essential components of the interface to any database backend.
+/// Each concrete database backend (e.g. MySQL) will define a class derived
+/// from LeaseMgr class.
+///
+/// Failover considerations:
+/// There are no intermediate plans to implement DHCPv4 failover
+/// (draft-ietf-dhc-failover-12.txt). Currently (Oct. 2012) the DHCPv6 failover
+/// is being defined in DHC WG in IETF (draft-ietf-dhcpv6-failover-requirements,
+/// draft-ietf-dhcpv6-dailover-design), but the work is not advanced enough
+/// for implementation plans yet. v4 failover requires additional parameters
+/// to be kept with a lease. It is likely that v6 failover will require similar
+/// fields. Such implementation will require database schema extension.
+/// We have designed a way to expand/upgrade schemas during upgrades: a database
+/// schema is versioned and sanity checks about required version will be done
+/// upon start and/or upgrade. With this mechanism in place, we can add new
+/// fields to the database. In particular we can use that capability to
+/// introduce failover related fields.
+///
+/// However, there is another approach that can be reliably used to provide
+/// failover, even without the actual failover protocol implemented. As the
+/// first backend will use MySQL, we will be able to use Multi-Master capability
+/// offered by MySQL and use two separatate Kea instances connecting to the
+/// same database.
+///
+/// Nevertheless, we hope to have failover protocol eventually implemented in
+/// the Kea.
+
+namespace isc {
+namespace dhcp {
+
+/// @brief specifies unique subnet identifier
+/// @todo: Move this to subnet.h once ticket #2237 is merged
+typedef uint32_t SubnetID;
+
+/// @brief Structure that holds a lease for IPv4 address
+///
+/// For performance reasons it is a simple structure, not a class. If we chose
+/// make it a class, all fields would have to made private and getters/setters
+/// would be required. As this is a critical part of the code that will be used
+/// extensively, direct access is warranted.
+struct Lease4 {
+ /// IPv4 address
+ isc::asiolink::IOAddress addr_;
+
+ /// @brief Address extension
+ ///
+ /// It is envisaged that in some cases IPv4 address will be accompanied with some
+ /// additional data. One example of such use are Address + Port solutions (or
+ /// Port-restricted Addresses), where several clients may get the same address, but
+ /// different port ranges. This feature is not expected to be widely used.
+ /// Under normal circumstances, the value should be 0.
+ uint32_t ext_;
+
+ /// @brief hardware address
+ std::vector<uint8_t> hwaddr_;
+
+ /// @brief client identifier
+ boost::shared_ptr<ClientId> client_id_;
+
+ /// @brief renewal timer
+ ///
+ /// Specifies renewal time. Although technically it is a property of IA container,
+ /// not the address itself, since our data model does not define separate IA
+ /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
+ /// for the same IA, each must have consistent T1 and T2 values. Specified in
+ /// seconds since cltt.
+ uint32_t t1_;
+
+ /// @brief rebinding timer
+ ///
+ /// Specifies rebinding time. Although technically it is a property of IA container,
+ /// not the address itself, since our data model does not define separate IA
+ /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
+ /// for the same IA, each must have consistent T1 and T2 values. Specified in
+ /// seconds since cltt.
+ uint32_t t2_;
+
+ /// @brief valid lifetime
+ ///
+ /// Expressed as number of seconds since cltt
+ uint32_t valid_lft_;
+
+ /// @brief client last transmission time
+ ///
+ /// Specifies a timestamp, when last transmission from a client was received.
+ time_t cltt_;
+
+ /// @brief Subnet identifier
+ ///
+ /// Specifies subnet-id of the subnet that the lease belongs to
+ SubnetID subnet_id_;
+
+ /// @brief Is this a fixed lease?
+ ///
+ /// Fixed leases are kept after they are released/expired.
+ bool fixed_;
+
+ /// @brief client hostname
+ ///
+ /// This field may be empty
+ std::string hostname_;
+
+ /// @brief did we update AAAA record for this lease?
+ bool fqdn_fwd_;
+
+ /// @brief did we update PTR record for this lease?
+ bool fqdn_rev_;
+
+ /// @brief Lease comments.
+ ///
+ /// Currently not used. It may be used for keeping comments made by the
+ /// system administrator.
+ std::string comments_;
+
+ /// @todo: Add DHCPv4 failover related fields here
+};
+
+/// @brief Pointer to a Lease4 structure.
+typedef boost::shared_ptr<Lease4> Lease4Ptr;
+
+/// @brief A collection of IPv4 leases.
+typedef std::vector< boost::shared_ptr<Lease4Ptr> > Lease4Collection;
+
+/// @brief Structure that holds a lease for IPv6 address and/or prefix
+///
+/// For performance reasons it is a simple structure, not a class. Had we chose to
+/// make it a class, all fields would have to be made private and getters/setters
+/// would be required. As this is a critical part of the code that will be used
+/// extensively, direct access rather than through getters/setters is warranted.
+struct Lease6 {
+ typedef enum {
+ LEASE_IA_NA, /// the lease contains non-temporary IPv6 address
+ LEASE_IA_TA, /// the lease contains temporary IPv6 address
+ LEASE_IA_PD /// the lease contains IPv6 prefix (for prefix delegation)
+ } LeaseType;
+
+ /// @brief specifies lease type (normal addr, temporary addr, prefix)
+ LeaseType type_;
+
+ /// IPv6 address
+ isc::asiolink::IOAddress addr_;
+
+ /// IPv6 prefix length (used only for PD)
+ uint8_t prefixlen_;
+
+ /// @brief IAID
+ ///
+ /// Identity Association IDentifier. DHCPv6 stores all addresses and prefixes
+ /// in IA containers (IA_NA, IA_TA, IA_PD). Most containers may appear more
+ /// than once in a message. To differentiate between them, IAID field is present
+ uint32_t iaid_;
+
+ /// @brief hardware address
+ ///
+ /// This field is not really used and is optional at best. The concept of identifying
+ /// clients by their hardware address was replaced in DHCPv6 by DUID concept. Each
+ /// client has its own unique DUID (DHCP Unique IDentifier). Furthermore, client's
+ /// HW address is not always available, because client may be behind a relay (relay
+ /// stores only link-local address).
+ std::vector<uint8_t> hwaddr_;
+
+ /// @brief client identifier
+ boost::shared_ptr<DUID> duid_;
+
+ /// @brief preferred lifetime
+ ///
+ /// This parameter specifies preferred lifetime since the lease was assigned/renewed
+ /// (cltt), expressed in seconds.
+ uint32_t preferred_lft_;
+
+ /// @brief valid lifetime
+ ///
+ /// This parameter specified valid lifetime since the lease was assigned/renewed
+ /// (cltt), expressed in seconds.
+ uint32_t valid_lft_;
+
+ /// @brief T1 timer
+ ///
+ /// Specifies renewal time. Although technically it is a property of IA container,
+ /// not the address itself, since our data model does not define separate IA
+ /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
+ /// for the same IA, each must have consistent T1 and T2 values. Specified in
+ /// seconds since cltt.
+ uint32_t t1_;
+
+ /// @brief T2 timer
+ ///
+ /// Specifies rebinding time. Although technically it is a property of IA container,
+ /// not the address itself, since our data model does not define separate IA
+ /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
+ /// for the same IA, each must have consistent T1 and T2 values. Specified in
+ /// seconds since cltt.
+ uint32_t t2_;
+
+ /// @brief client last transmission time
+ ///
+ /// Specifies a timestamp, when last transmission from a client was received.
+ time_t cltt_;
+
+ /// @brief Subnet identifier
+ ///
+ /// Specifies subnet-id of the subnet that the lease belongs to
+ SubnetID subnet_id_;
+
+ /// @brief Is this a fixed lease?
+ ///
+ /// Fixed leases are kept after they are released/expired.
+ bool fixed_;
+
+ /// @brief client hostname
+ ///
+ /// This field may be empty
+ std::string hostname_;
+
+ /// @brief did we update AAAA record for this lease?
+ bool fqdn_fwd_;
+
+ /// @brief did we update PTR record for this lease?
+ bool fqdn_rev_;
+
+ /// @brief Lease comments
+ ///
+ /// This field is currently not used.
+ std::string comments_;
+
+ /// @todo: Add DHCPv6 failover related fields here
+};
+
+/// @brief Pointer to a Lease6 structure.
+typedef boost::shared_ptr<Lease6> Lease6Ptr;
+
+/// @brief Const pointer to a Lease6 structure.
+typedef boost::shared_ptr<const Lease6> ConstLease6Ptr;
+
+/// @brief A collection of IPv6 leases.
+typedef std::vector< boost::shared_ptr<Lease6Ptr> > Lease6Collection;
+
+/// @brief Abstract Lease Manager
+///
+/// This is an abstract API for lease database backends. It provides unified
+/// interface to all backends. As this is an abstract class, it should not
+/// be used directly, but rather specialized derived class should be used
+/// instead.
+class LeaseMgr {
+public:
+
+ /// Client Hardware address
+ typedef std::vector<uint8_t> HWAddr;
+
+ /// @brief The sole lease manager constructor
+ ///
+ /// dbconfig is a generic way of passing parameters. Parameters
+ /// are passed in the "name=value" format, separated by spaces.
+ /// Values may be enclosed in double quotes, if needed.
+ ///
+ /// @param dbconfig database configuration
+ LeaseMgr(const std::string& dbconfig);
+
+ /// @brief Destructor (closes file)
+ virtual ~LeaseMgr();
+
+ /// @brief Adds an IPv4 lease.
+ ///
+ /// @param lease lease to be added
+ virtual bool addLease(Lease4Ptr lease) = 0;
+
+ /// @brief Adds an IPv6 lease.
+ ///
+ /// @param lease lease to be added
+ virtual bool addLease(Lease6Ptr lease) = 0;
+
+ /// @brief Returns existing IPv4 lease for specified IPv4 address and subnet_id
+ ///
+ /// This method is used to get a lease for specific subnet_id. There can be
+ /// at most one lease for any given subnet, so this method returns a single
+ /// pointer.
+ ///
+ /// @param addr address of the searched lease
+ /// @param subnet_id ID of the subnet the lease must belong to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(isc::asiolink::IOAddress addr,
+ SubnetID subnet_id) const = 0;
+
+ /// @brief Returns an IPv4 lease for specified IPv4 address
+ ///
+ /// This method return a lease that is associated with a given address.
+ /// For other query types (by hardware addr, by client-id) there can be
+ /// several leases in different subnets (e.g. for mobile clients that
+ /// got address in different subnets). However, for a single address
+ /// there can be only one lease, so this method returns a pointer to
+ /// a single lease, not a container of leases.
+ ///
+ /// @param addr address of the searched lease
+ /// @param subnet_id ID of the subnet the lease must belong to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(isc::asiolink::IOAddress addr) const = 0;
+
+ /// @brief Returns existing IPv4 leases for specified hardware address.
+ ///
+ /// Although in the usual case there will be only one lease, for mobile
+ /// clients or clients with multiple static/fixed/reserved leases there
+ /// can be more than one. Thus return type is a container, not a single
+ /// pointer.
+ ///
+ /// @param hwaddr hardware address of the client
+ ///
+ /// @return lease collection
+ virtual Lease4Collection getLease4(const HWAddr& hwaddr) const = 0;
+
+ /// @brief Returns existing IPv4 leases for specified hardware address
+ /// and a subnet
+ ///
+ /// There can be at most one lease for a given HW address in a single
+ /// pool, so this method with either return a single lease or NULL.
+ ///
+ /// @param hwaddr hardware address of the client
+ /// @param subnet_id identifier of the subnet that lease must belong to
+ ///
+ /// @return a pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const HWAddr& hwaddr,
+ SubnetID subnet_id) const = 0;
+
+ /// @brief Returns existing IPv4 lease for specified client-id
+ ///
+ /// Although in the usual case there will be only one lease, for mobile
+ /// clients or clients with multiple static/fixed/reserved leases there
+ /// can be more than one. Thus return type is a container, not a single
+ /// pointer.
+ ///
+ /// @param clientid client identifier
+ ///
+ /// @return lease collection
+ virtual Lease4Collection getLease4(const ClientId& clientid) const = 0;
+
+ /// @brief Returns existing IPv4 lease for specified client-id
+ ///
+ /// There can be at most one lease for a given HW address in a single
+ /// pool, so this method with either return a single lease or NULL.
+ ///
+ /// @param clientid client identifier
+ /// @param subnet_id identifier of the subnet that lease must belong to
+ ///
+ /// @return a pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const ClientId& clientid,
+ SubnetID subnet_id) const = 0;
+
+ /// @brief Returns existing IPv6 lease for a given IPv6 address.
+ ///
+ /// For a given address, we assume that there will be only one lease.
+ /// The assumtion here is that there will not be site or link-local
+ /// addresses used, so there is no way of having address duplication.
+ ///
+ /// @param addr address of the searched lease
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease6Ptr getLease6(isc::asiolink::IOAddress addr) const = 0;
+
+ /// @brief Returns existing IPv6 leases for a given DUID+IA combination
+ ///
+ /// Although in the usual case there will be only one lease, for mobile
+ /// clients or clients with multiple static/fixed/reserved leases there
+ /// can be more than one. Thus return type is a container, not a single
+ /// pointer.
+ ///
+ /// @param duid client DUID
+ /// @param iaid IA identifier
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease6Collection getLease6(const DUID& duid,
+ uint32_t iaid) const = 0;
+
+ /// @brief Returns existing IPv6 lease for a given DUID+IA combination
+ ///
+ /// @param duid client DUID
+ /// @param iaid IA identifier
+ /// @param subnet_id subnet id of the subnet the lease belongs to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease6Ptr getLease6(const DUID& duid, uint32_t iaid,
+ SubnetID subnet_id) const = 0;
+
+ /// @brief Updates IPv4 lease.
+ ///
+ /// @param lease4 The lease to be updated.
+ ///
+ /// If no such lease is present, an exception will be thrown.
+ virtual void updateLease4(Lease4Ptr lease4) = 0;
+
+ /// @brief Updates IPv4 lease.
+ ///
+ /// @param lease4 The lease to be updated.
+ ///
+ /// If no such lease is present, an exception will be thrown.
+ virtual void updateLease6(Lease6Ptr lease6) = 0;
+
+ /// @brief Deletes a lease.
+ ///
+ /// @param addr IPv4 address of the lease to be deleted.
+ ///
+ /// @return true if deletion was successful, false if no such lease exists
+ virtual bool deleteLease4(uint32_t addr) = 0;
+
+ /// @brief Deletes a lease.
+ ///
+ /// @param addr IPv4 address of the lease to be deleted.
+ ///
+ /// @return true if deletion was successful, false if no such lease exists
+ virtual bool deleteLease6(isc::asiolink::IOAddress addr) = 0;
+
+ /// @brief Returns backend name.
+ ///
+ /// Each backend have specific name, e.g. "mysql" or "sqlite".
+ virtual std::string getName() const = 0;
+
+ /// @brief Returns description of the backend.
+ ///
+ /// This description may be multiline text that describes the backend.
+ virtual std::string getDescription() const = 0;
+
+ /// @brief Returns backend version.
+ ///
+ /// @todo: We will need to implement 3 version functions eventually:
+ /// A. abstract API version
+ /// B. backend version
+ /// C. database version (stored in the database scheme)
+ ///
+ /// and then check that:
+ /// B>=A and B=C (it is ok to have newer backend, as it should be backward
+ /// compatible)
+ /// Also if B>C, some database upgrade procedure may be triggered
+ virtual std::string getVersion() const = 0;
+
+ /// @todo: Add host management here
+ /// As host reservation is outside of scope for 2012, support for hosts
+ /// is currently postponed.
+
+protected:
+ /// @brief returns value of the parameter
+ std::string getParameter(const std::string& name) const;
+
+ /// @brief list of parameters passed in dbconfig
+ ///
+ /// That will be mostly used for storing database name, username,
+ /// password and other parameters required for DB access. It is not
+ /// intended to keep any DHCP-related parameters.
+ std::map<std::string, std::string> parameters_;
+};
+
+}; // end of isc::dhcp namespace
+
+}; // end of isc namespace
diff --git a/src/lib/dhcp/pool.cc b/src/lib/dhcp/pool.cc
index da8a2e3..1cf47a3 100644
--- a/src/lib/dhcp/pool.cc
+++ b/src/lib/dhcp/pool.cc
@@ -30,6 +30,38 @@ bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
return (first_.smallerEqual(addr) && addr.smallerEqual(last_));
}
+Pool4::Pool4(const isc::asiolink::IOAddress& first,
+ const isc::asiolink::IOAddress& last)
+ :Pool(first, last) {
+ // check if specified address boundaries are sane
+ if (first.getFamily() != AF_INET || last.getFamily() != AF_INET) {
+ isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4");
+ }
+
+ if (last < first) {
+ isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
+ }
+}
+
+Pool4::Pool4(const isc::asiolink::IOAddress& prefix,
+ uint8_t prefix_len)
+ :Pool(prefix, IOAddress("0.0.0.0")) {
+
+ // check if the prefix is sane
+ if (prefix.getFamily() != AF_INET) {
+ isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4");
+ }
+
+ // check if the prefix length is sane
+ if (prefix_len == 0 || prefix_len > 32) {
+ isc_throw(BadValue, "Invalid prefix length");
+ }
+
+ // Let's now calculate the last address in defined pool
+ last_ = lastAddrInPrefix(prefix, prefix_len);
+}
+
+
Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last)
:Pool(first, last), type_(type), prefix_len_(0) {
@@ -52,7 +84,6 @@ Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
// last_ = first;
}
-
// TYPE_PD is not supported by this constructor. first-last style
// parameters are for IA and TA only. There is another dedicated
// constructor for that (it uses prefix/length)
diff --git a/src/lib/dhcp/pool.h b/src/lib/dhcp/pool.h
index 8f6fd86..46f6578 100644
--- a/src/lib/dhcp/pool.h
+++ b/src/lib/dhcp/pool.h
@@ -91,6 +91,33 @@ protected:
std::string comments_;
};
+/// @brief Pool information for IPv4 addresses
+///
+/// It holds information about pool4, i.e. a range of IPv4 address space that
+/// is configured for DHCP allocation.
+class Pool4 : public Pool {
+public:
+ /// @brief the constructor for Pool4 "min-max" style definition
+ ///
+ /// @param first the first address in a pool
+ /// @param last the last address in a pool
+ Pool4(const isc::asiolink::IOAddress& first,
+ const isc::asiolink::IOAddress& last);
+
+ /// @brief the constructor for Pool4 "prefix/len" style definition
+ ///
+ /// @param prefix specifies prefix of the pool
+ /// @param prefix_len specifies length of the prefix of the pool
+ Pool4(const isc::asiolink::IOAddress& prefix,
+ uint8_t prefix_len);
+};
+
+/// @brief a pointer an IPv4 Pool
+typedef boost::shared_ptr<Pool4> Pool4Ptr;
+
+/// @brief a container for IPv4 Pools
+typedef std::vector<Pool4Ptr> Pool4Collection;
+
/// @brief Pool information for IPv6 addresses and prefixes
///
/// It holds information about pool6, i.e. a range of IPv6 address space that
diff --git a/src/lib/dhcp/subnet.cc b/src/lib/dhcp/subnet.cc
index a999295..d0c4cb3 100644
--- a/src/lib/dhcp/subnet.cc
+++ b/src/lib/dhcp/subnet.cc
@@ -41,6 +41,50 @@ bool Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
return ((first <= addr) && (addr <= last));
}
+Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& valid_lifetime)
+ :Subnet(prefix, length, t1, t2, valid_lifetime) {
+ if (prefix.getFamily() != AF_INET) {
+ isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
+ << " specified in subnet4");
+ }
+}
+
+void Subnet4::addPool4(const Pool4Ptr& pool) {
+ IOAddress first_addr = pool->getFirstAddress();
+ IOAddress last_addr = pool->getLastAddress();
+
+ if (!inRange(first_addr) || !inRange(last_addr)) {
+ isc_throw(BadValue, "Pool4 (" << first_addr.toText() << "-" << last_addr.toText()
+ << " does not belong in this (" << prefix_ << "/" << prefix_len_
+ << ") subnet4");
+ }
+
+ /// @todo: Check that pools do not overlap
+
+ pools_.push_back(pool);
+}
+
+Pool4Ptr Subnet4::getPool4(const isc::asiolink::IOAddress& hint /* = IOAddress("::")*/ ) {
+ Pool4Ptr candidate;
+ for (Pool4Collection::iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
+
+ // if we won't find anything better, then let's just use the first pool
+ if (!candidate) {
+ candidate = *pool;
+ }
+
+ // if the client provided a pool and there's a pool that hint is valid in,
+ // then let's use that pool
+ if ((*pool)->inRange(hint)) {
+ return (*pool);
+ }
+ }
+ return (candidate);
+}
+
Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
const Triplet<uint32_t>& t1,
const Triplet<uint32_t>& t2,
diff --git a/src/lib/dhcp/subnet.h b/src/lib/dhcp/subnet.h
index aa59010..7e4e0b7 100644
--- a/src/lib/dhcp/subnet.h
+++ b/src/lib/dhcp/subnet.h
@@ -93,6 +93,57 @@ protected:
Triplet<uint32_t> valid_;
};
+/// @brief A configuration holder for IPv4 subnet.
+///
+/// This class represents an IPv4 subnet.
+class Subnet4 : public Subnet {
+public:
+
+ /// @brief Constructor with all parameters
+ ///
+ /// @param prefix Subnet4 prefix
+ /// @param length prefix length
+ /// @param t1 renewal timer (in seconds)
+ /// @param t2 rebind timer (in seconds)
+ /// @param valid_lifetime preferred lifetime of leases (in seconds)
+ Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& valid_lifetime);
+
+ /// @brief Returns a pool that specified address belongs to
+ ///
+ /// @param hint address that the returned pool should cover (optional)
+ /// @return Pointer to found pool4 (or NULL)
+ Pool4Ptr getPool4(const isc::asiolink::IOAddress& hint =
+ isc::asiolink::IOAddress("0.0.0.0"));
+
+ /// @brief Adds a new pool.
+ /// @param pool pool to be added
+ void addPool4(const Pool4Ptr& pool);
+
+ /// @brief returns all pools
+ ///
+ /// The reference is only valid as long as the object that
+ /// returned it.
+ ///
+ /// @return a collection of all pools
+ const Pool4Collection& getPools() const {
+ return pools_;
+ }
+
+protected:
+ /// @brief collection of pools in that list
+ Pool4Collection pools_;
+};
+
+/// @brief A pointer to a Subnet4 object
+typedef boost::shared_ptr<Subnet4> Subnet4Ptr;
+
+/// @brief A collection of Subnet6 objects
+typedef std::vector<Subnet4Ptr> Subnet4Collection;
+
+
/// @brief A configuration holder for IPv6 subnet.
///
/// This class represents an IPv6 subnet.
diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
index 9fd3492..a15d957 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -28,6 +28,7 @@ TESTS += libdhcp++_unittests libdhcpsrv_unittests
libdhcp___unittests_SOURCES = run_unittests.cc
libdhcp___unittests_SOURCES += libdhcp++_unittest.cc
libdhcp___unittests_SOURCES += iface_mgr_unittest.cc
+libdhcp___unittests_SOURCES += lease_mgr_unittest.cc
libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
libdhcp___unittests_SOURCES += option6_ia_unittest.cc
libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc
@@ -35,6 +36,7 @@ libdhcp___unittests_SOURCES += option4_addrlst_unittest.cc
libdhcp___unittests_SOURCES += option_unittest.cc
libdhcp___unittests_SOURCES += pkt6_unittest.cc
libdhcp___unittests_SOURCES += pkt4_unittest.cc
+libdhcp___unittests_SOURCES += duid_unittest.cc
libdhcp___unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
libdhcp___unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
diff --git a/src/lib/dhcp/tests/addr_utilities_unittest.cc b/src/lib/dhcp/tests/addr_utilities_unittest.cc
index 8382827..2ea4e2a 100644
--- a/src/lib/dhcp/tests/addr_utilities_unittest.cc
+++ b/src/lib/dhcp/tests/addr_utilities_unittest.cc
@@ -26,7 +26,67 @@ using namespace std;
using namespace isc::dhcp;
using namespace isc::asiolink;
-TEST(Pool6Test, lastAddrInPrefix) {
+// This test verifies that lastAddrInPrefix is able to handle IPv4 operations.
+TEST(AddrUtilitiesTest, lastAddrInPrefix4) {
+ IOAddress addr1("192.0.2.1");
+
+ // Prefixes rounded to addresses are easy...
+ EXPECT_EQ("192.255.255.255", lastAddrInPrefix(addr1, 8).toText());
+ EXPECT_EQ("192.0.255.255", lastAddrInPrefix(addr1, 16).toText());
+ EXPECT_EQ("192.0.2.255", lastAddrInPrefix(addr1, 24).toText());
+
+ // these are trickier
+ EXPECT_EQ("192.0.2.127", lastAddrInPrefix(addr1, 25).toText());
+ EXPECT_EQ("192.0.2.63", lastAddrInPrefix(addr1, 26).toText());
+ EXPECT_EQ("192.0.2.31", lastAddrInPrefix(addr1, 27).toText());
+ EXPECT_EQ("192.0.2.15", lastAddrInPrefix(addr1, 28).toText());
+ EXPECT_EQ("192.0.2.7", lastAddrInPrefix(addr1, 29).toText());
+ EXPECT_EQ("192.0.2.3", lastAddrInPrefix(addr1, 30).toText());
+
+ // that doesn't make much sense as /31 subnet consists of network address
+ // and a broadcast address, with 0 usable addresses.
+ EXPECT_EQ("192.0.2.1", lastAddrInPrefix(addr1, 31).toText());
+ EXPECT_EQ("192.0.2.1", lastAddrInPrefix(addr1, 32).toText());
+
+ // Let's check extreme cases
+ IOAddress anyAddr("0.0.0.0");
+ EXPECT_EQ("127.255.255.255", lastAddrInPrefix(anyAddr, 1).toText());
+ EXPECT_EQ("255.255.255.255", lastAddrInPrefix(anyAddr, 0).toText());
+ EXPECT_EQ("0.0.0.0", lastAddrInPrefix(anyAddr, 32).toText());
+}
+
+// This test checks if firstAddrInPrefix is able to handle IPv4 operations.
+TEST(AddrUtilitiesTest, firstAddrInPrefix4) {
+ IOAddress addr1("192.223.2.255");
+
+ // Prefixes rounded to addresses are easy...
+ EXPECT_EQ("192.0.0.0", firstAddrInPrefix(addr1, 8).toText());
+ EXPECT_EQ("192.223.0.0", firstAddrInPrefix(addr1, 16).toText());
+ EXPECT_EQ("192.223.2.0", firstAddrInPrefix(addr1, 24).toText());
+
+ // these are trickier
+ EXPECT_EQ("192.223.2.128", firstAddrInPrefix(addr1, 25).toText());
+ EXPECT_EQ("192.223.2.192", firstAddrInPrefix(addr1, 26).toText());
+ EXPECT_EQ("192.223.2.224", firstAddrInPrefix(addr1, 27).toText());
+ EXPECT_EQ("192.223.2.240", firstAddrInPrefix(addr1, 28).toText());
+ EXPECT_EQ("192.223.2.248", firstAddrInPrefix(addr1, 29).toText());
+ EXPECT_EQ("192.223.2.252", firstAddrInPrefix(addr1, 30).toText());
+
+ // that doesn't make much sense as /31 subnet consists of network address
+ // and a broadcast address, with 0 usable addresses.
+ EXPECT_EQ("192.223.2.254", firstAddrInPrefix(addr1, 31).toText());
+ EXPECT_EQ("192.223.2.255", firstAddrInPrefix(addr1, 32).toText());
+
+ // Let's check extreme cases.
+ IOAddress bcast("255.255.255.255");
+ EXPECT_EQ("128.0.0.0", firstAddrInPrefix(bcast, 1).toText());
+ EXPECT_EQ("0.0.0.0", firstAddrInPrefix(bcast, 0).toText());
+ EXPECT_EQ("255.255.255.255", firstAddrInPrefix(bcast, 32).toText());
+
+}
+
+/// This test checks if lastAddrInPrefix properly supports IPv6 operations
+TEST(AddrUtilitiesTest, lastAddrInPrefix6) {
IOAddress addr1("2001:db8:1:1234:5678:abcd:1234:beef");
// Prefixes rounded to nibbles are easy...
@@ -63,7 +123,8 @@ TEST(Pool6Test, lastAddrInPrefix) {
EXPECT_EQ("::", lastAddrInPrefix(anyAddr, 128).toText());
}
-TEST(Pool6Test, firstAddrInPrefix) {
+/// This test checks if firstAddrInPrefix properly supports IPv6 operations
+TEST(AddrUtilitiesTest, firstAddrInPrefix6) {
IOAddress addr1("2001:db8:1:1234:5678:1234:abcd:beef");
// Prefixes rounded to nibbles are easy...
diff --git a/src/lib/dhcp/tests/cfgmgr_unittest.cc b/src/lib/dhcp/tests/cfgmgr_unittest.cc
index a11acbf..462ca9e 100644
--- a/src/lib/dhcp/tests/cfgmgr_unittest.cc
+++ b/src/lib/dhcp/tests/cfgmgr_unittest.cc
@@ -34,6 +34,38 @@ namespace {
// This test verifies if the configuration manager is able to hold and return
// valid leases
+TEST(CfgMgrTest, subnet4) {
+ CfgMgr& cfg_mgr = CfgMgr::instance();
+
+ ASSERT_TRUE(&cfg_mgr != 0);
+
+ Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
+ Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
+ Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));
+
+ // there shouldn't be any subnet configured at this stage
+ EXPECT_EQ( Subnet4Ptr(), cfg_mgr.getSubnet4(IOAddress("192.0.2.0")));
+
+ cfg_mgr.addSubnet4(subnet1);
+
+ // Now we have only one subnet, any request will be served from it
+ EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.63")));
+
+ // Now we add more subnets and check that both old and new subnets
+ // are accessible.
+ cfg_mgr.addSubnet4(subnet2);
+ cfg_mgr.addSubnet4(subnet3);
+
+ EXPECT_EQ(subnet3, cfg_mgr.getSubnet4(IOAddress("192.0.2.191")));
+ EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.15")));
+ EXPECT_EQ(subnet2, cfg_mgr.getSubnet4(IOAddress("192.0.2.85")));
+
+ // Try to find an address that does not belong to any subnet
+ EXPECT_EQ(Subnet4Ptr(), cfg_mgr.getSubnet4(IOAddress("192.0.2.192")));
+}
+
+// This test verifies if the configuration manager is able to hold and return
+// valid leases
TEST(CfgMgrTest, subnet6) {
CfgMgr& cfg_mgr = CfgMgr::instance();
@@ -58,6 +90,10 @@ TEST(CfgMgrTest, subnet6) {
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::dead:beef")));
EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("5000::1")));
+ cfg_mgr.deleteSubnets6();
+ EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("200::123")));
+ EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("3000::123")));
+ EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("4000::123")));
}
} // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/duid_unittest.cc b/src/lib/dhcp/tests/duid_unittest.cc
new file mode 100644
index 0000000..aaf6d91
--- /dev/null
+++ b/src/lib/dhcp/tests/duid_unittest.cc
@@ -0,0 +1,169 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <sstream>
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+#include <exceptions/exceptions.h>
+#include <boost/scoped_ptr.hpp>
+#include <asiolink/io_address.h>
+#include <dhcp/duid.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+
+// don't import the entire boost namespace. It will unexpectedly hide uint8_t
+// for some systems.
+using boost::scoped_ptr;
+
+namespace {
+
+// This test verifies if the constructors are working as expected
+// and process passed parameters.
+TEST(DuidTest, constructor) {
+
+ uint8_t data1[] = {0, 1, 2, 3, 4, 5, 6};
+
+ vector<uint8_t> data2(data1, data1 + sizeof(data1));
+
+ scoped_ptr<DUID> duid1(new DUID(data1, sizeof(data1)));
+ scoped_ptr<DUID> duid2(new DUID(data2));
+
+ vector<uint8_t> vecdata = duid1->getDuid();
+ EXPECT_TRUE(data2 == vecdata);
+ EXPECT_EQ(DUID::DUID_LLT, duid1->getType());
+
+ vecdata = duid2->getDuid();
+ EXPECT_TRUE(data2 == vecdata);
+
+ EXPECT_EQ(DUID::DUID_LLT, duid2->getType());
+}
+
+// This test verifies if DUID size restrictions are implemented
+// properly.
+TEST(DuidTest, size) {
+ const int MAX_DUID_SIZE = 128;
+ uint8_t data[MAX_DUID_SIZE + 1];
+ vector<uint8_t> data2;
+ for (uint8_t i = 0; i < MAX_DUID_SIZE + 1; ++i) {
+ data[i] = i;
+ if (i < MAX_DUID_SIZE)
+ data2.push_back(i);
+ }
+ ASSERT_EQ(data2.size(), MAX_DUID_SIZE);
+
+ scoped_ptr<DUID> duidmaxsize1(new DUID(data, MAX_DUID_SIZE));
+ scoped_ptr<DUID> duidmaxsize2(new DUID(data2));
+
+ EXPECT_THROW(
+ scoped_ptr<DUID> toolarge1(new DUID(data, MAX_DUID_SIZE + 1)),
+ OutOfRange);
+
+ // that's one too much
+ data2.push_back(128);
+
+ EXPECT_THROW(
+ scoped_ptr<DUID> toolarge2(new DUID(data2)),
+ OutOfRange);
+}
+
+// This test verifies if the implementation supports all defined
+// DUID types.
+TEST(DuidTest, getType) {
+ uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6};
+ uint8_t en[] = {0, 2, 2, 3, 4, 5, 6};
+ uint8_t ll[] = {0, 3, 2, 3, 4, 5, 6};
+ uint8_t uuid[] = {0, 4, 2, 3, 4, 5, 6};
+ uint8_t invalid[] = {0,55, 2, 3, 4, 5, 6};
+
+ scoped_ptr<DUID> duid_llt(new DUID(llt, sizeof(llt)));
+ scoped_ptr<DUID> duid_en(new DUID(en, sizeof(en)));
+ scoped_ptr<DUID> duid_ll(new DUID(ll, sizeof(ll)));
+ scoped_ptr<DUID> duid_uuid(new DUID(uuid, sizeof(uuid)));
+ scoped_ptr<DUID> duid_invalid(new DUID(invalid, sizeof(invalid)));
+
+ EXPECT_EQ(DUID::DUID_LLT, duid_llt->getType());
+ EXPECT_EQ(DUID::DUID_EN, duid_en->getType());
+ EXPECT_EQ(DUID::DUID_LL, duid_ll->getType());
+ EXPECT_EQ(DUID::DUID_UUID, duid_uuid->getType());
+ EXPECT_EQ(DUID::DUID_UNKNOWN, duid_invalid->getType());
+}
+
+// This test checks if the comparison operators are sane.
+TEST(DuidTest, operators) {
+ uint8_t data1[] = {0, 1, 2, 3, 4, 5, 6};
+ uint8_t data2[] = {0, 1, 2, 3, 4};
+ uint8_t data3[] = {0, 1, 2, 3, 4, 5, 7}; // last digit different
+ uint8_t data4[] = {0, 1, 2, 3, 4, 5, 6}; // the same as 1
+
+ scoped_ptr<DUID> duid1(new DUID(data1, sizeof(data1)));
+ scoped_ptr<DUID> duid2(new DUID(data2, sizeof(data2)));
+ scoped_ptr<DUID> duid3(new DUID(data3, sizeof(data3)));
+ scoped_ptr<DUID> duid4(new DUID(data4, sizeof(data4)));
+
+ EXPECT_TRUE(*duid1 == *duid4);
+ EXPECT_FALSE(*duid1 == *duid2);
+ EXPECT_FALSE(*duid1 == *duid3);
+
+ EXPECT_FALSE(*duid1 != *duid4);
+ EXPECT_TRUE(*duid1 != *duid2);
+ EXPECT_TRUE(*duid1 != *duid3);
+}
+
+// This test verifies if the ClientId constructors are working properly
+// and passed parameters are used
+TEST(ClientIdTest, constructor) {
+ IOAddress addr2("192.0.2.1");
+ IOAddress addr3("2001:db8:1::1");
+
+ uint8_t data1[] = {0, 1, 2, 3, 4, 5, 6};
+ vector<uint8_t> data2(data1, data1 + sizeof(data1));
+
+ // checks for C-style construtor (uint8_t * + len)
+ scoped_ptr<ClientId> id1(new ClientId(data1, sizeof(data1)));
+ vector<uint8_t> vecdata = id1->getClientId();
+ EXPECT_TRUE(data2 == vecdata);
+
+ // checks for vector-based constructor
+ scoped_ptr<ClientId> id2(new ClientId(data2));
+ vecdata = id2->getClientId();
+ EXPECT_TRUE(data2 == vecdata);
+}
+
+// This test checks if the comparison operators are sane.
+TEST(ClientIdTest, operators) {
+ uint8_t data1[] = {0, 1, 2, 3, 4, 5, 6};
+ uint8_t data2[] = {0, 1, 2, 3, 4};
+ uint8_t data3[] = {0, 1, 2, 3, 4, 5, 7}; // last digit different
+ uint8_t data4[] = {0, 1, 2, 3, 4, 5, 6}; // the same as 1
+
+ scoped_ptr<ClientId> id1(new ClientId(data1, sizeof(data1)));
+ scoped_ptr<ClientId> id2(new ClientId(data2, sizeof(data2)));
+ scoped_ptr<ClientId> id3(new ClientId(data3, sizeof(data3)));
+ scoped_ptr<ClientId> id4(new ClientId(data4, sizeof(data4)));
+
+ EXPECT_TRUE(*id1 == *id4);
+ EXPECT_FALSE(*id1 == *id2);
+ EXPECT_FALSE(*id1 == *id3);
+
+ EXPECT_FALSE(*id1 != *id4);
+ EXPECT_TRUE(*id1 != *id2);
+ EXPECT_TRUE(*id1 != *id3);
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/lease_mgr_unittest.cc b/src/lib/dhcp/tests/lease_mgr_unittest.cc
new file mode 100644
index 0000000..97659a1
--- /dev/null
+++ b/src/lib/dhcp/tests/lease_mgr_unittest.cc
@@ -0,0 +1,296 @@
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <sstream>
+#include <gtest/gtest.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/lease_mgr.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+
+// This is a concrete implementation of a Lease database.
+// It does not do anything useful now, and is used for abstract LeaseMgr
+// class testing. It may later evolve into more useful backend if the
+// need arises. We can reuse code from memfile benchmark. See code in
+// tests/tools/dhcp-ubench/memfile_bench.{cc|h}
+class Memfile_LeaseMgr : public LeaseMgr {
+public:
+
+ /// @brief The sole lease manager constructor
+ ///
+ /// dbconfig is a generic way of passing parameters. Parameters
+ /// are passed in the "name=value" format, separated by spaces.
+ /// Values may be enclosed in double quotes, if needed.
+ ///
+ /// @param dbconfig database configuration
+ Memfile_LeaseMgr(const std::string& dbconfig);
+
+ /// @brief Destructor (closes file)
+ virtual ~Memfile_LeaseMgr();
+
+ /// @brief Adds an IPv4 lease.
+ ///
+ /// @param lease lease to be added
+ virtual bool addLease(Lease4Ptr lease);
+
+ /// @brief Adds an IPv6 lease.
+ ///
+ /// @param lease lease to be added
+ virtual bool addLease(Lease6Ptr lease);
+
+ /// @brief Returns existing IPv4 lease for specified IPv4 address.
+ ///
+ /// @param addr address of the searched lease
+ ///
+ /// @return a collection of leases
+ virtual Lease4Ptr getLease4(isc::asiolink::IOAddress addr) const;
+
+ /// @brief Returns existing IPv4 lease for specific address and subnet
+ /// @param addr address of the searched lease
+ /// @param subnet_id ID of the subnet the lease must belong to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(isc::asiolink::IOAddress addr,
+ SubnetID subnet_id) const;
+
+ /// @brief Returns existing IPv4 leases for specified hardware address.
+ ///
+ /// Although in the usual case there will be only one lease, for mobile
+ /// clients or clients with multiple static/fixed/reserved leases there
+ /// can be more than one. Thus return type is a container, not a single
+ /// pointer.
+ ///
+ /// @param hwaddr hardware address of the client
+ ///
+ /// @return lease collection
+ virtual Lease4Collection getLease4(const HWAddr& hwaddr) const;
+
+ /// @brief Returns existing IPv4 leases for specified hardware address
+ /// and a subnet
+ ///
+ /// There can be at most one lease for a given HW address in a single
+ /// pool, so this method with either return a single lease or NULL.
+ ///
+ /// @param hwaddr hardware address of the client
+ /// @param subnet_id identifier of the subnet that lease must belong to
+ ///
+ /// @return a pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const HWAddr& hwaddr,
+ SubnetID subnet_id) const;
+
+ /// @brief Returns existing IPv4 lease for specified client-id
+ ///
+ /// @param clientid client identifier
+ virtual Lease4Collection getLease4(const ClientId& clientid) const;
+
+ /// @brief Returns existing IPv4 lease for specified client-id
+ ///
+ /// There can be at most one lease for a given HW address in a single
+ /// pool, so this method with either return a single lease or NULL.
+ ///
+ /// @param clientid client identifier
+ /// @param subnet_id identifier of the subnet that lease must belong to
+ ///
+ /// @return a pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const ClientId& clientid,
+ SubnetID subnet_id) const;
+
+ /// @brief Returns existing IPv6 lease for a given IPv6 address.
+ ///
+ /// @param addr address of the searched lease
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ Lease6Ptr getLease6(isc::asiolink::IOAddress addr) const;
+
+ /// @brief Returns existing IPv6 lease for a given DUID+IA combination
+ ///
+ /// @param duid client DUID
+ /// @param iaid IA identifier
+ ///
+ /// @return collection of IPv6 leases
+ Lease6Collection getLease6(const DUID& duid, uint32_t iaid) const;
+
+ /// @brief Returns existing IPv6 lease for a given DUID+IA combination
+ ///
+ /// @param duid client DUID
+ /// @param iaid IA identifier
+ /// @param subnet_id identifier of the subnet the lease must belong to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ Lease6Ptr getLease6(const DUID& duid, uint32_t iaid, SubnetID subnet_id) const;
+
+ /// @brief Updates IPv4 lease.
+ ///
+ /// @param lease4 The lease to be updated.
+ ///
+ /// If no such lease is present, an exception will be thrown.
+ void updateLease4(Lease4Ptr lease4);
+
+ /// @brief Updates IPv4 lease.
+ ///
+ /// @param lease4 The lease to be updated.
+ ///
+ /// If no such lease is present, an exception will be thrown.
+ void updateLease6(Lease6Ptr lease6);
+
+ /// @brief Deletes a lease.
+ ///
+ /// @param addr IPv4 address of the lease to be deleted.
+ ///
+ /// @return true if deletion was successful, false if no such lease exists
+ bool deleteLease4(uint32_t addr);
+
+ /// @brief Deletes a lease.
+ ///
+ /// @param addr IPv4 address of the lease to be deleted.
+ ///
+ /// @return true if deletion was successful, false if no such lease exists
+ bool deleteLease6(isc::asiolink::IOAddress addr);
+
+ /// @brief Returns backend name.
+ ///
+ /// Each backend have specific name, e.g. "mysql" or "sqlite".
+ std::string getName() const { return "memfile"; }
+
+ /// @brief Returns description of the backend.
+ ///
+ /// This description may be multiline text that describes the backend.
+ std::string getDescription() const;
+
+ /// @brief Returns backend version.
+ std::string getVersion() const { return "test-version"; }
+
+ using LeaseMgr::getParameter;
+
+protected:
+
+
+};
+
+Memfile_LeaseMgr::Memfile_LeaseMgr(const std::string& dbconfig)
+ : LeaseMgr(dbconfig) {
+}
+
+Memfile_LeaseMgr::~Memfile_LeaseMgr() {
+}
+
+bool Memfile_LeaseMgr::addLease(boost::shared_ptr<isc::dhcp::Lease4>) {
+ return (false);
+}
+
+bool Memfile_LeaseMgr::addLease(boost::shared_ptr<isc::dhcp::Lease6>) {
+ return (false);
+}
+
+Lease4Ptr Memfile_LeaseMgr::getLease4(isc::asiolink::IOAddress) const {
+ return (Lease4Ptr());
+}
+
+Lease4Collection Memfile_LeaseMgr::getLease4(const HWAddr& ) const {
+ return (Lease4Collection());
+}
+
+Lease4Ptr Memfile_LeaseMgr::getLease4(isc::asiolink::IOAddress ,
+ SubnetID) const {
+ return (Lease4Ptr());
+}
+
+Lease4Ptr Memfile_LeaseMgr::getLease4(const HWAddr&,
+ SubnetID) const {
+ return (Lease4Ptr());
+}
+
+
+Lease4Ptr Memfile_LeaseMgr::getLease4(const ClientId&,
+ SubnetID) const {
+ return (Lease4Ptr());
+}
+
+Lease4Collection Memfile_LeaseMgr::getLease4(const ClientId& ) const {
+ return (Lease4Collection());
+}
+
+Lease6Ptr Memfile_LeaseMgr::getLease6(isc::asiolink::IOAddress) const {
+ return (Lease6Ptr());
+}
+
+Lease6Collection Memfile_LeaseMgr::getLease6(const DUID& , uint32_t ) const {
+ return (Lease6Collection());
+}
+
+Lease6Ptr Memfile_LeaseMgr::getLease6(const DUID&, uint32_t,
+ SubnetID) const {
+ return (Lease6Ptr());
+}
+
+void Memfile_LeaseMgr::updateLease4(Lease4Ptr ) {
+}
+
+void Memfile_LeaseMgr::updateLease6(Lease6Ptr ) {
+
+}
+
+bool Memfile_LeaseMgr::deleteLease4(uint32_t ) {
+ return (false);
+}
+
+bool Memfile_LeaseMgr::deleteLease6(isc::asiolink::IOAddress ) {
+ return (false);
+}
+
+std::string Memfile_LeaseMgr::getDescription() const {
+ return (string("This is a dummy memfile backend implementation.\n"
+ "It does not offer any useful lease management and its only\n"
+ "purpose is to test abstract lease manager API."));
+}
+
+namespace {
+// empty class for now, but may be extended once Addr6 becomes bigger
+class LeaseMgrTest : public ::testing::Test {
+public:
+ LeaseMgrTest() {
+ }
+};
+
+// This test checks if the LeaseMgr can be instantiated and that it
+// parses parameters string properly.
+TEST_F(LeaseMgrTest, constructor) {
+
+ // should not throw any exceptions here
+ Memfile_LeaseMgr * leaseMgr = new Memfile_LeaseMgr("");
+ delete leaseMgr;
+
+ leaseMgr = new Memfile_LeaseMgr("param1=value1 param2=value2");
+
+ EXPECT_EQ("value1", leaseMgr->getParameter("param1"));
+ EXPECT_EQ("value2", leaseMgr->getParameter("param2"));
+ EXPECT_THROW(leaseMgr->getParameter("param3"), BadValue);
+
+ delete leaseMgr;
+}
+
+// There's no point in calling any other methods in LeaseMgr, as they
+// are purely virtual, so we would only call Memfile_LeaseMgr methods.
+// Those methods are just stubs that does not return anything.
+// It seems likely that we will need to extend the memfile code for
+// allocation engine tests, so we may implement tests that call
+// Memfile_LeaseMgr methods then.
+
+}; // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/pool_unittest.cc b/src/lib/dhcp/tests/pool_unittest.cc
index 61d4c4a..63d4289 100644
--- a/src/lib/dhcp/tests/pool_unittest.cc
+++ b/src/lib/dhcp/tests/pool_unittest.cc
@@ -27,6 +27,79 @@ using namespace isc::asiolink;
namespace {
+TEST(Pool4Test, constructor_first_last) {
+
+ // let's construct 192.0.2.1-192.0.2.255 pool
+ Pool4 pool1(IOAddress("192.0.2.1"), IOAddress("192.0.2.255"));
+
+ EXPECT_EQ(IOAddress("192.0.2.1"), pool1.getFirstAddress());
+ EXPECT_EQ(IOAddress("192.0.2.255"), pool1.getLastAddress());
+
+ // This is Pool4, IPv6 addresses do not belong here
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::1"),
+ IOAddress("192.168.0.5")), BadValue);
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
+ IOAddress("2001:db8::1")), BadValue);
+
+ // Should throw. Range should be 192.0.2.1-192.0.2.2, not
+ // the other way around.
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.0.2.2"),
+ IOAddress("192.0.2.1")), BadValue);
+}
+
+TEST(Pool4Test, constructor_prefix_len) {
+
+ // let's construct 2001:db8:1::/96 pool
+ Pool4 pool1(IOAddress("192.0.2.0"), 25);
+
+ EXPECT_EQ("192.0.2.0", pool1.getFirstAddress().toText());
+ EXPECT_EQ("192.0.2.127", pool1.getLastAddress().toText());
+
+ // No such thing as /33 prefix
+ EXPECT_THROW(Pool4(IOAddress("192.0.2.1"), 33), BadValue);
+
+ // /0 prefix does not make sense
+ EXPECT_THROW(Pool4(IOAddress("192.0.2.0"), 0), BadValue);
+
+ // This is Pool6, IPv4 addresses do not belong here
+ EXPECT_THROW(Pool4(IOAddress("2001:db8::1"), 20), BadValue);
+}
+
+TEST(Pool4Test, in_range) {
+ Pool4 pool1(IOAddress("192.0.2.10"), IOAddress("192.0.2.20"));
+
+ EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.0")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.10")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.17")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.20")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.21")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.255")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("255.255.255.255")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("0.0.0.0")));
+}
+
+// This test creates 100 pools and verifies that their IDs are unique.
+TEST(Pool4Test, unique_id) {
+
+ const int num_pools = 100;
+ std::vector<Pool4Ptr> pools;
+
+ for (int i = 0; i < num_pools; ++i) {
+ pools.push_back(Pool4Ptr(new Pool4(IOAddress("192.0.2.0"),
+ IOAddress("192.0.2.255"))));
+ }
+
+ for (int i = 0; i < num_pools; ++i) {
+ for (int j = i + 1; j < num_pools; ++j) {
+ if (pools[i]->getId() == pools[j]->getId()) {
+ FAIL() << "Pool-ids must be unique";
+ }
+ }
+ }
+
+}
+
+
TEST(Pool6Test, constructor_first_last) {
// let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool
diff --git a/src/lib/dhcp/tests/subnet_unittest.cc b/src/lib/dhcp/tests/subnet_unittest.cc
index 6afebb8..6c26106 100644
--- a/src/lib/dhcp/tests/subnet_unittest.cc
+++ b/src/lib/dhcp/tests/subnet_unittest.cc
@@ -29,6 +29,83 @@ using namespace isc::asiolink;
namespace {
+TEST(Subnet4Test, constructor) {
+ EXPECT_NO_THROW(Subnet4 subnet1(IOAddress("192.0.2.2"), 16,
+ 1, 2, 3));
+
+ EXPECT_THROW(Subnet4 subnet2(IOAddress("192.0.2.0"), 33, 1, 2, 3),
+ BadValue); // invalid prefix length
+ EXPECT_THROW(Subnet4 subnet3(IOAddress("2001:db8::1"), 24, 1, 2, 3),
+ BadValue); // IPv6 addresses are not allowed in Subnet4
+}
+
+TEST(Subnet4Test, in_range) {
+ Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);
+
+ EXPECT_EQ(1000, subnet.getT1());
+ EXPECT_EQ(2000, subnet.getT2());
+ EXPECT_EQ(3000, subnet.getValid());
+
+ EXPECT_FALSE(subnet.inRange(IOAddress("192.0.0.0")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.0")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.1")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.255")));
+ EXPECT_FALSE(subnet.inRange(IOAddress("192.0.3.0")));
+ EXPECT_FALSE(subnet.inRange(IOAddress("0.0.0.0")));
+ EXPECT_FALSE(subnet.inRange(IOAddress("255.255.255.255")));
+}
+
+TEST(Subnet4Test, Pool4InSubnet4) {
+
+ Subnet4Ptr subnet(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3));
+
+ Pool4Ptr pool1(new Pool4(IOAddress("192.1.2.0"), 25));
+ Pool4Ptr pool2(new Pool4(IOAddress("192.1.2.128"), 26));
+ Pool4Ptr pool3(new Pool4(IOAddress("192.1.2.192"), 30));
+
+ subnet->addPool4(pool1);
+
+ // If there's only one pool, get that pool
+ Pool4Ptr mypool = subnet->getPool4();
+ EXPECT_EQ(mypool, pool1);
+
+
+ subnet->addPool4(pool2);
+ subnet->addPool4(pool3);
+
+ // If there are more than one pool and we didn't provide hint, we
+ // should get the first pool
+ mypool = subnet->getPool4();
+
+ EXPECT_EQ(mypool, pool1);
+
+ // If we provide a hint, we should get a pool that this hint belongs to
+ mypool = subnet->getPool4(IOAddress("192.1.2.195"));
+
+ EXPECT_EQ(mypool, pool3);
+
+}
+
+TEST(Subnet4Test, Subnet4_Pool4_checks) {
+
+ Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 8, 1, 2, 3));
+
+ // this one is in subnet
+ Pool4Ptr pool1(new Pool4(IOAddress("192.255.0.0"), 16));
+ subnet->addPool4(pool1);
+
+ // this one is larger than the subnet!
+ Pool4Ptr pool2(new Pool4(IOAddress("193.0.0.0"), 24));
+
+ EXPECT_THROW(subnet->addPool4(pool2), BadValue);
+
+ // this one is totally out of blue
+ Pool4Ptr pool3(new Pool4(IOAddress("1.2.3.4"), 16));
+ EXPECT_THROW(subnet->addPool4(pool3), BadValue);
+}
+
+// Tests for Subnet6
+
TEST(Subnet6Test, constructor) {
EXPECT_NO_THROW(Subnet6 subnet1(IOAddress("2001:db8:1::"), 64,
@@ -48,7 +125,6 @@ TEST(Subnet6Test, in_range) {
EXPECT_EQ(3000, subnet.getPreferred());
EXPECT_EQ(4000, subnet.getValid());
-
EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:0:ffff:ffff:ffff:ffff:ffff")));
EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::0")));
EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::1")));
@@ -106,7 +182,9 @@ TEST(Subnet6Test, Subnet6_Pool6_checks) {
Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("3000::"), 16));
EXPECT_THROW(subnet->addPool6(pool3), BadValue);
-}
+ Pool6Ptr pool4(new Pool6(Pool6::TYPE_IA, IOAddress("4001:db8:1::"), 80));
+ EXPECT_THROW(subnet->addPool6(pool4), BadValue);
+}
};
diff --git a/src/lib/dhcp/triplet.h b/src/lib/dhcp/triplet.h
index d45f003..d9388fe 100644
--- a/src/lib/dhcp/triplet.h
+++ b/src/lib/dhcp/triplet.h
@@ -12,6 +12,9 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#ifndef TRIPLET_H
+#define TRIPLET_H
+
#include <exceptions/exceptions.h>
namespace isc {
@@ -108,3 +111,5 @@ protected:
} // namespace isc::dhcp
} // namespace isc
+
+#endif // ifdef TRIPLET_H
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 40cb943..977854d 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -107,7 +107,6 @@ libb10_dns___la_SOURCES += rdatafields.h rdatafields.cc
libb10_dns___la_SOURCES += rrclass.cc
libb10_dns___la_SOURCES += rrparamregistry.h
libb10_dns___la_SOURCES += rrset.h rrset.cc
-libb10_dns___la_SOURCES += rrsetlist.h rrsetlist.cc
libb10_dns___la_SOURCES += rrttl.h rrttl.cc
libb10_dns___la_SOURCES += rrtype.cc
libb10_dns___la_SOURCES += question.h question.cc
diff --git a/src/lib/dns/rrsetlist.cc b/src/lib/dns/rrsetlist.cc
deleted file mode 100644
index fcdcfbb..0000000
--- a/src/lib/dns/rrsetlist.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <vector>
-
-#include <boost/foreach.hpp>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-#include <dns/rrset.h>
-#include <dns/rrsetlist.h>
-
-namespace isc {
-namespace dns {
-
-void
-RRsetList::addRRset(RRsetPtr rrsetptr) {
- ConstRRsetPtr rrset_found = findRRset(rrsetptr->getType(),
- rrsetptr->getClass());
- if (rrset_found != NULL) {
- isc_throw(DuplicateRRset, "RRset is being doubly added to RRsetList: "
- "type=" << rrsetptr->getType() << ", class=" <<
- rrsetptr->getClass());
- }
- rrsets_.push_back(rrsetptr);
-}
-
-void
-RRsetList::append(RRsetList& source) {
- BOOST_FOREACH(RRsetPtr rrset, source) {
- addRRset(rrset);
- }
-}
-
-RRsetPtr
-RRsetList::findRRset(const RRType& rrtype, const RRClass& rrclass) {
- BOOST_FOREACH(RRsetPtr rrsetptr, rrsets_) {
- if ((rrsetptr->getClass() == rrclass) &&
- (rrsetptr->getType() == rrtype)) {
- return (rrsetptr);
- }
- }
- return (RRsetPtr());
-}
-
-}
-}
diff --git a/src/lib/dns/rrsetlist.h b/src/lib/dns/rrsetlist.h
deleted file mode 100644
index 0e05b5b..0000000
--- a/src/lib/dns/rrsetlist.h
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __RRSETLIST_H
-#define __RRSETLIST_H 1
-
-#include <iostream>
-#include <iterator>
-#include <vector>
-
-#include <boost/shared_ptr.hpp>
-
-#include <dns/rrset.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-
-namespace isc {
-namespace dns {
-
-class DuplicateRRset : public Exception {
-public:
- DuplicateRRset(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
-
-template <typename T, typename P, typename R>
-class RRsetListIterator :
- public std::iterator<std::input_iterator_tag, RRsetPtr> {
-public:
- RRsetListIterator() {}
- explicit RRsetListIterator(const T& it) :
- it_(it) {}
- RRsetListIterator& operator++()
- {
- ++it_;
- return (*this);
- }
- RRsetListIterator operator++(int)
- {
- RRsetListIterator tmp(*this);
- ++it_;
- return (tmp);
- }
- R operator*() const
- {
- return (*it_);
- }
- P operator->() const
- {
- return (&(operator*()));
- }
- bool operator==(const RRsetListIterator& other)
- {
- return (it_ == other.it_);
- }
- bool operator!=(const RRsetListIterator& other)
- {
- return (it_ != other.it_);
- }
-
-private:
- T it_;
-};
-
-/// A set of RRsets.
-///
-/// \note Do not use this class unless you really understand what
-/// you're doing and you're 100% sure that this class is the best choice
-/// for your purpose.
-///
-/// Counter intuitively, this class is not a "list" of RRsets but a
-/// "set" of them; it doesn't allow multiple RRsets of the same RR
-/// type and RR class to be added at the same time. And, for that
-/// reason, adding an RRset is more expensive than you'd expect. The
-/// class name is confusing, but was named so as a result of
-/// compromise: "RRsetset" would look awkward; RRsets would be
-/// confusing (with RRset).
-///
-/// In any case, if you want a list like container of RRsets, your best choice
-/// would be \c std::vector<RRset> or \c std::list<RRset>, not this class.
-/// In fact, in many cases \c RRsetList will be a suboptimal choice.
-/// This class is defined publicly as part of libdns++ for a historical
-/// reason and is actually quite specific to a particular need for libdatasrc.
-/// If you are tempted to use it, think twice to assess if this class
-/// is really what you want. Again, in many cases the answer will be no.
-class RRsetList {
-private:
- RRsetList(const RRsetList& source);
- RRsetList& operator=(const RRsetList& source);
-public:
- RRsetList() {}
- void addRRset(RRsetPtr new_rrsetptr);
- void append(RRsetList& source);
- RRsetPtr findRRset(const RRType& rrtype, const RRClass& rrclass);
-
- typedef RRsetListIterator<std::vector<RRsetPtr>::iterator,
- RRsetPtr*,
- RRsetPtr&> iterator;
- typedef RRsetListIterator<std::vector<RRsetPtr>::const_iterator,
- const RRsetPtr*,
- const RRsetPtr&> const_iterator;
-
- const_iterator begin() const { return (const_iterator(rrsets_.begin())); }
- const_iterator end() const { return (const_iterator(rrsets_.end())); }
-
- iterator begin() { return (iterator(rrsets_.begin())); }
- iterator end() { return (iterator(rrsets_.end())); }
-
- size_t size() const { return (rrsets_.size()); }
-
-private:
- std::vector<RRsetPtr> rrsets_;
-};
-
-} // end of namespace dns
-} // end of namespace isc
-#endif // __RRSETLIST_H
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index 0abb389..e8cbe10 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -56,7 +56,7 @@ run_unittests_SOURCES += rdata_minfo_unittest.cc
run_unittests_SOURCES += rdata_tsig_unittest.cc
run_unittests_SOURCES += rdata_naptr_unittest.cc
run_unittests_SOURCES += rdata_hinfo_unittest.cc
-run_unittests_SOURCES += rrset_unittest.cc rrsetlist_unittest.cc
+run_unittests_SOURCES += rrset_unittest.cc
run_unittests_SOURCES += question_unittest.cc
run_unittests_SOURCES += rrparamregistry_unittest.cc
run_unittests_SOURCES += masterload_unittest.cc
diff --git a/src/lib/dns/tests/rrsetlist_unittest.cc b/src/lib/dns/tests/rrsetlist_unittest.cc
deleted file mode 100644
index 080f888..0000000
--- a/src/lib/dns/tests/rrsetlist_unittest.cc
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <vector>
-#include <boost/foreach.hpp>
-
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-#include <dns/rrsetlist.h>
-#include <dns/rrset.h>
-#include <dns/rrttl.h>
-
-#include <gtest/gtest.h>
-
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-
-namespace {
-class RRsetListTest : public ::testing::Test {
-protected:
- RRsetListTest() : example_name(Name("example.com")),
- example_ttl(RRTTL(3600))
- {}
- void setupList(RRsetList& list);
- Name example_name;
- RRTTL example_ttl;
-};
-
-const in::A rdata_in_a("192.0.2.1");
-const in::AAAA rdata_in_aaaa("2001:db8::1234");
-const generic::NS rdata_ns("ns.example.com");
-const generic::SOA rdata_soa(Name("ns.example.com"), Name("root.example.com"),
- 2010012601, 3600, 300, 3600000, 1200);
-const generic::CNAME rdata_cname("target.example.com");
-const generic::DNAME rdata_dname("dtarget.example.com");
-
-void
-RRsetListTest::setupList(RRsetList& list) {
- RRsetPtr a(new RRset(Name("example.com"), RRClass::IN(),
- RRType::A(), example_ttl));
- RRsetPtr aaaa(new RRset(Name("example.com"), RRClass::IN(),
- RRType::AAAA(), example_ttl));
- RRsetPtr ns(new RRset(Name("example.com"), RRClass::IN(),
- RRType::NS(), example_ttl));
- RRsetPtr soa(new RRset(Name("example.com"), RRClass::IN(),
- RRType::SOA(), example_ttl));
- RRsetPtr cname(new RRset(Name("example.com"), RRClass::IN(),
- RRType::CNAME(), example_ttl));
-
- a->addRdata(rdata_in_a);
- aaaa->addRdata(rdata_in_aaaa);
- ns->addRdata(rdata_ns);
- soa->addRdata(rdata_soa);
- cname->addRdata(rdata_cname);
-
- list.addRRset(a);
- list.addRRset(aaaa);
- list.addRRset(ns);
- list.addRRset(soa);
- list.addRRset(cname);
-}
-
-TEST_F(RRsetListTest, emptyOnInitialCreate) {
- RRsetList list;
- EXPECT_EQ(list.size(), 0);
-}
-
-TEST_F(RRsetListTest, addRRsets) {
- RRsetList list;
- setupList(list);
- EXPECT_EQ(list.size(), 5);
-}
-
-TEST_F(RRsetListTest, append) {
- RRsetList list1;
- setupList(list1);
- RRsetList list2;
- RRsetPtr dname(new RRset(Name("example.com"), RRClass::IN(),
- RRType::DNAME(), example_ttl));
- dname->addRdata(rdata_dname);
- list2.addRRset(dname);
- list1.append(list2);
- EXPECT_EQ(list2.size(), 1);
- EXPECT_EQ(list1.size(), 6);
-
- RRsetPtr rrset = list1.findRRset(RRType::DNAME(), RRClass::IN());
- EXPECT_EQ(RRType::DNAME(), rrset->getType());
-
- EXPECT_THROW(list1.append(list2), DuplicateRRset);
-}
-
-TEST_F(RRsetListTest, extraRRset) {
- RRsetList list;
- setupList(list);
- RRsetPtr cname(new RRset(Name("another.example.com"), RRClass::IN(),
- RRType::CNAME(), example_ttl));
- EXPECT_THROW(list.addRRset(cname), DuplicateRRset);
-}
-
-void
-checkFindResult(RRsetList& list, const Name& name,
- const RRType& rrtype, const RRClass& rrclass,
- const RRTTL& rrttl)
-{
- RRsetPtr rrset = list.findRRset(rrtype, rrclass);;
- EXPECT_EQ(name, rrset->getName());
- EXPECT_EQ(rrtype, rrset->getType());
- EXPECT_EQ(rrclass, rrset->getClass());
- EXPECT_EQ(rrttl, rrset->getTTL());
-}
-
-TEST_F(RRsetListTest, findRRset) {
- RRsetList list;
- setupList(list);
-
- checkFindResult(list, example_name, RRType::A(), RRClass::IN(),
- example_ttl);
- checkFindResult(list, example_name, RRType::CNAME(), RRClass::IN(),
- example_ttl);
- checkFindResult(list, example_name, RRType::AAAA(), RRClass::IN(),
- example_ttl);
- checkFindResult(list, example_name, RRType::NS(), RRClass::IN(),
- example_ttl);
- checkFindResult(list, example_name, RRType::SOA(), RRClass::IN(),
- example_ttl);
-}
-
-TEST_F(RRsetListTest, checkData) {
- RRsetList list;
- RRsetPtr a(new RRset(Name("example.com"), RRClass::IN(),
- RRType::A(), example_ttl));
- a->addRdata(rdata_in_a);
- list.addRRset(a);
-
- RdataIteratorPtr it =
- list.findRRset(RRType::A(), RRClass::IN())->getRdataIterator();
- EXPECT_FALSE(it->isLast());
- EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
-}
-
-TEST_F(RRsetListTest, iterate) {
- RRsetList list;
- setupList(list);
-
- bool has_a = false, has_aaaa = false, has_ns = false, has_soa = false,
- has_cname = false;
- int i = 0;
- BOOST_FOREACH(RRsetPtr rrset, list) {
- if (rrset->getType() == RRType::A()) {
- has_a = true;
- }
- if (rrset->getType() == RRType::AAAA()) {
- has_aaaa = true;
- }
- if (rrset->getType() == RRType::NS()) {
- has_ns = true;
- }
- if (rrset->getType() == RRType::SOA()) {
- has_soa = true;
- }
- if (rrset->getType() == RRType::CNAME()) {
- has_cname = true;
- }
- ++i;
- }
- EXPECT_TRUE(has_a);
- EXPECT_TRUE(has_aaaa);
- EXPECT_TRUE(has_ns);
- EXPECT_TRUE(has_soa);
- EXPECT_TRUE(has_cname);
- EXPECT_TRUE(i == 5);
-}
-
-}
More information about the bind10-changes
mailing list