test_control_unittest.cc 81 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892
  1. // Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include "command_options_helper.h"
  8. #include "../test_control.h"
  9. #include <asiolink/io_address.h>
  10. #include <exceptions/exceptions.h>
  11. #include <dhcp/dhcp4.h>
  12. #include <dhcp/iface_mgr.h>
  13. #include <boost/date_time/posix_time/posix_time.hpp>
  14. #include <boost/foreach.hpp>
  15. #include <algorithm>
  16. #include <cstddef>
  17. #include <stdint.h>
  18. #include <string>
  19. #include <fstream>
  20. #include <gtest/gtest.h>
  21. using namespace std;
  22. using namespace boost::posix_time;
  23. using namespace isc;
  24. using namespace isc::dhcp;
  25. using namespace isc::perfdhcp;
  26. /// \brief Test Control class with protected members made public.
  27. ///
  28. /// This class makes protected TestControl class'es member public
  29. /// to allow unit testing.
  30. class NakedTestControl: public TestControl {
  31. public:
  32. /// \brief Incremental transaction id generator.
  33. ///
  34. /// This is incremental transaction id generator. It overrides
  35. /// the default transaction id generator that generates transaction
  36. /// ids using random function. This generator will generate values
  37. /// like: 1,2,3 etc.
  38. class IncrementalGenerator : public TestControl::NumberGenerator {
  39. public:
  40. /// \brief Default constructor.
  41. IncrementalGenerator() :
  42. NumberGenerator(),
  43. transid_(0) {
  44. }
  45. /// \brief Generate unique transaction id.
  46. ///
  47. /// Generate unique transaction ids incrementally:
  48. /// 1,2,3,4 etc.
  49. ///
  50. /// \return generated transaction id.
  51. virtual uint32_t generate() {
  52. return (++transid_);
  53. }
  54. /// \brief Return next transaction id value.
  55. uint32_t getNext() const {
  56. return (transid_ + 1);
  57. }
  58. private:
  59. uint32_t transid_; ///< Last generated transaction id.
  60. };
  61. /// \brief Pointer to incremental generator.
  62. typedef boost::shared_ptr<IncrementalGenerator> IncrementalGeneratorPtr;
  63. /// \brief Sets the due times for sending Solicit, Renew and Release.
  64. ///
  65. /// There are three class members that hold the due time for sending DHCP
  66. /// messages:
  67. /// - send_due_ - due time to send Solicit,
  68. /// - renew_due_ - due time to send Renew,
  69. /// - release_due_ - due time to send Release.
  70. /// Some tests in this test suite need to modify these values relative to
  71. /// the current time. This function modifies this values using time
  72. /// offset values (positive or negative) specified as a difference in
  73. /// seconds between current time and the due time.
  74. ///
  75. /// \param send_secs An offset of the due time for Solicit.
  76. /// \param renew_secs An offset of the due time for Renew.
  77. /// \param release_secs An offset of the due time for Release.
  78. void setRelativeDueTimes(const int send_secs, const int renew_secs = 0,
  79. const int release_secs = 0) {
  80. ptime now = microsec_clock::universal_time();
  81. // Use now to avoid unused but set warning
  82. ASSERT_FALSE(now.is_special());
  83. basic_rate_control_.setRelativeDue(send_secs);
  84. renew_rate_control_.setRelativeDue(renew_secs);
  85. release_rate_control_.setRelativeDue(release_secs);
  86. }
  87. using TestControl::checkExitConditions;
  88. using TestControl::createMessageFromReply;
  89. using TestControl::createRequestFromAck;
  90. using TestControl::factoryElapsedTime6;
  91. using TestControl::factoryGeneric;
  92. using TestControl::factoryIana6;
  93. using TestControl::factoryOptionRequestOption6;
  94. using TestControl::factoryRapidCommit6;
  95. using TestControl::factoryRequestList4;
  96. using TestControl::generateClientId;
  97. using TestControl::generateDuid;
  98. using TestControl::generateMacAddress;
  99. using TestControl::getCurrentTimeout;
  100. using TestControl::getTemplateBuffer;
  101. using TestControl::initPacketTemplates;
  102. using TestControl::initializeStatsMgr;
  103. using TestControl::openSocket;
  104. using TestControl::processReceivedPacket4;
  105. using TestControl::processReceivedPacket6;
  106. using TestControl::registerOptionFactories;
  107. using TestControl::reset;
  108. using TestControl::sendDiscover4;
  109. using TestControl::sendPackets;
  110. using TestControl::sendMultipleRequests;
  111. using TestControl::sendMultipleMessages6;
  112. using TestControl::sendRequest6;
  113. using TestControl::sendSolicit6;
  114. using TestControl::setDefaults4;
  115. using TestControl::setDefaults6;
  116. using TestControl::basic_rate_control_;
  117. using TestControl::renew_rate_control_;
  118. using TestControl::release_rate_control_;
  119. using TestControl::last_report_;
  120. using TestControl::transid_gen_;
  121. using TestControl::macaddr_gen_;
  122. using TestControl::first_packet_serverid_;
  123. using TestControl::interrupted_;
  124. NakedTestControl() : TestControl() {
  125. uint32_t clients_num = CommandOptions::instance().getClientsNum() == 0 ?
  126. 1 : CommandOptions::instance().getClientsNum();
  127. setMacAddrGenerator(NumberGeneratorPtr(new TestControl::SequentialGenerator(clients_num)));
  128. };
  129. };
  130. /// \brief Test Fixture Class
  131. ///
  132. /// This test fixture class is used to perform
  133. /// unit tests on perfdhcp TestControl class.
  134. class TestControlTest : public virtual ::testing::Test
  135. {
  136. public:
  137. typedef std::vector<uint8_t> MacAddress;
  138. typedef MacAddress::iterator MacAddressIterator;
  139. typedef std::vector<uint8_t> Duid;
  140. typedef Duid::iterator DuidIterator;
  141. /// \brief Default Constructor
  142. TestControlTest() { }
  143. /// \brief Create packet template file from binary data.
  144. ///
  145. /// Function creates file containing data from the provided buffer
  146. /// in hexadecimal format. The size parameter specifies the maximum
  147. /// size of the file. If total number of hexadecimal digits resulting
  148. /// from buffer size is greater than maximum file size the file is
  149. /// truncated.
  150. ///
  151. /// \param filename template file to be created.
  152. /// \param buffer with binary data to be stored in file.
  153. /// \param size target size of the file.
  154. /// \param invalid_chars inject invalid chars to the template file.
  155. /// \return true if file creation successful.
  156. bool createTemplateFile(const std::string& filename,
  157. const std::vector<uint8_t>& buf,
  158. const size_t size,
  159. const bool invalid_chars = false) const {
  160. std::ofstream temp_file;
  161. temp_file.open(filename.c_str(), ios::out | ios::trunc);
  162. if (!temp_file.is_open()) {
  163. return (false);
  164. }
  165. for (size_t i = 0; i < buf.size(); ++i) {
  166. int first_digit = buf[i] / 16;
  167. int second_digit = buf[i] % 16;
  168. // Insert two spaces between two hexadecimal digits.
  169. // Spaces are allowed in template files.
  170. temp_file << std::string(2, ' ');
  171. if (2 * i + 1 < size) {
  172. if (!invalid_chars) {
  173. temp_file << std::hex << first_digit << second_digit << std::dec;
  174. } else {
  175. temp_file << "XY";
  176. }
  177. } else if (2 * i < size) {
  178. if (!invalid_chars) {
  179. temp_file << std::hex << first_digit;
  180. } else {
  181. temp_file << "X";
  182. }
  183. } else {
  184. break;
  185. }
  186. }
  187. temp_file.close();
  188. return (true);
  189. }
  190. /// \brief Get local loopback interface name.
  191. ///
  192. /// Scan available network interfaces for local loopback
  193. /// interface and get its name. On Linux this interface is
  194. /// usually called 'lo' but on other systems, e.g. BSD
  195. /// it will have slightly different name. Local loopback
  196. /// interface is required for unit tests that require
  197. /// socket creation.
  198. ///
  199. /// \return local loopback interface name.
  200. std::string getLocalLoopback() const {
  201. BOOST_FOREACH(IfacePtr iface, IfaceMgr::instance().getIfaces()) {
  202. if (iface->flag_loopback_) {
  203. return (iface->getName());
  204. }
  205. }
  206. return ("");
  207. }
  208. /// \brief Get full path to a file in testdata directory.
  209. ///
  210. /// \param filename filename being appended to absolute
  211. /// path to testdata directory
  212. ///
  213. /// \return full path to a file in testdata directory.
  214. std::string getFullPath(const std::string& filename) const {
  215. std::ostringstream stream;
  216. stream << TEST_DATA_DIR << "/" << filename;
  217. return (stream.str());
  218. }
  219. /// \brief Match requested options in the buffer with given list.
  220. ///
  221. /// This method iterates through options provided in the buffer
  222. /// and matches them with the options specified with first parameter.
  223. /// Options in both vectors may be laid in different order.
  224. ///
  225. /// \param requested_options reference buffer with options.
  226. /// \param buf test buffer with options that will be matched.
  227. /// \return number of options from the buffer matched with options
  228. /// in the reference buffer.
  229. int matchRequestedOptions(const dhcp::OptionBuffer& requested_options,
  230. const dhcp::OptionBuffer& buf) const {
  231. size_t matched_num = 0;
  232. for (size_t i = 0; i < buf.size(); ++i) {
  233. for (size_t j = 0; j < requested_options.size(); ++j) {
  234. if (requested_options[j] == buf[i]) {
  235. // Requested option has been found.
  236. ++matched_num;
  237. }
  238. }
  239. }
  240. return (matched_num);
  241. }
  242. /// \brief Match requested DHCPv6 options in the buffer with given list.
  243. ///
  244. /// This method iterates through options provided in the buffer and
  245. /// matches them with the options specified with first parameter.
  246. /// Options in both vectors ma be laid in different order.
  247. ///
  248. /// \param requested_options reference buffer with options.
  249. /// \param buf test buffer with options that will be matched.
  250. /// \return number of options from the buffer matched with options in
  251. /// the reference buffer or -1 if error occurred.
  252. int matchRequestedOptions6(const dhcp::OptionBuffer& requested_options,
  253. const dhcp::OptionBuffer& buf) const {
  254. // Sanity check.
  255. if ((requested_options.size() % 2 != 0) ||
  256. (buf.size() % 2 != 0)) {
  257. return -1;
  258. }
  259. size_t matched_num = 0;
  260. for (size_t i = 0; i < buf.size(); i += 2) {
  261. for (size_t j = 0; j < requested_options.size(); j += 2) {
  262. uint16_t opt_i = (buf[i + 1] << 8) + (buf[i] & 0xFF);
  263. uint16_t opt_j = (requested_options[j + 1] << 8)
  264. + (requested_options[j] & 0xFF);
  265. if (opt_i == opt_j) {
  266. // Requested option has been found.
  267. ++matched_num;
  268. }
  269. }
  270. }
  271. return (matched_num);
  272. }
  273. /// \brief Calculate the maximum vectors' mismatch position.
  274. ///
  275. /// This helper function calculates the maximum mismatch position
  276. /// between two vectors (two different DUIDs or MAC addresses).
  277. /// Calculated position is counted from the end of vectors.
  278. /// Calculation is based on number of simulated clients. When number
  279. /// of clients is less than 256 different DUIDs or MAC addresses can
  280. /// can be coded in such a way that they differ on last vector element.
  281. /// If number of clients is between 257 and 65536 they can differ
  282. /// on two last positions so the returned value will be 2 and so on.
  283. ///
  284. /// \param clients_num number of simulated clients
  285. /// \return maximum mismatch position
  286. int unequalOctetPosition(int clients_num) const {
  287. if (!clients_num) {
  288. return (0);
  289. }
  290. clients_num--;
  291. int cnt = 0;
  292. while (clients_num) {
  293. clients_num >>= 8;
  294. ++cnt;
  295. }
  296. return (cnt);
  297. }
  298. /// \brief Test generation of multiple DUIDs
  299. ///
  300. /// This method checks the generation of multiple DUIDs. Number
  301. /// of iterations depends on the number of simulated clients.
  302. /// It is expected that DUID's size is 14 (consists of DUID-LLT
  303. /// HW type field, 4 octets of time value and MAC address). The
  304. /// MAC address can be randomized depending on the number of
  305. /// simulated clients. The DUID-LLT and HW type are expected to
  306. /// be constant. The time value has to be properly calculated
  307. /// as the number of seconds since DUID time epoch. The parts
  308. /// of MAC address has to change if multiple clients are simulated
  309. /// and do not change if single client is simulated.
  310. void testDuid() const {
  311. int clients_num = CommandOptions::instance().getClientsNum();
  312. // Initialize Test Control class.
  313. NakedTestControl tc;
  314. // The old duid will be holding the previously generated DUID.
  315. // It will be used to compare against the new one. If we have
  316. // multiple clients we want to make sure that duids differ.
  317. uint8_t randomized = 0;
  318. Duid old_duid(tc.generateDuid(randomized));
  319. Duid new_duid(0);
  320. // total_dist shows the total difference between generated duid.
  321. // It has to be greater than zero if multiple clients are simulated.
  322. size_t total_dist = 0;
  323. // Number of unique DUIDs.
  324. size_t unique_duids = 0;
  325. // Holds the position if the octet on which two DUIDS can be different.
  326. // If number of clients is 256 or less it is last DUID octet (except for
  327. // single client when subsequent DUIDs have to be equal). If number of
  328. // clients is between 257 and 65536 the last two octets can differ etc.
  329. int unequal_pos = unequalOctetPosition(clients_num);
  330. // Keep generated DUIDs in this container.
  331. std::list<std::vector<uint8_t> > duids;
  332. // Perform number of iterations to generate number of DUIDs.
  333. for (int i = 0; i < 10 * clients_num; ++i) {
  334. if (new_duid.empty()) {
  335. new_duid = old_duid;
  336. } else {
  337. std::swap(old_duid, new_duid);
  338. new_duid = tc.generateDuid(randomized);
  339. }
  340. // The DUID-LLT is expected to start with DUID_LLT value
  341. // of 1 and hardware ethernet type equal to 1 (HWETHER_TYPE).
  342. const uint8_t duid_llt_and_hw[4] = { 0x0, 0x1, 0x0, 0x1 };
  343. // We assume DUID-LLT length 14. This includes 4 octets of
  344. // DUID_LLT value, two octets of hardware type, 4 octets
  345. // of time value and 6 octets of variable link layer (MAC)
  346. // address.
  347. const int duid_llt_size = 14;
  348. ASSERT_EQ(duid_llt_size, new_duid.size());
  349. // The first four octets do not change.
  350. EXPECT_TRUE(std::equal(new_duid.begin(), new_duid.begin() + 4,
  351. duid_llt_and_hw));
  352. // As described in RFC3315: 'the time value is the time
  353. // that the DUID is generated represented in seconds
  354. // since midnight (UTC), January 1, 2000, modulo 2^32.'
  355. uint32_t duid_time = 0;
  356. // Pick 4 bytes of the time from generated DUID and put them
  357. // in reverse order (in DUID they are stored in network order).
  358. for (int j = 4; j < 8; ++j) {
  359. duid_time |= new_duid[j] << (j - 4);
  360. }
  361. // Calculate the duration since epoch time.
  362. ptime now = microsec_clock::universal_time();
  363. ptime duid_epoch(from_iso_string("20000101T000000"));
  364. time_period period(duid_epoch, now);
  365. // Current time is the same or later than time from the DUID because
  366. // DUID had been generated before reference duration was calculated.
  367. EXPECT_GE(period.length().total_seconds(), duid_time);
  368. // Get the mismatch position (counting from the end) of
  369. // mismatched octet between previously generated DUID
  370. // and current.
  371. std::pair<DuidIterator, DuidIterator> mismatch_pos =
  372. std::mismatch(old_duid.begin(), old_duid.end(),
  373. new_duid.begin());
  374. size_t mismatch_dist =
  375. std::distance(mismatch_pos.first, old_duid.end());
  376. // For single client total_dist is expected to be 0 because
  377. // old_duid and new_duid should always match. If we have
  378. // more clients then duids have to differ except the case
  379. // if randomization algorithm generates the same values but
  380. // this would be an error in randomization algorithm.
  381. total_dist += mismatch_dist;
  382. // Mismatch may have occurred on the DUID octet position
  383. // up to calculated earlier unequal_pos.
  384. ASSERT_LE(mismatch_dist, unequal_pos);
  385. // unique will inform if tested DUID is unique.
  386. bool unique = true;
  387. for (std::list<std::vector<uint8_t> >::const_iterator it =
  388. duids.begin();
  389. it != duids.end(); ++it) {
  390. // DUIDs should be of the same size if we want to compare them.
  391. ASSERT_EQ(new_duid.size(), it->size());
  392. // Check if DUID is unique.
  393. if (std::equal(new_duid.begin(), new_duid.end(), it->begin())) {
  394. unique = false;
  395. }
  396. }
  397. // Expecting that DUIDs will be unique only when
  398. // first clients-num iterations is performed.
  399. // After that, DUIDs become non unique.
  400. if (unique) {
  401. ++unique_duids;
  402. }
  403. // For number of iterations equal to clients_num,2*clients_num
  404. // 3*clients_num ... we have to have number of unique duids
  405. // equal to clients_num.
  406. if ((i != 0) && (i % clients_num == 0)) {
  407. ASSERT_EQ(clients_num, unique_duids);
  408. }
  409. // Remember generated DUID.
  410. duids.push_back(new_duid);
  411. }
  412. // If we have more than one client at least one mismatch occurred.
  413. if (clients_num < 2) {
  414. EXPECT_EQ(0, total_dist);
  415. }
  416. }
  417. /// \brief Test DHCPv4 exchanges.
  418. ///
  419. /// Function simulates DHCPv4 exchanges. Function caller specifies
  420. /// number of exchanges to be simulated and number of simulated
  421. /// responses. When number of responses is lower than number of
  422. /// iterations than the difference between them is the number
  423. /// of simulated packet drops. This is useful to test if program
  424. /// exit conditions are handled properly (maximum number of packet
  425. /// drops specified as -D<max-drops> is taken into account).
  426. ///
  427. /// \param iterations_num number of exchanges to simulate.
  428. /// \param receive_num number of received OFFER packets.
  429. /// \param iterations_performed actual number of iterations.
  430. void testPkt4Exchange(int iterations_num,
  431. int receive_num,
  432. bool use_templates,
  433. int& iterations_performed) const {
  434. int sock_handle = 0;
  435. NakedTestControl tc;
  436. tc.initializeStatsMgr();
  437. // Use templates files to crate packets.
  438. if (use_templates) {
  439. tc.initPacketTemplates();
  440. ASSERT_NO_THROW(tc.getTemplateBuffer(0));
  441. ASSERT_NO_THROW(tc.getTemplateBuffer(1));
  442. }
  443. // Incremental transaction id generator will generate
  444. // predictable values of transaction id for each iteration.
  445. // This is important because we need to simulate responses
  446. // from the server and use the same transaction ids as in
  447. // packets sent by client.
  448. NakedTestControl::IncrementalGeneratorPtr
  449. generator(new NakedTestControl::IncrementalGenerator());
  450. tc.setTransidGenerator(generator);
  451. // Socket is needed to send packets through the interface.
  452. ASSERT_NO_THROW(sock_handle = tc.openSocket());
  453. TestControl::TestControlSocket sock(sock_handle);
  454. for (int i = 0; i < iterations_num; ++i) {
  455. // Get next transaction id, without actually using it. The same
  456. // id wll be used by the TestControl class for DHCPDISCOVER.
  457. uint32_t transid = generator->getNext();
  458. if (use_templates) {
  459. ASSERT_NO_THROW(tc.sendDiscover4(sock, tc.getTemplateBuffer(0)));
  460. } else {
  461. ASSERT_NO_THROW(tc.sendDiscover4(sock));
  462. }
  463. // Do not simulate responses for packets later
  464. // that specified as receive_num. This simulates
  465. // packet drops.
  466. if (i < receive_num) {
  467. boost::shared_ptr<Pkt4> offer_pkt4(createOfferPkt4(transid));
  468. ASSERT_NO_THROW(tc.processReceivedPacket4(sock, offer_pkt4));
  469. }
  470. if (tc.checkExitConditions()) {
  471. iterations_performed = i + 1;
  472. break;
  473. }
  474. iterations_performed = i + 1;
  475. }
  476. }
  477. /// \brief Test DHCPv6 exchanges.
  478. ///
  479. /// Function simulates DHCPv6 exchanges. Function caller specifies
  480. /// number of exchanges to be simulated and number of simulated
  481. /// responses. When number of responses is lower than number of
  482. /// iterations than the difference between them is the number
  483. /// of simulated packet drops. This is useful to test if program
  484. /// exit conditions are handled properly (maximum number of packet
  485. /// drops specified as -D<max-drops> is taken into account).
  486. ///
  487. /// \param iterations_num number of exchanges to simulate.
  488. /// \param receive_num number of received OFFER packets.
  489. /// \param iterations_performed actual number of iterations.
  490. void testPkt6Exchange(int iterations_num,
  491. int receive_num,
  492. bool use_templates,
  493. int& iterations_performed) const {
  494. int sock_handle = 0;
  495. NakedTestControl tc;
  496. tc.initializeStatsMgr();
  497. // Use templates files to crate packets.
  498. if (use_templates) {
  499. tc.initPacketTemplates();
  500. ASSERT_NO_THROW(tc.getTemplateBuffer(0));
  501. ASSERT_NO_THROW(tc.getTemplateBuffer(1));
  502. }
  503. // Incremental transaction id generator will generate
  504. // predictable values of transaction id for each iteration.
  505. // This is important because we need to simulate responses
  506. // from the server and use the same transaction ids as in
  507. // packets sent by client.
  508. TestControl::NumberGeneratorPtr
  509. generator(new NakedTestControl::IncrementalGenerator());
  510. tc.setTransidGenerator(generator);
  511. // Socket is needed to send packets through the interface.
  512. ASSERT_NO_THROW(sock_handle = tc.openSocket());
  513. TestControl::TestControlSocket sock(sock_handle);
  514. uint32_t transid = 0;
  515. for (int i = 0; i < iterations_num; ++i) {
  516. // Do not simulate responses for packets later
  517. // that specified as receive_num. This simulates
  518. // packet drops.
  519. if (use_templates) {
  520. ASSERT_NO_THROW(tc.sendSolicit6(sock, tc.getTemplateBuffer(0)));
  521. } else {
  522. ASSERT_NO_THROW(tc.sendSolicit6(sock));
  523. }
  524. ++transid;
  525. if (i < receive_num) {
  526. boost::shared_ptr<Pkt6>
  527. advertise_pkt6(createAdvertisePkt6(transid));
  528. // Receive ADVERTISE and send REQUEST.
  529. ASSERT_NO_THROW(tc.processReceivedPacket6(sock,
  530. advertise_pkt6));
  531. ++transid;
  532. }
  533. if (tc.checkExitConditions()) {
  534. iterations_performed = i + 1;
  535. break;
  536. }
  537. iterations_performed = i + 1;
  538. }
  539. }
  540. /// \brief Test generation of multiple MAC addresses.
  541. ///
  542. /// This method validates generation of multiple MAC addresses.
  543. /// The MAC address can be randomized depending on the number
  544. /// of simulated clients. This test checks if different MAC
  545. /// addresses are generated if number of simulated clients is
  546. /// greater than 1. It also checks if the same MAC addresses is
  547. /// generated if only 1 client is simulated.
  548. void testMacAddress() const {
  549. int clients_num = CommandOptions::instance().getClientsNum();
  550. // The old_mac will be holding the value of previously generated
  551. // MAC address. We will be comparing the newly generated one with it
  552. // to see if it changes when multiple clients are simulated or if it
  553. // does not change when single client is simulated.
  554. MacAddress old_mac(CommandOptions::instance().getMacTemplate());
  555. // Holds the position if the octet on which two MAC addresses can
  556. // be different. If number of clients is 256 or less it is last MAC
  557. // octet (except for single client when subsequent MAC addresses
  558. // have to be equal). If number of clients is between 257 and 65536
  559. // the last two octets can differ etc.
  560. int unequal_pos = unequalOctetPosition(clients_num);
  561. // Number of unique MACs.
  562. size_t unique_macs = 0;
  563. // Initialize Test Controller.
  564. NakedTestControl tc;
  565. size_t total_dist = 0;
  566. // Keep generated MACs in this container.
  567. std::list<std::vector<uint8_t> > macs;
  568. // Do many iterations to generate and test MAC address values.
  569. for (int i = 0; i < clients_num * 10; ++i) {
  570. // Generate new MAC address.
  571. uint8_t randomized = 0;
  572. MacAddress new_mac(tc.generateMacAddress(randomized));
  573. // Get the mismatch position (counting from the end) of
  574. // mismatched octet between previously generated MAC address
  575. // and current.
  576. std::pair<MacAddressIterator, MacAddressIterator> mismatch_pos =
  577. std::mismatch(old_mac.begin(), old_mac.end(), new_mac.begin());
  578. size_t mismatch_dist =
  579. std::distance(mismatch_pos.first, old_mac.end());
  580. // For single client total_dist is expected to be 0 because
  581. // old_mac and new_mac should always match. If we have
  582. // more clients then MAC addresses have to differ except
  583. // the case if randomization algorithm generates the same
  584. // values but this would be an error in randomization algorithm.
  585. total_dist += mismatch_dist;
  586. // Mismatch may have occurred on the MAC address'es octet position
  587. // up to calculated earlier unequal_pos.
  588. ASSERT_LE(mismatch_dist, unequal_pos);
  589. // unique will inform if tested DUID is unique.
  590. bool unique = true;
  591. for (std::list<std::vector<uint8_t> >::const_iterator it =
  592. macs.begin();
  593. it != macs.end(); ++it) {
  594. // MACs should be of the same size if we want to compare them.
  595. ASSERT_EQ(new_mac.size(), it->size());
  596. // Check if MAC is unique.
  597. if (std::equal(new_mac.begin(), new_mac.end(), it->begin())) {
  598. unique = false;
  599. }
  600. }
  601. // Expecting that MACs will be unique only when
  602. // first clients-num iterations is performed.
  603. // After that, MACs become non unique.
  604. if (unique) {
  605. ++unique_macs;
  606. }
  607. // For number of iterations equal to clients_num,2*clients_num
  608. // 3*clients_num ... we have to have number of unique MACs
  609. // equal to clients_num.
  610. if ((i != 0) && (i % clients_num == 0)) {
  611. ASSERT_EQ(clients_num, unique_macs);
  612. }
  613. // Remember generated MAC.
  614. macs.push_back(new_mac);
  615. }
  616. if (clients_num < 2) {
  617. EXPECT_EQ(total_dist, 0);
  618. }
  619. }
  620. /// \brief Test sending DHCPv4 renews.
  621. ///
  622. /// This function simulates acquiring 10 leases from the server. Returned
  623. /// DHCPACK messages are cached and used to send renew messages.
  624. /// The maximal number of messages which can be sent is equal to the
  625. /// number of leases acquired (10). This function also checks that an
  626. /// attempt to send more renew messages than the number of leases acquired
  627. /// will fail.
  628. void testSendRenew4() {
  629. std::string loopback_iface(getLocalLoopback());
  630. if (loopback_iface.empty()) {
  631. std::cout << "Skipping the test because loopback interface could"
  632. " not be detected" << std::endl;
  633. return;
  634. }
  635. // Build a command line. Depending on the message type, we will use
  636. // -f<renew-rate> or -F<release-rate> parameter.
  637. std::ostringstream s;
  638. s << "perfdhcp -4 -l " << loopback_iface << " -r 10 -f";
  639. s << " 10 -R 10 -L 10067 -n 10 127.0.0.1";
  640. ASSERT_NO_THROW(processCmdLine(s.str()));
  641. // Create a test controller class.
  642. NakedTestControl tc;
  643. tc.initializeStatsMgr();
  644. // Set the transaction id generator to sequential to control to
  645. // guarantee that transaction ids are predictable.
  646. boost::shared_ptr<NakedTestControl::IncrementalGenerator>
  647. generator(new NakedTestControl::IncrementalGenerator());
  648. tc.setTransidGenerator(generator);
  649. // Socket has to be created so as we can actually send packets.
  650. int sock_handle = 0;
  651. ASSERT_NO_THROW(sock_handle = tc.openSocket());
  652. TestControl::TestControlSocket sock(sock_handle);
  653. // Send a number of DHCPDISCOVER messages. Each generated message will
  654. // be assigned a different transaction id, starting from 1 to 10.
  655. tc.sendPackets(sock, 10);
  656. // Simulate DHCPOFFER responses from the server. Each DHCPOFFER is
  657. // assigned a transaction id from the range of 1 to 10, so as they
  658. // match the transaction ids from the DHCPDISCOVER messages.
  659. for (unsigned i = generator->getNext() - 10;
  660. i < generator->getNext(); ++i) {
  661. Pkt4Ptr offer(createOfferPkt4(i));
  662. // If DHCPOFFER is matched with the DHCPDISCOVER the call below
  663. // will trigger a corresponding DHCPREQUEST. They will be assigned
  664. // transaction ids from the range from 11 to 20 (the range of
  665. // 1 to 10 has been used by DHCPDISCOVER-DHCPOFFER).
  666. ASSERT_NO_THROW(tc.processReceivedPacket4(sock, offer));
  667. }
  668. // Requests have been sent, so now let's simulate responses from the
  669. // server. Generate corresponding DHCPACK messages with the transaction
  670. // ids from the range from 11 to 20.
  671. for (unsigned i = generator->getNext() - 10;
  672. i < generator->getNext(); ++i) {
  673. Pkt4Ptr ack(createAckPkt4(i));
  674. // Each DHCPACK packet corresponds to the new lease acquired. Since
  675. // -f<renew-rate> option has been specified, received Reply
  676. // messages are held so as renew messages can be sent for
  677. // existing leases.
  678. ASSERT_NO_THROW(tc.processReceivedPacket4(sock, ack));
  679. }
  680. uint64_t msg_num;
  681. // Try to send 5 messages. It should be successful because 10
  682. // DHCPREQUEST messages has been received. For each of them we
  683. // should be able to send renewal.
  684. ASSERT_NO_THROW(
  685. msg_num = tc.sendMultipleRequests(sock, 5)
  686. );
  687. // Make sure that we have sent 5 messages.
  688. EXPECT_EQ(5, msg_num);
  689. // Try to do it again. We should still have 5 Reply packets for
  690. // which renews haven't been sent yet.
  691. ASSERT_NO_THROW(
  692. msg_num = tc.sendMultipleRequests(sock, 5)
  693. );
  694. EXPECT_EQ(5, msg_num);
  695. // We used all the DHCPACK packets (we sent renew or release for each of
  696. // them already). Therefore, no further renew messages should be sent
  697. // before we acquire new leases.
  698. ASSERT_NO_THROW(
  699. msg_num = tc.sendMultipleRequests(sock, 5)
  700. );
  701. // Make sure that no message has been sent.
  702. EXPECT_EQ(0, msg_num);
  703. }
  704. /// \brief Test that the DHCPREQUEST message is created correctly and
  705. /// comprises expected values.
  706. void testCreateRequest() {
  707. // This command line specifies that the Release/Renew messages should
  708. // be sent with the same rate as the Solicit messages.
  709. std::ostringstream s;
  710. s << "perfdhcp -4 -l lo -r 10 -f 10";
  711. s << " -R 10 -L 10067 -n 10 127.0.0.1";
  712. ASSERT_NO_THROW(processCmdLine(s.str()));
  713. // Create a test controller class.
  714. NakedTestControl tc;
  715. // Set the transaction id generator which will be used by the
  716. // createRenew or createRelease function to generate transaction id.
  717. boost::shared_ptr<NakedTestControl::IncrementalGenerator>
  718. generator(new NakedTestControl::IncrementalGenerator());
  719. tc.setTransidGenerator(generator);
  720. Pkt4Ptr ack = createAckPkt4(1);
  721. // Create DHCPREQUST from DHCPACK.
  722. Pkt4Ptr request;
  723. ASSERT_NO_THROW(request = tc.createRequestFromAck(ack));
  724. // Make sure that the DHCPACK has been successfully created and that
  725. // it holds expected data.
  726. ASSERT_TRUE(request);
  727. EXPECT_EQ("127.0.0.1", request->getCiaddr().toText());
  728. // HW address.
  729. HWAddrPtr hwaddr_ack = ack->getHWAddr();
  730. ASSERT_TRUE(hwaddr_ack);
  731. HWAddrPtr hwaddr_req = request->getHWAddr();
  732. ASSERT_TRUE(hwaddr_req);
  733. EXPECT_TRUE(hwaddr_ack->hwaddr_ == hwaddr_req->hwaddr_);
  734. // Creating message from null DHCPACK should fail.
  735. EXPECT_THROW(tc.createRequestFromAck(Pkt4Ptr()), isc::BadValue);
  736. // Creating message from DHCPACK holding zero yiaddr should fail.
  737. asiolink::IOAddress yiaddr = ack->getYiaddr();
  738. ack->setYiaddr(asiolink::IOAddress::IPV4_ZERO_ADDRESS());
  739. EXPECT_THROW(tc.createRequestFromAck(ack), isc::BadValue);
  740. ack->setYiaddr(yiaddr);
  741. }
  742. /// \brief Test that the DHCPv6 Release or Renew message is created
  743. /// correctly and comprises expected options.
  744. ///
  745. /// \param msg_type A type of the message to be tested: DHCPV6_RELEASE
  746. /// or DHCPV6_RENEW.
  747. void testCreateRenewRelease(const uint16_t msg_type) {
  748. // This command line specifies that the Release/Renew messages should
  749. // be sent with the same rate as the Solicit messages.
  750. std::ostringstream s;
  751. s << "perfdhcp -6 -l lo -r 10 ";
  752. s << (msg_type == DHCPV6_RELEASE ? "-F" : "-f") << " 10 ";
  753. s << "-R 10 -L 10547 -n 10 -e address-and-prefix ::1";
  754. ASSERT_NO_THROW(processCmdLine(s.str()));
  755. // Create a test controller class.
  756. NakedTestControl tc;
  757. // Set the transaction id generator which will be used by the
  758. // createRenew or createRelease function to generate transaction id.
  759. boost::shared_ptr<NakedTestControl::IncrementalGenerator>
  760. generator(new NakedTestControl::IncrementalGenerator());
  761. tc.setTransidGenerator(generator);
  762. // Create a Reply packet. The createRelease or createReply function will
  763. // need Reply packet to create a corresponding Release or Reply.
  764. Pkt6Ptr reply = createReplyPkt6(1);
  765. Pkt6Ptr msg;
  766. // Check that the message is created.
  767. ASSERT_NO_THROW(msg = tc.createMessageFromReply(msg_type, reply));
  768. ASSERT_TRUE(msg);
  769. // Check that the message type and transaction id is correct.
  770. EXPECT_EQ(msg_type, msg->getType());
  771. EXPECT_EQ(1, msg->getTransid());
  772. // Check that the message has expected options. These are the same for
  773. // Release and Renew.
  774. // Client Identifier.
  775. OptionPtr opt_clientid = msg->getOption(D6O_CLIENTID);
  776. ASSERT_TRUE(opt_clientid);
  777. EXPECT_TRUE(reply->getOption(D6O_CLIENTID)->getData() ==
  778. opt_clientid->getData());
  779. // Server identifier
  780. OptionPtr opt_serverid = msg->getOption(D6O_SERVERID);
  781. ASSERT_TRUE(opt_serverid);
  782. EXPECT_TRUE(reply->getOption(D6O_SERVERID)->getData() ==
  783. opt_serverid->getData());
  784. // IA_NA
  785. OptionPtr opt_ia_na = msg->getOption(D6O_IA_NA);
  786. ASSERT_TRUE(opt_ia_na);
  787. EXPECT_TRUE(reply->getOption(D6O_IA_NA)->getData() ==
  788. opt_ia_na->getData());
  789. // IA_PD
  790. OptionPtr opt_ia_pd = msg->getOption(D6O_IA_PD);
  791. ASSERT_TRUE(opt_ia_pd);
  792. EXPECT_TRUE(reply->getOption(D6O_IA_PD)->getData() ==
  793. opt_ia_pd->getData());
  794. // Make sure that exception is thrown if the Reply message is NULL.
  795. EXPECT_THROW(tc.createMessageFromReply(msg_type, Pkt6Ptr()),
  796. isc::BadValue);
  797. }
  798. /// \brief Test sending DHCPv6 Releases or Renews.
  799. ///
  800. /// This function simulates acquiring 10 leases from the server. Returned
  801. /// Reply messages are cached and used to send Renew or Release messages.
  802. /// The maximal number of Renew or Release messages which can be sent is
  803. /// equal to the number of leases acquired (10). This function also checks
  804. /// that an attempt to send more Renew or Release messages than the number
  805. /// of leases acquired will fail.
  806. ///
  807. /// \param msg_type A type of the message which is simulated to be sent
  808. /// (DHCPV6_RENEW or DHCPV6_RELEASE).
  809. void testSendRenewRelease(const uint16_t msg_type) {
  810. std::string loopback_iface(getLocalLoopback());
  811. if (loopback_iface.empty()) {
  812. std::cout << "Skipping the test because loopback interface could"
  813. " not be detected" << std::endl;
  814. return;
  815. }
  816. // Build a command line. Depending on the message type, we will use
  817. // -f<renew-rate> or -F<release-rate> parameter.
  818. std::ostringstream s;
  819. s << "perfdhcp -6 -l " << loopback_iface << " -r 10 ";
  820. s << (msg_type == DHCPV6_RENEW ? "-f" : "-F");
  821. s << " 10 -R 10 -L 10547 -n 10 ::1";
  822. ASSERT_NO_THROW(processCmdLine(s.str()));
  823. // Create a test controller class.
  824. NakedTestControl tc;
  825. tc.initializeStatsMgr();
  826. // Set the transaction id generator to sequential to control to
  827. // guarantee that transaction ids are predictable.
  828. boost::shared_ptr<NakedTestControl::IncrementalGenerator>
  829. generator(new NakedTestControl::IncrementalGenerator());
  830. tc.setTransidGenerator(generator);
  831. // Socket has to be created so as we can actually send packets.
  832. int sock_handle = 0;
  833. ASSERT_NO_THROW(sock_handle = tc.openSocket());
  834. TestControl::TestControlSocket sock(sock_handle);
  835. // Send a number of Solicit messages. Each generated Solicit will be
  836. // assigned a different transaction id, starting from 1 to 10.
  837. tc.sendPackets(sock, 10);
  838. // Simulate Advertise responses from the server. Each advertise is
  839. // assigned a transaction id from the range of 1 to 10, so as they
  840. // match the transaction ids from the Solicit messages.
  841. for (unsigned i = generator->getNext() - 10;
  842. i < generator->getNext(); ++i) {
  843. Pkt6Ptr advertise(createAdvertisePkt6(i));
  844. // If Advertise is matched with the Solicit the call below will
  845. // trigger a corresponding Request. They will be assigned
  846. // transaction ids from the range from 11 to 20 (the range of
  847. // 1 to 10 has been used by Solicit-Advertise).
  848. ASSERT_NO_THROW(tc.processReceivedPacket6(sock, advertise));
  849. }
  850. // Requests have been sent, so now let's simulate responses from the
  851. // server. Generate corresponding Reply messages with the transaction
  852. // ids from the range from 11 to 20.
  853. for (unsigned i = generator->getNext() - 10;
  854. i < generator->getNext(); ++i) {
  855. Pkt6Ptr reply(createReplyPkt6(i));
  856. // Each Reply packet corresponds to the new lease acquired. Since
  857. // -f<renew-rate> option has been specified, received Reply
  858. // messages are held so as Renew messages can be sent for
  859. // existing leases.
  860. ASSERT_NO_THROW(tc.processReceivedPacket6(sock, reply));
  861. }
  862. uint64_t msg_num;
  863. // Try to send 5 messages. It should be successful because 10 Reply
  864. // messages has been received. For each of them we should be able to
  865. // send Renew or Release.
  866. ASSERT_NO_THROW(
  867. msg_num = tc.sendMultipleMessages6(sock, msg_type, 5)
  868. );
  869. // Make sure that we have sent 5 messages.
  870. EXPECT_EQ(5, msg_num);
  871. // Try to do it again. We should still have 5 Reply packets for
  872. // which Renews or Releases haven't been sent yet.
  873. ASSERT_NO_THROW(
  874. msg_num = tc.sendMultipleMessages6(sock, msg_type, 5)
  875. );
  876. EXPECT_EQ(5, msg_num);
  877. // We used all the Reply packets (we sent Renew or Release for each of
  878. // them already). Therefore, no further Renew or Release messages should
  879. // be sent before we acquire new leases.
  880. ASSERT_NO_THROW(
  881. msg_num = tc.sendMultipleMessages6(sock, msg_type, 5)
  882. );
  883. // Make sure that no message has been sent.
  884. EXPECT_EQ(0, msg_num);
  885. }
  886. /// \brief Parse command line string with CommandOptions.
  887. ///
  888. /// \param cmdline command line string to be parsed.
  889. /// \throw isc::Unexpected if unexpected error occurred.
  890. /// \throw isc::InvalidParameter if command line is invalid.
  891. void processCmdLine(const std::string& cmdline) const {
  892. CommandOptionsHelper::process(cmdline);
  893. }
  894. /// \brief Create DHCPOFFER or DHCPACK packet.
  895. ///
  896. /// \param pkt_type DHCPOFFER or DHCPACK.
  897. /// \param transid Transaction id.
  898. ///
  899. /// \return Instance of the packet.
  900. Pkt4Ptr
  901. createResponsePkt4(const uint8_t pkt_type,
  902. const uint32_t transid) const {
  903. Pkt4Ptr pkt(new Pkt4(pkt_type, transid));
  904. OptionPtr opt_serverid = Option::factory(Option::V4,
  905. DHO_DHCP_SERVER_IDENTIFIER,
  906. OptionBuffer(4, 1));
  907. pkt->setYiaddr(asiolink::IOAddress("127.0.0.1"));
  908. pkt->addOption(opt_serverid);
  909. pkt->updateTimestamp();
  910. return (pkt);
  911. }
  912. /// \brief Create DHCPv4 OFFER packet.
  913. ///
  914. /// \param transid transaction id.
  915. /// \return instance of the packet.
  916. Pkt4Ptr
  917. createOfferPkt4(uint32_t transid) const {
  918. return (createResponsePkt4(DHCPOFFER, transid));
  919. }
  920. /// \brief Create DHCPACK packet.
  921. ///
  922. /// \param transid transaction id.
  923. /// \return instance of the packet.
  924. Pkt4Ptr
  925. createAckPkt4(const uint32_t transid) const {
  926. return (createResponsePkt4(DHCPACK, transid));
  927. }
  928. /// \brief Create DHCPv6 ADVERTISE packet.
  929. ///
  930. /// \param transid transaction id.
  931. /// \return instance of the packet.
  932. Pkt6Ptr
  933. createAdvertisePkt6(const uint32_t transid) const {
  934. boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE, transid));
  935. // Add IA_NA if requested by the client.
  936. if (CommandOptions::instance().getLeaseType()
  937. .includes(CommandOptions::LeaseType::ADDRESS)) {
  938. OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
  939. advertise->addOption(opt_ia_na);
  940. }
  941. // Add IA_PD if requested by the client.
  942. if (CommandOptions::instance().getLeaseType()
  943. .includes(CommandOptions::LeaseType::PREFIX)) {
  944. OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD);
  945. advertise->addOption(opt_ia_pd);
  946. }
  947. OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
  948. NakedTestControl tc;
  949. uint8_t randomized = 0;
  950. std::vector<uint8_t> duid(tc.generateDuid(randomized));
  951. OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
  952. advertise->addOption(opt_serverid);
  953. advertise->addOption(opt_clientid);
  954. advertise->updateTimestamp();
  955. return (advertise);
  956. }
  957. Pkt6Ptr
  958. createReplyPkt6(const uint32_t transid) const {
  959. Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, transid));
  960. // Add IA_NA if requested by the client.
  961. if (CommandOptions::instance().getLeaseType()
  962. .includes(CommandOptions::LeaseType::ADDRESS)) {
  963. OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
  964. reply->addOption(opt_ia_na);
  965. }
  966. // Add IA_PD if requested by the client.
  967. if (CommandOptions::instance().getLeaseType()
  968. .includes(CommandOptions::LeaseType::PREFIX)) {
  969. OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD);
  970. reply->addOption(opt_ia_pd);
  971. }
  972. OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
  973. NakedTestControl tc;
  974. uint8_t randomized = 0;
  975. std::vector<uint8_t> duid(tc.generateDuid(randomized));
  976. OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
  977. reply->addOption(opt_serverid);
  978. reply->addOption(opt_clientid);
  979. reply->updateTimestamp();
  980. return (reply);
  981. }
  982. };
  983. // This test verifies that the class members are reset to expected values.
  984. TEST_F(TestControlTest, reset) {
  985. ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l ethx -r 50 -f 30 -F 10 -a 3 all"));
  986. NakedTestControl tc;
  987. tc.reset();
  988. EXPECT_EQ(3, tc.basic_rate_control_.getAggressivity());
  989. EXPECT_EQ(3, tc.renew_rate_control_.getAggressivity());
  990. EXPECT_EQ(3, tc.release_rate_control_.getAggressivity());
  991. EXPECT_EQ(50, tc.basic_rate_control_.getRate());
  992. EXPECT_EQ(30, tc.renew_rate_control_.getRate());
  993. EXPECT_EQ(10, tc.release_rate_control_.getRate());
  994. EXPECT_FALSE(tc.last_report_.is_not_a_date_time());
  995. EXPECT_FALSE(tc.transid_gen_);
  996. EXPECT_FALSE(tc.macaddr_gen_);
  997. EXPECT_TRUE(tc.first_packet_serverid_.empty());
  998. EXPECT_FALSE(tc.interrupted_);
  999. }
  1000. // This test verifies that the client id is generated from the HW address.
  1001. TEST_F(TestControlTest, generateClientId) {
  1002. // Generate HW address.
  1003. std::vector<uint8_t> hwaddr;
  1004. for (unsigned int i = 0; i < 6; ++i) {
  1005. hwaddr.push_back(i);
  1006. }
  1007. HWAddrPtr hwaddr_ptr(new HWAddr(hwaddr, 5));
  1008. // Use generated HW address to generate client id.
  1009. NakedTestControl tc;
  1010. OptionPtr opt_client_id;
  1011. ASSERT_NO_THROW(opt_client_id = tc.generateClientId(hwaddr_ptr));
  1012. ASSERT_TRUE(opt_client_id);
  1013. // Extract the client id data.
  1014. const OptionBuffer& client_id = opt_client_id->getData();
  1015. ASSERT_EQ(7, client_id.size());
  1016. // Verify that the client identifier is generated correctly.
  1017. // First byte is the HW type.
  1018. EXPECT_EQ(5, client_id[0]);
  1019. // The rest of the client identifier should be equal to the HW address.
  1020. std::vector<uint8_t> sub(client_id.begin() + 1, client_id.end());
  1021. EXPECT_TRUE(hwaddr == sub);
  1022. }
  1023. TEST_F(TestControlTest, GenerateDuid) {
  1024. // Simple command line that simulates one client only. Always the
  1025. // same DUID will be generated.
  1026. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 all"));
  1027. testDuid();
  1028. // Simulate 50 clients. Different DUID will be generated.
  1029. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -R 50 all"));
  1030. testDuid();
  1031. // Checks that the random mac address returned by generateDuid
  1032. // is in the list of mac addresses in the mac-list.txt data file
  1033. std::string mac_list_full_path = getFullPath("mac-list.txt");
  1034. std::ostringstream cmd;
  1035. cmd << "perfdhcp -M " << mac_list_full_path << " abc";
  1036. ASSERT_NO_THROW(processCmdLine(cmd.str()));
  1037. // Initialize Test Controller.
  1038. NakedTestControl tc;
  1039. uint8_t randomized = 0;
  1040. std::vector<uint8_t> generated_duid = tc.generateDuid(randomized);
  1041. // Check that generated_duid is DUID_LL
  1042. ASSERT_EQ(10, generated_duid.size());
  1043. DuidPtr duid(new DUID(generated_duid));
  1044. ASSERT_EQ(duid->getType(), DUID::DUID_LL);
  1045. // Make sure it's on the list
  1046. CommandOptions& options = CommandOptions::instance();
  1047. const CommandOptions::MacAddrsVector& macs = options.getMacsFromFile();
  1048. // DUID LL comprises 2 bytes of duid type, 2 bytes of hardware type,
  1049. // then 6 bytes of HW address.
  1050. vector<uint8_t> mac(6);
  1051. std::copy(generated_duid.begin() + 4, generated_duid.begin() + 10,
  1052. mac.begin());
  1053. // Check that mac is in macs.
  1054. ASSERT_TRUE(std::find(macs.begin(), macs.end(), mac) != macs.end());
  1055. }
  1056. TEST_F(TestControlTest, MisMatchVerionServer) {
  1057. NakedTestControl tc;
  1058. // make sure we catch -6 paired with v4 address
  1059. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -6 192.168.1.1"));
  1060. EXPECT_THROW(tc.openSocket(), isc::InvalidParameter);
  1061. // make sure we catch -4 paired with v6 address
  1062. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -4 ff02::1:2"));
  1063. EXPECT_THROW(tc.openSocket(), isc::InvalidParameter);
  1064. }
  1065. TEST_F(TestControlTest, GenerateMacAddress) {
  1066. // Simulate one client only. Always the same MAC address will be
  1067. // generated.
  1068. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 all"));
  1069. testMacAddress();
  1070. // Simulate 50 clients. Different MAC addresses will be generated.
  1071. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -R 50 all"));
  1072. testMacAddress();
  1073. // Checks that the random mac address returned by generateMacAddress
  1074. // is in the list of mac addresses in the mac-list.txt data file
  1075. std::string mac_list_full_path = getFullPath("mac-list.txt");
  1076. std::ostringstream cmd;
  1077. cmd << "perfdhcp -M " << mac_list_full_path << " abc";
  1078. ASSERT_NO_THROW(processCmdLine(cmd.str()));
  1079. // Initialize Test Controller.
  1080. NakedTestControl tc;
  1081. uint8_t randomized = 0;
  1082. // Generate MAC adddress and sanity check its size.
  1083. std::vector<uint8_t> mac = tc.generateMacAddress(randomized);
  1084. ASSERT_EQ(6, mac.size());
  1085. // Make sure that the generated MAC address belongs to the MAC addresses
  1086. // read from a file.
  1087. CommandOptions& options = CommandOptions::instance();
  1088. const CommandOptions::MacAddrsVector& macs = options.getMacsFromFile();
  1089. ASSERT_TRUE(std::find(macs.begin(), macs.end(), mac) != macs.end());
  1090. }
  1091. TEST_F(TestControlTest, Options4) {
  1092. using namespace isc::dhcp;
  1093. NakedTestControl tc;
  1094. // By default the IP version mode is V4 so there is no need to
  1095. // parse command line to override the IP version. Note that
  1096. // registerOptionFactories is used for both V4 and V6.
  1097. tc.registerOptionFactories();
  1098. // Create option with buffer size equal to 1 and holding DHCPDISCOVER
  1099. // message type.
  1100. OptionPtr opt_msg_type(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE,
  1101. OptionBuffer(1, DHCPDISCOVER)));
  1102. // Validate the option type and universe.
  1103. EXPECT_EQ(Option::V4, opt_msg_type->getUniverse());
  1104. EXPECT_EQ(DHO_DHCP_MESSAGE_TYPE, opt_msg_type->getType());
  1105. // Validate the message type from the option we have now created.
  1106. uint8_t msg_type = 0;
  1107. ASSERT_NO_THROW(msg_type = opt_msg_type->getUint8());
  1108. EXPECT_EQ(DHCPDISCOVER, msg_type);
  1109. // Create another option: DHCP_PARAMETER_REQUEST_LIST
  1110. OptionPtr
  1111. opt_requested_options(Option::factory(Option::V4,
  1112. DHO_DHCP_PARAMETER_REQUEST_LIST));
  1113. // Here is a list of options that we are requesting in the
  1114. // server's response.
  1115. const uint8_t requested_options[] = {
  1116. DHO_SUBNET_MASK,
  1117. DHO_BROADCAST_ADDRESS,
  1118. DHO_TIME_OFFSET,
  1119. DHO_ROUTERS,
  1120. DHO_DOMAIN_NAME,
  1121. DHO_DOMAIN_NAME_SERVERS,
  1122. DHO_HOST_NAME
  1123. };
  1124. OptionBuffer
  1125. requested_options_ref(requested_options,
  1126. requested_options + sizeof(requested_options));
  1127. // Get the option buffer. It should hold the combination of values
  1128. // listed in requested_options array. However their order can be
  1129. // different in general so we need to search each value separately.
  1130. const OptionBuffer& requested_options_buf =
  1131. opt_requested_options->getData();
  1132. EXPECT_EQ(requested_options_ref.size(), requested_options_buf.size());
  1133. size_t matched_num = matchRequestedOptions(requested_options_ref,
  1134. requested_options_buf);
  1135. // We want exactly the same requested options as listed in
  1136. // requested_options array - nothing more or less.
  1137. EXPECT_EQ(requested_options_ref.size(), matched_num);
  1138. }
  1139. TEST_F(TestControlTest, Options6) {
  1140. using namespace isc::dhcp;
  1141. // Lets override the IP version to test V6 options (-6 parameter)
  1142. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -6 all"));
  1143. NakedTestControl tc;
  1144. tc.registerOptionFactories();
  1145. // Validate the D6O_ELAPSED_TIME option.
  1146. OptionPtr opt_elapsed_time(Option::factory(Option::V6, D6O_ELAPSED_TIME));
  1147. // Validate the option type and universe.
  1148. EXPECT_EQ(Option::V6, opt_elapsed_time->getUniverse());
  1149. EXPECT_EQ(D6O_ELAPSED_TIME, opt_elapsed_time->getType());
  1150. // The default value of elapsed time is zero.
  1151. uint16_t elapsed_time;
  1152. ASSERT_NO_THROW(elapsed_time = opt_elapsed_time->getUint16());
  1153. EXPECT_EQ(0, elapsed_time);
  1154. // With the factory function we may also specify the actual
  1155. // value of elapsed time. Let's make use of std::vector
  1156. // constructor to create the option buffer, 2 octets long
  1157. // with each octet initialized to 0x1.
  1158. size_t elapsed_time_buf_size = 2;
  1159. uint8_t elapsed_time_pattern = 0x1;
  1160. OptionPtr
  1161. opt_elapsed_time2(Option::factory(Option::V6, D6O_ELAPSED_TIME,
  1162. OptionBuffer(elapsed_time_buf_size,
  1163. elapsed_time_pattern)));
  1164. // Any buffer that has size neither equal to 0 nor 2 is considered invalid.
  1165. elapsed_time_buf_size = 1;
  1166. EXPECT_THROW(
  1167. Option::factory(Option::V6, D6O_ELAPSED_TIME,
  1168. OptionBuffer(elapsed_time_buf_size, elapsed_time_pattern)),
  1169. isc::BadValue
  1170. );
  1171. // Validate the option type and universe.
  1172. EXPECT_EQ(Option::V6, opt_elapsed_time2->getUniverse());
  1173. EXPECT_EQ(D6O_ELAPSED_TIME, opt_elapsed_time2->getType());
  1174. // Make sure the getUint16 does not throw exception. It wile throw
  1175. // buffer is shorter than 2 octets.
  1176. ASSERT_NO_THROW(elapsed_time = opt_elapsed_time2->getUint16());
  1177. // Check the expected value of elapsed time.
  1178. EXPECT_EQ(0x0101, elapsed_time);
  1179. // Validate the D6O_RAPID_COMMIT option.
  1180. OptionPtr opt_rapid_commit(Option::factory(Option::V6, D6O_RAPID_COMMIT));
  1181. // Validate the option type and universe.
  1182. EXPECT_EQ(Option::V6, opt_rapid_commit->getUniverse());
  1183. EXPECT_EQ(D6O_RAPID_COMMIT, opt_rapid_commit->getType());
  1184. // Rapid commit has no data payload.
  1185. EXPECT_THROW(opt_rapid_commit->getUint8(), isc::OutOfRange);
  1186. // Validate the D6O_CLIENTID option.
  1187. OptionBuffer duid(CommandOptions::instance().getDuidTemplate());
  1188. OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
  1189. EXPECT_EQ(Option::V6, opt_clientid->getUniverse());
  1190. EXPECT_EQ(D6O_CLIENTID, opt_clientid->getType());
  1191. const OptionBuffer& duid2 = opt_clientid->getData();
  1192. ASSERT_EQ(duid.size(), duid2.size());
  1193. // The Duid we set for option is the same we get.
  1194. EXPECT_TRUE(std::equal(duid.begin(), duid.end(), duid2.begin()));
  1195. // Validate the D6O_ORO (Option Request Option).
  1196. OptionPtr opt_oro(Option::factory(Option::V6, D6O_ORO));
  1197. // Prepare the reference buffer with requested options.
  1198. const uint8_t requested_options[] = {
  1199. 0, D6O_NAME_SERVERS,
  1200. 0, D6O_DOMAIN_SEARCH
  1201. };
  1202. // Each option code in ORO is 2 bytes long. We calculate the number of
  1203. // requested options by dividing the size of the buffer holding options
  1204. // by the size of each individual option.
  1205. int requested_options_num = sizeof(requested_options) / sizeof(uint16_t);
  1206. OptionBuffer
  1207. requested_options_ref(requested_options,
  1208. requested_options + sizeof(requested_options));
  1209. // Get the buffer from option.
  1210. const OptionBuffer& requested_options_buf = opt_oro->getData();
  1211. // Size of reference buffer and option buffer have to be
  1212. // the same for comparison.
  1213. EXPECT_EQ(requested_options_ref.size(), requested_options_buf.size());
  1214. // Check if all options in the buffer are matched with reference buffer.
  1215. size_t matched_num = matchRequestedOptions6(requested_options_ref,
  1216. requested_options_buf);
  1217. EXPECT_EQ(requested_options_num, matched_num);
  1218. // Validate the D6O_IA_NA option.
  1219. OptionPtr opt_ia_na(Option::factory(Option::V6, D6O_IA_NA));
  1220. EXPECT_EQ(Option::V6, opt_ia_na->getUniverse());
  1221. EXPECT_EQ(D6O_IA_NA, opt_ia_na->getType());
  1222. // Every IA_NA option is expected to start with this sequence.
  1223. const uint8_t opt_ia_na_array[] = {
  1224. 0, 0, 0, 1, // IAID = 1
  1225. 0, 0, 3600 >> 8, 3600 & 0xff, // T1 = 3600
  1226. 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400
  1227. };
  1228. OptionBuffer opt_ia_na_ref(opt_ia_na_array,
  1229. opt_ia_na_array + sizeof(opt_ia_na_array));
  1230. const OptionBuffer& opt_ia_na_buf = opt_ia_na->getData();
  1231. ASSERT_EQ(opt_ia_na_buf.size(), opt_ia_na_ref.size());
  1232. EXPECT_TRUE(std::equal(opt_ia_na_ref.begin(), opt_ia_na_ref.end(),
  1233. opt_ia_na_buf.begin()));
  1234. // @todo Add more tests for IA address options.
  1235. }
  1236. TEST_F(TestControlTest, Packet4) {
  1237. // Use Interface Manager to get the local loopback interface.
  1238. // If interface can't be found we don't want to fail test.
  1239. std::string loopback_iface(getLocalLoopback());
  1240. if (!loopback_iface.empty()) {
  1241. ASSERT_NO_THROW(processCmdLine("perfdhcp -l " + loopback_iface +
  1242. " -L 10547 all"));
  1243. NakedTestControl tc;
  1244. int sock_handle = 0;
  1245. // We have to create the socket to setup some parameters of
  1246. // outgoing packet.
  1247. ASSERT_NO_THROW(sock_handle = tc.openSocket());
  1248. TestControl::TestControlSocket sock(sock_handle);
  1249. uint32_t transid = 123;
  1250. boost::shared_ptr<Pkt4> pkt4(new Pkt4(DHCPDISCOVER, transid));
  1251. // Set parameters on outgoing packet.
  1252. ASSERT_NO_THROW(tc.setDefaults4(sock, pkt4));
  1253. // Validate that packet has been setup correctly.
  1254. EXPECT_EQ(loopback_iface, pkt4->getIface());
  1255. EXPECT_EQ(sock.ifindex_, pkt4->getIndex());
  1256. EXPECT_EQ(DHCP4_CLIENT_PORT, pkt4->getLocalPort());
  1257. EXPECT_EQ(DHCP4_SERVER_PORT, pkt4->getRemotePort());
  1258. EXPECT_EQ(1, pkt4->getHops());
  1259. EXPECT_EQ(asiolink::IOAddress("255.255.255.255"),
  1260. pkt4->getRemoteAddr());
  1261. EXPECT_EQ(asiolink::IOAddress(sock.addr_), pkt4->getLocalAddr());
  1262. EXPECT_EQ(asiolink::IOAddress(sock.addr_), pkt4->getGiaddr());
  1263. } else {
  1264. std::cout << "Unable to find the loopback interface. Skip test. "
  1265. << std::endl;
  1266. }
  1267. }
  1268. TEST_F(TestControlTest, Packet6) {
  1269. // Use Interface Manager to get the local loopback interface.
  1270. // If the interface can't be found we don't want to fail test.
  1271. std::string loopback_iface(getLocalLoopback());
  1272. if (!loopback_iface.empty()) {
  1273. ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l " + loopback_iface +
  1274. " -L 10547 servers"));
  1275. NakedTestControl tc;
  1276. int sock_handle = 0;
  1277. // Create the socket. It will be needed to set packet's
  1278. // parameters.
  1279. ASSERT_NO_THROW(sock_handle = tc.openSocket());
  1280. TestControl::TestControlSocket sock(sock_handle);
  1281. uint32_t transid = 123;
  1282. boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
  1283. // Set packet's parameters.
  1284. ASSERT_NO_THROW(tc.setDefaults6(sock, pkt6));
  1285. // Validate if parameters have been set correctly.
  1286. EXPECT_EQ(loopback_iface, pkt6->getIface());
  1287. EXPECT_EQ(sock.ifindex_, pkt6->getIndex());
  1288. EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort());
  1289. EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort());
  1290. EXPECT_EQ(sock.addr_, pkt6->getLocalAddr());
  1291. EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr());
  1292. // Packet must not be relayed.
  1293. EXPECT_TRUE(pkt6->relay_info_.empty());
  1294. } else {
  1295. std::cout << "Unable to find the loopback interface. Skip test. "
  1296. << std::endl;
  1297. }
  1298. }
  1299. TEST_F(TestControlTest, Packet6Relayed) {
  1300. // Use Interface Manager to get the local loopback interface.
  1301. // If the interface can't be found we don't want to fail test.
  1302. std::string loopback_iface(getLocalLoopback());
  1303. if (!loopback_iface.empty()) {
  1304. ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l " + loopback_iface +
  1305. " -A1 -L 10547 servers"));
  1306. NakedTestControl tc;
  1307. int sock_handle = 0;
  1308. // Create the socket. It will be needed to set packet's
  1309. // parameters.
  1310. ASSERT_NO_THROW(sock_handle = tc.openSocket());
  1311. TestControl::TestControlSocket sock(sock_handle);
  1312. uint32_t transid = 123;
  1313. boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
  1314. // Set packet's parameters.
  1315. ASSERT_NO_THROW(tc.setDefaults6(sock, pkt6));
  1316. // Validate if parameters have been set correctly.
  1317. EXPECT_EQ(loopback_iface, pkt6->getIface());
  1318. EXPECT_EQ(sock.ifindex_, pkt6->getIndex());
  1319. EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort());
  1320. EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort());
  1321. EXPECT_EQ(sock.addr_, pkt6->getLocalAddr());
  1322. EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr());
  1323. // Packet should be relayed.
  1324. EXPECT_EQ(pkt6->relay_info_.size(), 1);
  1325. EXPECT_EQ(pkt6->relay_info_[0].hop_count_, 1);
  1326. EXPECT_EQ(pkt6->relay_info_[0].msg_type_, DHCPV6_RELAY_FORW);
  1327. EXPECT_EQ(pkt6->relay_info_[0].linkaddr_, sock.addr_);
  1328. EXPECT_EQ(pkt6->relay_info_[0].peeraddr_, sock.addr_);
  1329. } else {
  1330. std::cout << "Unable to find the loopback interface. Skip test. "
  1331. << std::endl;
  1332. }
  1333. }
  1334. TEST_F(TestControlTest, Packet4Exchange) {
  1335. // Get the local loopback interface to open socket on
  1336. // it and test packets exchanges. We don't want to fail
  1337. // the test if interface is not available.
  1338. std::string loopback_iface(getLocalLoopback());
  1339. if (loopback_iface.empty()) {
  1340. std::cout << "Unable to find the loopback interface. Skip test."
  1341. << std::endl;
  1342. return;
  1343. }
  1344. // Set number of iterations to some high value.
  1345. const int iterations_num = 100;
  1346. processCmdLine("perfdhcp -l " + loopback_iface
  1347. + " -r 100 -n 10 -R 20 -L 10547 127.0.0.1");
  1348. // The actual number of iterations will be stored in the
  1349. // following variable.
  1350. int iterations_performed = 0;
  1351. bool use_templates = false;
  1352. testPkt4Exchange(iterations_num, iterations_num, use_templates, iterations_performed);
  1353. // The command line restricts the number of iterations to 10
  1354. // with -n 10 parameter.
  1355. EXPECT_EQ(10, iterations_performed);
  1356. // With the following command line we restrict the maximum
  1357. // number of dropped packets to 10% of all.
  1358. // Use templates for this test.
  1359. processCmdLine("perfdhcp -l " + loopback_iface
  1360. + " -r 100 -R 20 -n 20 -D 10% -L 10547"
  1361. + " -T " + getFullPath("discover-example.hex")
  1362. + " -T " + getFullPath("request4-example.hex")
  1363. + " 127.0.0.1");
  1364. // The number iterations is restricted by the percentage of
  1365. // dropped packets (-D 10%). We also have to bump up the number
  1366. // of iterations because the percentage limitation checks starts
  1367. // at packet #10. We expect that at packet #12 the 10% threshold
  1368. // will be reached.
  1369. const int received_num = 10;
  1370. use_templates = true;
  1371. testPkt4Exchange(iterations_num, received_num, use_templates, iterations_performed);
  1372. EXPECT_EQ(12, iterations_performed);
  1373. }
  1374. TEST_F(TestControlTest, Packet6ExchangeFromTemplate) {
  1375. // Get the local loopback interface to open socket on
  1376. // it and test packets exchanges. We don't want to fail
  1377. // the test if interface is not available.
  1378. std::string loopback_iface(getLocalLoopback());
  1379. if (loopback_iface.empty()) {
  1380. std::cout << "Unable to find the loopback interface. Skip test."
  1381. << std::endl;
  1382. return;
  1383. }
  1384. const int iterations_num = 100;
  1385. // Set number of iterations to 10.
  1386. processCmdLine("perfdhcp -l " + loopback_iface
  1387. + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
  1388. int iterations_performed = 0;
  1389. // Set number of received packets equal to number of iterations.
  1390. // This simulates no packet drops.
  1391. bool use_templates = false;
  1392. testPkt6Exchange(iterations_num, iterations_num, use_templates,
  1393. iterations_performed);
  1394. // Actual number of iterations should be 10.
  1395. EXPECT_EQ(10, iterations_performed);
  1396. // The maximum number of dropped packets is 3 (because of -D 3).
  1397. use_templates = true;
  1398. processCmdLine("perfdhcp -l " + loopback_iface
  1399. + " -6 -r 100 -n 10 -R 20 -D 3 -L 10547"
  1400. + " -T " + getFullPath("solicit-example.hex")
  1401. + " -T " + getFullPath("request6-example.hex ::1"));
  1402. // For the first 3 packets we are simulating responses from server.
  1403. // For other packets we don't so packet as 4,5,6 will be dropped and
  1404. // then test should be interrupted and actual number of iterations will
  1405. // be 6.
  1406. const int received_num = 3;
  1407. // Simulate the number of Solicit-Advertise-Request-Reply (SARR) exchanges.
  1408. // The test function generates server's responses and passes it to the
  1409. // TestControl class methods for processing. The number of exchanges
  1410. // actually performed is returned in 'iterations_performed' argument. If
  1411. // processing is successful, the number of performed iterations should be
  1412. // equal to the number of exchanges specified with the '-n' command line
  1413. // parameter (10 in this case). All exchanged packets carry the IA_NA option
  1414. // to simulate the IPv6 address acquisition and to verify that the
  1415. // IA_NA options returned by the server are processed correctly.
  1416. testPkt6Exchange(iterations_num, received_num, use_templates,
  1417. iterations_performed);
  1418. EXPECT_EQ(6, iterations_performed);
  1419. }
  1420. TEST_F(TestControlTest, Packet6Exchange) {
  1421. // Get the local loopback interface to open socket on
  1422. // it and test packets exchanges. We don't want to fail
  1423. // the test if interface is not available.
  1424. std::string loopback_iface(getLocalLoopback());
  1425. if (loopback_iface.empty()) {
  1426. std::cout << "Unable to find the loopback interface. Skip test."
  1427. << std::endl;
  1428. return;
  1429. }
  1430. const int iterations_num = 100;
  1431. // Set number of iterations to 10.
  1432. processCmdLine("perfdhcp -l " + loopback_iface
  1433. + " -e address-only"
  1434. + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
  1435. int iterations_performed = 0;
  1436. // Set number of received packets equal to number of iterations.
  1437. // This simulates no packet drops.
  1438. bool use_templates = false;
  1439. // Simulate the number of Solicit-Advertise-Request-Reply (SARR) exchanges.
  1440. // The test function generates server's responses and passes it to the
  1441. // TestControl class methods for processing. The number of exchanges
  1442. // actually performed is returned in 'iterations_performed' argument. If
  1443. // processing is successful, the number of performed iterations should be
  1444. // equal to the number of exchanges specified with the '-n' command line
  1445. // parameter (10 in this case). All exchanged packets carry the IA_NA option
  1446. // to simulate the IPv6 address acquisition and to verify that the IA_NA
  1447. // options returned by the server are processed correctly.
  1448. testPkt6Exchange(iterations_num, iterations_num, use_templates,
  1449. iterations_performed);
  1450. // Actual number of iterations should be 10.
  1451. EXPECT_EQ(10, iterations_performed);
  1452. }
  1453. TEST_F(TestControlTest, Packet6ExchangePrefixDelegation) {
  1454. // Get the local loopback interface to open socket on
  1455. // it and test packets exchanges. We don't want to fail
  1456. // the test if interface is not available.
  1457. std::string loopback_iface(getLocalLoopback());
  1458. if (loopback_iface.empty()) {
  1459. std::cout << "Unable to find the loopback interface. Skip test."
  1460. << std::endl;
  1461. return;
  1462. }
  1463. const int iterations_num = 100;
  1464. // Set number of iterations to 10.
  1465. processCmdLine("perfdhcp -l " + loopback_iface
  1466. + " -e prefix-only"
  1467. + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
  1468. int iterations_performed = 0;
  1469. // Set number of received packets equal to number of iterations.
  1470. // This simulates no packet drops.
  1471. bool use_templates = false;
  1472. // Simulate the number of Solicit-Advertise-Request-Reply (SARR) exchanges.
  1473. // The test function generates server's responses and passes it to the
  1474. // TestControl class methods for processing. The number of exchanges
  1475. // actually performed is returned in 'iterations_performed' argument. If
  1476. // processing is successful, the number of performed iterations should be
  1477. // equal to the number of exchanges specified with the '-n' command line
  1478. // parameter (10 in this case). All exchanged packets carry the IA_PD option
  1479. // to simulate the Prefix Delegation and to verify that the IA_PD options
  1480. // returned by the server are processed correctly.
  1481. testPkt6Exchange(iterations_num, iterations_num, use_templates,
  1482. iterations_performed);
  1483. // Actual number of iterations should be 10.
  1484. EXPECT_EQ(10, iterations_performed);
  1485. }
  1486. TEST_F(TestControlTest, Packet6ExchangeAddressAndPrefix) {
  1487. // Get the local loopback interface to open socket on
  1488. // it and test packets exchanges. We don't want to fail
  1489. // the test if interface is not available.
  1490. std::string loopback_iface(getLocalLoopback());
  1491. if (loopback_iface.empty()) {
  1492. std::cout << "Unable to find the loopback interface. Skip test."
  1493. << std::endl;
  1494. return;
  1495. }
  1496. const int iterations_num = 100;
  1497. // Set number of iterations to 10.
  1498. processCmdLine("perfdhcp -l " + loopback_iface
  1499. + " -e address-and-prefix"
  1500. + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
  1501. int iterations_performed = 0;
  1502. // Set number of received packets equal to number of iterations.
  1503. // This simulates no packet drops.
  1504. bool use_templates = false;
  1505. // Simulate the number of Solicit-Advertise-Request-Reply (SARR) exchanges.
  1506. // The test function generates server's responses and passes it to the
  1507. // TestControl class methods for processing. The number of exchanges
  1508. // actually performed is returned in 'iterations_performed' argument. If
  1509. // processing is successful, the number of performed iterations should be
  1510. // equal to the number of exchanges specified with the '-n' command line
  1511. // parameter (10 in this case). All exchanged packets carry either IA_NA
  1512. // or IA_PD options to simulate the address and prefix acquisition with
  1513. // the single message and to verify that the IA_NA and IA_PD options
  1514. // returned by the server are processed correctly.
  1515. testPkt6Exchange(iterations_num, iterations_num, use_templates,
  1516. iterations_performed);
  1517. // Actual number of iterations should be 10.
  1518. EXPECT_EQ(10, iterations_performed);
  1519. }
  1520. TEST_F(TestControlTest, PacketTemplates) {
  1521. std::vector<uint8_t> template1(256);
  1522. std::string file1("test1.hex");
  1523. std::vector<uint8_t> template2(233);
  1524. std::string file2("test2.hex");
  1525. for (size_t i = 0; i < template1.size(); ++i) {
  1526. template1[i] = static_cast<uint8_t>(random() % 256);
  1527. }
  1528. for (size_t i = 0; i < template2.size(); ++i) {
  1529. template2[i] = static_cast<uint8_t>(random() % 256);
  1530. }
  1531. // Size of the file is 2 times larger than binary data size.
  1532. ASSERT_TRUE(createTemplateFile(file1, template1, template1.size() * 2));
  1533. ASSERT_TRUE(createTemplateFile(file2, template2, template2.size() * 2));
  1534. NakedTestControl tc;
  1535. ASSERT_NO_THROW(
  1536. processCmdLine("perfdhcp -l 127.0.0.1"
  1537. " -T " + file1 + " -T " + file2 + " all")
  1538. );
  1539. ASSERT_NO_THROW(tc.initPacketTemplates());
  1540. TestControl::TemplateBuffer buf1;
  1541. TestControl::TemplateBuffer buf2;
  1542. ASSERT_NO_THROW(buf1 = tc.getTemplateBuffer(0));
  1543. ASSERT_NO_THROW(buf2 = tc.getTemplateBuffer(1));
  1544. ASSERT_EQ(template1.size(), buf1.size());
  1545. ASSERT_EQ(template2.size(), buf2.size());
  1546. EXPECT_TRUE(std::equal(template1.begin(), template1.end(), buf1.begin()));
  1547. EXPECT_TRUE(std::equal(template2.begin(), template2.end(), buf2.begin()));
  1548. // Try to read template file with odd number of digits.
  1549. std::string file3("test3.hex");
  1550. // Size of the file is 2 times larger than binary data size and it is always
  1551. // even number. Substracting 1 makes file size odd.
  1552. ASSERT_TRUE(createTemplateFile(file3, template1, template1.size() * 2 - 1));
  1553. ASSERT_NO_THROW(
  1554. processCmdLine("perfdhcp -l 127.0.0.1 -T " + file3 + " all")
  1555. );
  1556. EXPECT_THROW(tc.initPacketTemplates(), isc::OutOfRange);
  1557. // Try to read empty file.
  1558. std::string file4("test4.hex");
  1559. ASSERT_TRUE(createTemplateFile(file4, template2, 0));
  1560. ASSERT_NO_THROW(
  1561. processCmdLine("perfdhcp -l 127.0.0.1 -T " + file4 + " all")
  1562. );
  1563. EXPECT_THROW(tc.initPacketTemplates(), isc::OutOfRange);
  1564. // Try reading file with non hexadecimal characters.
  1565. std::string file5("test5.hex");
  1566. ASSERT_TRUE(createTemplateFile(file5, template1, template1.size() * 2, true));
  1567. ASSERT_NO_THROW(
  1568. processCmdLine("perfdhcp -l 127.0.0.1 -T " + file5 + " all")
  1569. );
  1570. EXPECT_THROW(tc.initPacketTemplates(), isc::BadValue);
  1571. }
  1572. // This test verifies that DHCPv4 renew (DHCPREQUEST) messages can be
  1573. // sent for acquired leases.
  1574. TEST_F(TestControlTest, processRenew4) {
  1575. testSendRenew4();
  1576. }
  1577. // This test verifies that DHCPv6 Renew messages can be sent for acquired
  1578. // leases.
  1579. TEST_F(TestControlTest, processRenew6) {
  1580. testSendRenewRelease(DHCPV6_RENEW);
  1581. }
  1582. // This test verifies that DHCPv6 Release messages can be sent for acquired
  1583. // leases.
  1584. TEST_F(TestControlTest, processRelease6) {
  1585. testSendRenewRelease(DHCPV6_RELEASE);
  1586. }
  1587. // This test verifies that DHCPREQUEST is created correctly from the
  1588. // DHCPACK message.
  1589. TEST_F(TestControlTest, createRequest) {
  1590. testCreateRequest();
  1591. }
  1592. // This test verifies that the DHCPV6 Renew message is created correctly
  1593. // and that it comprises all required options.
  1594. TEST_F(TestControlTest, createRenew) {
  1595. testCreateRenewRelease(DHCPV6_RENEW);
  1596. }
  1597. // This test verifies that the DHCPv6 Release message is created correctly
  1598. // and that it comprises all required options.
  1599. TEST_F(TestControlTest, createRelease) {
  1600. testCreateRenewRelease(DHCPV6_RELEASE);
  1601. }
  1602. // This test verifies that the current timeout value for waiting for
  1603. // the server's responses is valid. The timeout value corresponds to the
  1604. // time period between now and the next message to be sent from the
  1605. // perfdhcp to a server.
  1606. TEST_F(TestControlTest, getCurrentTimeout) {
  1607. // Process the command line: set the rate for Discovers to 10,
  1608. // and set Renew rate to 0 (-f flag absent).
  1609. ASSERT_NO_THROW(processCmdLine("perfdhcp -4 -l lo -r 10 ::1"));
  1610. NakedTestControl tc;
  1611. // Make sure that the renew rate is 0.
  1612. ASSERT_EQ(0, CommandOptions::instance().getRenewRate());
  1613. // Simulate the case when we are already behind the due time for
  1614. // the next Discover to be sent.
  1615. tc.setRelativeDueTimes(-3);
  1616. // Expected timeout value is 0, which means that perfdhcp should
  1617. // not wait for server's response but rather send the next
  1618. // message to a server immediately.
  1619. EXPECT_EQ(0, tc.getCurrentTimeout());
  1620. // Now, let's do set the due time to a value in the future. The returned
  1621. // timeout value should be somewhere between now and this time in the
  1622. // future. The value of ten seconds ahead should be safe and guarantee
  1623. // that the returned timeout value is non-zero, even though there is a
  1624. // delay between setting the send_due_ value and invoking the function.
  1625. tc.setRelativeDueTimes(10);
  1626. uint32_t timeout = tc.getCurrentTimeout();
  1627. EXPECT_GT(timeout, 0);
  1628. EXPECT_LE(timeout, 10000000);
  1629. }
  1630. // This test verifies that the current timeout value for waiting for the
  1631. // server's responses is valid. In this case, we are simulating that perfdhcp
  1632. // sends Renew requests to the server, apart from the regular 4-way exchanges.
  1633. // The timeout value depends on both the due time to send next Solicit and the
  1634. // due time to send Renew - the timeout should be adjusted to the due time
  1635. // that occurs sooner.
  1636. TEST_F(TestControlTest, getCurrentTimeoutRenew) {
  1637. // Set the Solicit rate to 10 and the Renew rate 5.
  1638. ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l lo -r 10 -f 5 ::1"));
  1639. NakedTestControl tc;
  1640. // Make sure, that the Renew rate has been set to 5.
  1641. ASSERT_EQ(5, CommandOptions::instance().getRenewRate());
  1642. // The send_due_ is in the past, the renew_due_ is in the future.
  1643. tc.setRelativeDueTimes(-3, 3);
  1644. EXPECT_EQ(0, tc.getCurrentTimeout());
  1645. // Swap the due times from the previous check. The effect should be the
  1646. // same.
  1647. tc.setRelativeDueTimes(3, -3);
  1648. EXPECT_EQ(0, tc.getCurrentTimeout());
  1649. // Set both due times to the future. The renew due time is to occur
  1650. // sooner. The timeout should be a value between now and the
  1651. // renew due time.
  1652. tc.setRelativeDueTimes(10, 5);
  1653. EXPECT_GT(tc.getCurrentTimeout(), 0);
  1654. EXPECT_LE(tc.getCurrentTimeout(), 5000000);
  1655. // Repeat the same check, but swap the due times.
  1656. tc.setRelativeDueTimes(5, 10);
  1657. EXPECT_GT(tc.getCurrentTimeout(), 0);
  1658. EXPECT_LE(tc.getCurrentTimeout(), 5000000);
  1659. }
  1660. // This test verifies that the current timeout value for waiting for the
  1661. // server's responses is valid. In this case, we are simulating that perfdhcp
  1662. // sends Release requests to the server, apart from the regular 4-way exchanges.
  1663. TEST_F(TestControlTest, getCurrentTimeoutRelease) {
  1664. // Set the Solicit rate to 10 and the Release rate 5.
  1665. ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l lo -r 10 -F 5 ::1"));
  1666. NakedTestControl tc;
  1667. // Make sure, that the Release rate has been set to 5.
  1668. ASSERT_EQ(5, CommandOptions::instance().getReleaseRate());
  1669. // The send_due_ is in the past, the renew_due_ is in the future.
  1670. tc.setRelativeDueTimes(-3, 0, 3);
  1671. EXPECT_EQ(0, tc.getCurrentTimeout());
  1672. // Swap the due times from the previous check. The effect should be the
  1673. // same.
  1674. tc.setRelativeDueTimes(3, 0, -3);
  1675. EXPECT_EQ(0, tc.getCurrentTimeout());
  1676. // Set both due times to the future. The renew due time is to occur
  1677. // sooner. The timeout should be a value between now and the
  1678. // release due time.
  1679. tc.setRelativeDueTimes(10, 0, 5);
  1680. EXPECT_GT(tc.getCurrentTimeout(), 0);
  1681. EXPECT_LE(tc.getCurrentTimeout(), 5000000);
  1682. // Repeat the same check, but swap the due times.
  1683. tc.setRelativeDueTimes(5, 0, 10);
  1684. EXPECT_GT(tc.getCurrentTimeout(), 0);
  1685. EXPECT_LE(tc.getCurrentTimeout(), 5000000);
  1686. }
  1687. // This test verifies that the current timeout value for waiting for the
  1688. // server's responses is valid. In this case, we are simulating that perfdhcp
  1689. // sends both Renew and Release requests to the server, apart from the regular
  1690. // 4-way exchanges.
  1691. TEST_F(TestControlTest, getCurrentTimeoutRenewRelease) {
  1692. // Set the Solicit rate to 10 and, Renew rate to 5, Release rate to 3.
  1693. ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l lo -r 10 -f 5 -F 3 ::1"));
  1694. NakedTestControl tc;
  1695. // Make sure the Renew and Release rates has been set to a non-zero value.
  1696. ASSERT_EQ(5, CommandOptions::instance().getRenewRate());
  1697. ASSERT_EQ(3, CommandOptions::instance().getReleaseRate());
  1698. // If any of the due times is in the past, the timeout value should be 0,
  1699. // to indicate that the next message should be sent immediately.
  1700. tc.setRelativeDueTimes(-3, 3, 5);
  1701. EXPECT_EQ(0, tc.getCurrentTimeout());
  1702. tc.setRelativeDueTimes(-3, 5, 3);
  1703. EXPECT_EQ(0, tc.getCurrentTimeout());
  1704. tc.setRelativeDueTimes(3, -3, 5);
  1705. EXPECT_EQ(0, tc.getCurrentTimeout());
  1706. tc.setRelativeDueTimes(3, 2, -5);
  1707. EXPECT_EQ(0, tc.getCurrentTimeout());
  1708. tc.setRelativeDueTimes(-3, -2, -5);
  1709. EXPECT_EQ(0, tc.getCurrentTimeout());
  1710. // If due times are in the future, the timeout value should be aligned to
  1711. // the due time which occurs the soonest.
  1712. tc.setRelativeDueTimes(10, 9, 8);
  1713. EXPECT_GT(tc.getCurrentTimeout(), 0);
  1714. EXPECT_LE(tc.getCurrentTimeout(), 8000000);
  1715. tc.setRelativeDueTimes(10, 8, 9);
  1716. EXPECT_GT(tc.getCurrentTimeout(), 0);
  1717. EXPECT_LE(tc.getCurrentTimeout(), 8000000);
  1718. tc.setRelativeDueTimes(5, 8, 9);
  1719. EXPECT_GT(tc.getCurrentTimeout(), 0);
  1720. EXPECT_LE(tc.getCurrentTimeout(), 5000000);
  1721. }