#include <dhcp/option.h>
#include <cfgrpt/config_report.h>
#include <util/encode/hex.h>
+#include <asiolink/io_error.h>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
addr_unique_ = false;
mac_list_file_.clear();
mac_list_.clear();
+ giaddr_list_file_.clear();
+ giaddr_list_.clear();
+ multi_subnet_ = false;
num_request_.clear();
exit_wait_time_ = 0;
period_ = 0;
// they will be tuned and validated elsewhere
while((opt = getopt_long(argc, argv,
"huv46A:r:t:R:b:n:p:d:D:l:P:a:L:N:M:s:iBc1"
- "T:X:O:o:E:S:I:x:W:w:e:f:F:g:",
+ "J:T:X:O:o:E:S:I:x:W:w:e:f:F:g:",
long_options, NULL)) != -1) {
stream << " -" << static_cast<char>(opt);
if (optarg) {
" positive integer");
break;
+ case 'J':
+ giaddr_list_file_ = std::string(optarg);
+ loadGiaddr();
+ break;
+
case 'l':
localname_ = std::string(optarg);
initIsInterface();
return ui;
}
+bool CommandOptions::validateIP(const std::string& line) {
+ try {
+ asiolink::IOAddress ip_address_ = isc::asiolink::IOAddress(line);
+ // let's silence not used warning
+ (void) ip_address_;
+ } catch (const isc::asiolink::IOError& e) {
+ return (true);
+ }
+ giaddr_list_.push_back(line);
+ multi_subnet_ = true;
+ return (false);
+}
+
+void CommandOptions::loadGiaddr() {
+ std::string line;
+ std::ifstream infile(giaddr_list_file_.c_str());
+ size_t cnt = 0;
+ while (std::getline(infile, line)) {
+ cnt++;
+ stringstream tmp;
+ tmp << "invalid address in line: "<< cnt;
+ check(validateIP(line), tmp.str());
+ }
+}
+
void CommandOptions::loadMacs() {
std::string line;
std::ifstream infile(mac_list_file_.c_str());
" whether -6 is given.\n"
"-I<ip-offset>: Offset of the (DHCPv4) IP address in the requested-IP\n"
" option / (DHCPv6) IA_NA option in the (second/request) template.\n"
+ "-J<giaddr-list-file>: Text file that include multiple addresses.\n"
+ " If provided perfdhcp will choose randomly one of addresses for each\n"
+ " exchange.\n"
"-l<local-addr|interface>: For DHCPv4 operation, specify the local\n"
" hostname/address to use when communicating with the server. By\n"
" default, the interface address through which traffic would\n"
/// \return server name.
std::string getServerName() const { return server_name_; }
+ /// \brief Returns giaddr file location.
+ ///
+ /// \return giaddr list file location.
+ std::string getGiaddrListFile() const { return giaddr_list_file_; }
+
+ /// \brief Returns list of giaddr addresses.
+ ///
+ /// \return list of giaddr.
+ std::vector<std::string> getGiaddrList() const { return giaddr_list_; }
+
+ /// \brief Returns random giaddr.
+ ///
+ /// \return single string containing giaddr.
+ std::string getRandGiaddr() { return giaddr_list_[rand() % giaddr_list_.size()];}
+
+ /// \brief Check if multi subnet mode is enabled
+ ///
+ /// \return true if multisubnet mode is enabled.
+ bool checkMultiSubnet() { return multi_subnet_; }
/// \brief Find if diagnostic flag has been set.
///
/// mac_list_ vector.
bool decodeMacString(const std::string& line);
+ /// \brief Opens the text file containgin list of addresses (one per line).
+ void loadGiaddr();
+
+ /// \brief Checks if loaded giaddr from text file are correct,
+ /// adds them to giaddr_list_.
+ ///
+ /// \return true if address is incorrect
+ bool validateIP(const std::string& line);
+
/// IP protocol version to be used, expected values are:
/// 4 for IPv4 and 6 for IPv6, default value 0 means "not set".
uint8_t ipversion_;
/// List of MAC addresses loaded from a file.
std::vector<std::vector<uint8_t> > mac_list_;
+ std::string giaddr_list_file_;
+
+ std::vector<std::string> giaddr_list_;
+
+ bool multi_subnet_;
/// Offset of transaction id in template files. First vector
/// element points to offset for DISCOVER/SOLICIT messages,
/// second element points to transaction id offset for
OptionPtr opt_parameter_list =
Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST);
pkt4->addOption(opt_parameter_list);
- // Set client's and server's ports as well as server's address,
- // and local (relay) address.
+ // Set client's and server's ports as well as server's address
setDefaults4(pkt4);
-
+ // Override relay address
+ pkt4->setGiaddr(offer_pkt4->getGiaddr());
// Add any extra options that user may have specified.
addExtraOpts(pkt4);
pkt->setRemoteAddr(IOAddress(options_.getServerName()));
// Set local address.
pkt->setLocalAddr(IOAddress(socket_.addr_));
- // Set relay (GIADDR) address to local address.
- pkt->setGiaddr(IOAddress(socket_.addr_));
+ // Set relay (GIADDR) address to local address if multiple
+ // subnet mode is not enabled
+ if (!options_.checkMultiSubnet()) {
+ pkt->setGiaddr(IOAddress(socket_.addr_));
+ } else {
+ pkt->setGiaddr(IOAddress(options_.getRandGiaddr()));
+ }
// Pretend that we have one relay (which is us).
pkt->setHops(1);
}
EXPECT_EQ(4, m.size());
}
+TEST_F(CommandOptionsTest, LoadGiaddrFromFile) {
+ CommandOptions opt;
+ std::string giaddr_list_full_path = getFullPath("giaddr");
+ std::ostringstream cmd;
+ cmd << "perfdhcp -J " << giaddr_list_full_path << " abc";
+ EXPECT_NO_THROW(process(opt, cmd.str()));
+ EXPECT_EQ(giaddr_list_full_path, opt.getGiaddrListFile());
+ EXPECT_TRUE(opt.checkMultiSubnet());
+ EXPECT_EQ(5, opt.getGiaddrList().size());
+}
+
TEST_F(CommandOptionsTest, LoadMacsFromFileNegativeCases) {
CommandOptions opt;
// Negative test cases
EXTRA_DIST = discover-example.hex request4-example.hex
EXTRA_DIST += solicit-example.hex request6-example.hex
-EXTRA_DIST += mac-list.txt
+EXTRA_DIST += mac-list.txt giaddr
--- /dev/null
+100.95.0.1
+20.86.12.1
+101.64.4.1
+1.86.0.1
+92.86.238.1