LCOV - code coverage report
Current view: top level - vnsw/agent/services - dhcp_handler_base.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 440 0.0 %
Date: 2026-11-09 02:10:49 Functions: 0 25 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include <stdint.h>
       7             : #include "vr_defs.h"
       8             : #include "cmn/agent_cmn.h"
       9             : #include "pkt/pkt_init.h"
      10             : #include "oper/vn.h"
      11             : #include "services/dhcp_proto.h"
      12             : #include "services/dhcpv6_proto.h"
      13             : #include "services/services_types.h"
      14             : #include "services/services_init.h"
      15             : #include "services/dns_proto.h"
      16             : #include "services/services_sandesh.h"
      17             : #include "bind/bind_util.h"
      18             : 
      19             : #include <boost/assign/list_of.hpp>
      20             : #include <boost/scoped_array.hpp>
      21             : #include <bind/bind_util.h>
      22             : 
      23             : using namespace boost::assign;
      24             : 
      25           0 : DhcpHandlerBase::DhcpHandlerBase(Agent *agent, boost::shared_ptr<PktInfo> info,
      26           0 :                                  boost::asio::io_context &io)
      27           0 :         : ProtoHandler(agent, info, io), vm_itf_(NULL), vm_itf_index_(-1),
      28           0 :           option_(NULL), flags_(), dns_enable_(true),
      29           0 :           host_routes_level_(Invalid) {
      30           0 :     ipam_type_.ipam_dns_method = "none";
      31           0 : }
      32             : 
      33           0 : DhcpHandlerBase::~DhcpHandlerBase() {
      34           0 : }
      35             : 
      36             : // Add option taking no data (length = 0)
      37           0 : uint16_t DhcpHandlerBase::AddNoDataOption(uint32_t option, uint16_t opt_len) {
      38           0 :     option_->WriteData(option, 0, NULL, &opt_len);
      39           0 :     return opt_len;
      40             : }
      41             : 
      42             : // Add option taking a byte from input
      43           0 : uint16_t DhcpHandlerBase::AddByteOption(uint32_t option, uint16_t opt_len,
      44             :                                         const std::string &input) {
      45           0 :     std::stringstream value(input);
      46           0 :     uint32_t data = 0;
      47           0 :     value >> data;
      48           0 :     if (value.bad() || value.fail() || data > 0xFF) {
      49           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
      50             :                         input << "is invalid");
      51             :     } else {
      52           0 :         uint8_t byte = (uint8_t)data;
      53           0 :         option_->WriteData(option, 1, &byte, &opt_len);
      54             :     }
      55           0 :     return opt_len;
      56           0 : }
      57             : 
      58             : // Add option taking array of bytes from input
      59           0 : uint16_t DhcpHandlerBase::AddByteArrayOption(uint32_t option, uint16_t opt_len,
      60             :                                              const std::string &input) {
      61           0 :     option_->WriteData(option, 0, NULL, &opt_len);
      62           0 :     std::stringstream value(input);
      63           0 :     bool done = false;
      64           0 :     uint32_t byte = 0;
      65           0 :     value >> byte;
      66           0 :     while (!value.bad() && !value.fail() && byte <= 0xFF) {
      67           0 :         option_->AppendData(1, &byte, &opt_len);
      68           0 :         if (value.eof()) {
      69           0 :             done = true;
      70           0 :             break;
      71             :         }
      72           0 :         value >> byte;
      73             :     }
      74             : 
      75             :     // if atleast one byte is not added or in case of error, ignore this option
      76           0 :     if (!option_->GetLen() || !done) {
      77           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
      78             :                         input << "is invalid");
      79           0 :         return opt_len - option_->GetLen() - option_->GetFixedLen();
      80             :     }
      81             : 
      82           0 :     return opt_len;
      83           0 : }
      84             : 
      85             : // Add option taking a byte followed by a string, from input
      86           0 : uint16_t DhcpHandlerBase::AddByteStringOption(uint32_t option, uint16_t opt_len,
      87             :                                               const std::string &input) {
      88           0 :     std::stringstream value(input);
      89           0 :     uint32_t data = 0;
      90           0 :     value >> data;
      91           0 :     if (value.fail() || value.bad() || data > 0xFF) {
      92           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
      93             :                         input << "is invalid");
      94           0 :         return opt_len;
      95             :     }
      96             : 
      97           0 :     uint8_t byte = (uint8_t)data;
      98           0 :     std::string str;
      99           0 :     value >> str;
     100           0 :     option_->WriteData(option, 1, &byte, &opt_len);
     101           0 :     option_->AppendData(str.length(), str.c_str(), &opt_len);
     102             : 
     103           0 :     return opt_len;
     104           0 : }
     105             : 
     106             : // Add option taking a byte followed by one or more IPs, from input
     107           0 : uint16_t DhcpHandlerBase::AddByteIPOption(uint32_t option, uint16_t opt_len,
     108             :                                           const std::string &input) {
     109           0 :     std::stringstream value(input);
     110           0 :     uint32_t data = 0;
     111           0 :     value >> data;
     112           0 :     uint8_t byte = (uint8_t)data;
     113             : 
     114           0 :     if (value.fail() || value.bad() || data > 0xFF) {
     115           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
     116             :                         input << "is invalid");
     117           0 :         return opt_len;
     118             :     }
     119             : 
     120           0 :     option_->WriteData(option, 1, &byte, &opt_len);
     121           0 :     while (value.good()) {
     122           0 :         std::string ipstr;
     123           0 :         value >> ipstr;
     124           0 :         opt_len = AddIP(opt_len, ipstr);
     125           0 :     }
     126             : 
     127             :     // if atleast one IP is not added, ignore this option
     128           0 :     if (option_->GetLen() == 1) {
     129           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
     130             :                         input << "is invalid");
     131           0 :         return opt_len - option_->GetLen() - option_->GetFixedLen();
     132             :     }
     133             : 
     134           0 :     return opt_len;
     135           0 : }
     136             : 
     137             : // Add option taking string from input
     138           0 : uint16_t DhcpHandlerBase::AddStringOption(uint32_t option, uint16_t opt_len,
     139             :                                           const std::string &input) {
     140           0 :     option_->WriteData(option, input.length(), input.c_str(), &opt_len);
     141           0 :     return opt_len;
     142             : }
     143             : 
     144             : // Add option taking integer from input
     145           0 : uint16_t DhcpHandlerBase::AddIntegerOption(uint32_t option, uint16_t opt_len,
     146             :                                            const std::string &input) {
     147           0 :     std::stringstream value(input);
     148           0 :     uint32_t data = 0;
     149           0 :     value >> data;
     150           0 :     if (value.bad() || value.fail()) {
     151           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
     152             :                         input << "is invalid");
     153             :     } else {
     154           0 :         data = htonl(data);
     155           0 :         option_->WriteData(option, 4, &data, &opt_len);
     156             :     }
     157           0 :     return opt_len;
     158           0 : }
     159             : 
     160             : // Add option taking array of short from input
     161           0 : uint16_t DhcpHandlerBase::AddShortArrayOption(uint32_t option, uint16_t opt_len,
     162             :                                               const std::string &input,
     163             :                                               bool array) {
     164           0 :     option_->WriteData(option, 0, NULL, &opt_len);
     165           0 :     std::stringstream value(input);
     166           0 :     uint16_t data = 0;
     167           0 :     value >> data;
     168           0 :     while (!value.bad() && !value.fail()) {
     169           0 :         data = htons(data);
     170           0 :         option_->AppendData(2, &data, &opt_len);
     171           0 :         if (!array || value.eof()) break;
     172           0 :         value >> data;
     173             :     }
     174             : 
     175             :     // if atleast one short is not added, ignore this option
     176           0 :     if (!option_->GetLen() || !value.eof()) {
     177           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
     178             :                         input << "is invalid");
     179           0 :         return opt_len - option_->GetLen() - option_->GetFixedLen();
     180             :     }
     181             : 
     182           0 :     return opt_len;
     183           0 : }
     184             : 
     185             : // Check for exceptions in handling IP options
     186           0 : bool DhcpHandlerBase::IsValidIpOption(uint32_t option, const std::string &ipstr,
     187             :                                       bool is_v4) {
     188           0 :     boost::system::error_code ec;
     189           0 :     if (is_v4) {
     190           0 :         if (option == DHCP_OPTION_DNS) {
     191           0 :             return IsValidDnsOption(option, ipstr);
     192             :         } else {
     193           0 :             uint32_t ip = Ip4Address::from_string(ipstr, ec).to_ulong();
     194           0 :             if(!ec.value() && !ip) {
     195           0 :                 return false;
     196             :             }
     197             :         }
     198             : 
     199             :     } else {
     200           0 :         if (option == DHCPV6_OPTION_DNS_SERVERS) {
     201           0 :             return IsValidDnsOption(option, ipstr);
     202             :         } else {
     203           0 :             IpAddress ip = IpAddress::from_string(ipstr, ec);
     204           0 :             if (!ec.value() && ip.is_unspecified()) {
     205           0 :                 return false;
     206             :             }
     207             :         }
     208             :     }
     209             : 
     210           0 :     return true;
     211             : }
     212             : 
     213           0 : bool DhcpHandlerBase::IsValidDnsOption(uint32_t option,
     214             :                                        const std::string &ipstr) {
     215           0 :     boost::system::error_code ec;
     216           0 :     IpAddress ip = IpAddress::from_string(ipstr, ec);
     217           0 :     if (!ec.value()) {
     218             :         // when DNS server is present in DHCP option, disable vrouter
     219             :         // proxying for DNS requests from VMs.
     220           0 :         dns_enable_ = false;
     221           0 :         if (ip.is_unspecified()) {
     222             :             // Do not send the option when DNS servers have 0.0.0.0 or ::
     223             :             // Set option flag so that they are not added later
     224           0 :             set_flag(option);
     225           0 :             return false;
     226             :         }
     227             :     }
     228             : 
     229           0 :     return true;
     230             : }
     231             : 
     232             : // Add option taking number of Ipv4 addresses
     233           0 : uint16_t DhcpHandlerBase::AddIpv4Option(uint32_t option, uint16_t opt_len,
     234             :                                         const std::string &input,
     235             :                                         uint8_t min_count,
     236             :                                         uint8_t max_count,
     237             :                                         uint8_t multiples) {
     238           0 :     option_->WriteData(option, 0, NULL, &opt_len);
     239           0 :     std::stringstream value(input);
     240           0 :     while (value.good()) {
     241           0 :         std::string ipstr;
     242           0 :         value >> ipstr;
     243           0 :         if (!IsValidIpOption(option, ipstr, true)) {
     244           0 :             return opt_len - option_->GetLen() - option_->GetFixedLen();
     245             :         }
     246           0 :         opt_len = AddIP(opt_len, ipstr);
     247           0 :     }
     248             : 
     249           0 :     if (option == DHCP_OPTION_ROUTER) {
     250             :         // Add our gw as well
     251           0 :         if (!config_.gw_addr.is_unspecified()) {
     252           0 :             opt_len = AddIP(opt_len, config_.gw_addr.to_string());
     253             :         }
     254             :     }
     255             : 
     256             :     // check that atleast min_count IP addresses are added
     257           0 :     if (min_count && option_->GetLen() < min_count * 4) {
     258           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
     259             :                         input << "is invalid");
     260           0 :         return opt_len - option_->GetLen() - option_->GetFixedLen();
     261             :     }
     262             : 
     263             :     // if specified, check that we dont add more than max_count IP addresses
     264           0 :     if (max_count && option_->GetLen() > max_count * 4) {
     265           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
     266             :                         input << "is invalid");
     267           0 :         return opt_len - option_->GetLen() - option_->GetFixedLen();
     268             :     }
     269             : 
     270             :     // if specified, check that we add in multiples of IP addresses
     271           0 :     if (multiples && option_->GetLen() % (multiples * 4)) {
     272           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
     273             :                         input << "is invalid");
     274           0 :         return opt_len - option_->GetLen() - option_->GetFixedLen();
     275             :     }
     276             : 
     277           0 :     return opt_len;
     278           0 : }
     279             : 
     280             : // Add option taking number of Ipv6 addresses
     281           0 : uint16_t DhcpHandlerBase::AddIpv6Option(uint32_t option, uint16_t opt_len,
     282             :                                         const std::string &input, bool list) {
     283           0 :     option_->WriteData(option, 0, NULL, &opt_len);
     284           0 :     std::stringstream value(input);
     285           0 :     while (value.good()) {
     286           0 :         std::string ipstr;
     287           0 :         value >> ipstr;
     288           0 :         if (!IsValidIpOption(option, ipstr, false)) {
     289           0 :             return opt_len - option_->GetLen() - option_->GetFixedLen();
     290             :         }
     291           0 :         opt_len = AddIP(opt_len, ipstr);
     292           0 :         if (!list) break;
     293           0 :     }
     294             : 
     295             :     // check that atleast one IP address is added
     296           0 :     if (option_->GetLen() < 16) {
     297           0 :         DHCPV6_TRACE(Error, "Invalid DHCP option " << option << " for VM " <<
     298             :                      config_.ip_addr.to_string() << "; data missing");
     299           0 :         return opt_len - option_->GetLen() - option_->GetFixedLen();
     300             :     }
     301             : 
     302           0 :     return opt_len;
     303           0 : }
     304             : 
     305             : // Add option taking compressed name
     306           0 : uint16_t DhcpHandlerBase::AddCompressedNameOption(uint32_t option,
     307             :                                                   uint16_t opt_len,
     308             :                                                   const std::string &input,
     309             :                                                   bool list) {
     310           0 :     option_->WriteData(option, 0, NULL, &opt_len);
     311           0 :     std::stringstream value(input);
     312           0 :     while (value.good()) {
     313           0 :         std::string str;
     314           0 :         value >> str;
     315           0 :         if (str.size()) {
     316           0 :             opt_len = AddCompressedName(opt_len, str);
     317           0 :             if (!list) break;
     318             :         }
     319           0 :     }
     320             : 
     321           0 :     if (!option_->GetLen()) {
     322           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
     323             :                         input << "is invalid");
     324           0 :         return opt_len - option_->GetLen() - option_->GetFixedLen();
     325             :     }
     326             : 
     327           0 :     return opt_len;
     328           0 : }
     329             : 
     330             : // Add option taking a byte followed by a compressed name
     331           0 : uint16_t DhcpHandlerBase::AddByteCompressedNameOption(uint32_t option,
     332             :                                                       uint16_t opt_len,
     333             :                                                       const std::string &input) {
     334           0 :     option_->WriteData(option, 0, NULL, &opt_len);
     335             : 
     336           0 :     std::stringstream value(input);
     337           0 :     uint32_t data = 0;
     338           0 :     value >> data;
     339           0 :     if (value.bad() || value.fail() || data > 0xFF) {
     340           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
     341             :                         input << "is invalid");
     342           0 :         return opt_len - option_->GetLen() - option_->GetFixedLen();
     343             :     } else {
     344           0 :         uint8_t byte = (uint8_t)data;
     345           0 :         option_->WriteData(option, 1, &byte, &opt_len);
     346             :     }
     347             : 
     348           0 :     std::string str;
     349           0 :     value >> str;
     350           0 :     if (value.bad() || value.fail() || !str.size()) {
     351           0 :         DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
     352             :                         input << "is invalid");
     353           0 :         return opt_len - option_->GetLen() - option_->GetFixedLen();
     354             :     }
     355           0 :     return AddCompressedName(opt_len, str);
     356           0 : }
     357             : 
     358           0 : uint16_t DhcpHandlerBase::AddCompressedName(uint16_t opt_len,
     359             :                                             const std::string &input) {
     360           0 :     boost::scoped_array<uint8_t> name(new uint8_t[input.size() * 2 + 2]);
     361           0 :     uint16_t len = 0;
     362           0 :     BindUtil::AddName(name.get(), input, 0, 0, len);
     363           0 :     option_->AppendData(len, name.get(), &opt_len);
     364           0 :     return opt_len;
     365           0 : }
     366             : 
     367             : // Add an DNS server addresses from IPAM to the option
     368             : // Option code and len are added already; add only the addresses
     369           0 : uint16_t DhcpHandlerBase::AddDnsServers(uint16_t opt_len) {
     370           0 :     if (ipam_type_.ipam_dns_method == "default-dns-server" ||
     371           0 :         ipam_type_.ipam_dns_method == "virtual-dns-server" ||
     372           0 :         ipam_type_.ipam_dns_method == "none" ||
     373           0 :         ipam_type_.ipam_dns_method == "") {
     374           0 :         if (!config_.dns_addr.is_unspecified()) {
     375           0 :             opt_len = AddIP(opt_len, config_.dns_addr.to_string());
     376             :         }
     377           0 :     } else if (ipam_type_.ipam_dns_method == "tenant-dns-server") {
     378           0 :         for (unsigned int i = 0; i < ipam_type_.ipam_dns_server.
     379           0 :              tenant_dns_server_address.ip_address.size(); ++i) {
     380           0 :             opt_len = AddIP(opt_len, ipam_type_.ipam_dns_server.
     381           0 :                                      tenant_dns_server_address.ip_address[i]);
     382             :         }
     383             :     }
     384           0 :     return opt_len;
     385             : }
     386             : 
     387             : // Read the list of <subnet/plen, gw> from input and store them
     388             : // for later processing in AddClasslessRouteOption
     389           0 : void DhcpHandlerBase::ReadClasslessRoute(uint32_t option, uint16_t opt_len,
     390             :                                          const std::string &input) {
     391           0 :     std::stringstream value(input);
     392           0 :     while (value.good()) {
     393           0 :         std::string snetstr;
     394           0 :         value >> snetstr;
     395           0 :         OperDhcpOptions::HostRoute host_route;
     396           0 :         boost::system::error_code ec = Ip4PrefixParse(snetstr, &host_route.prefix_,
     397             :                                                       (int *)&host_route.plen_);
     398           0 :         if (ec || host_route.plen_ > 32 || !value.good()) {
     399           0 :             DHCP_BASE_TRACE("Invalid Classless route DHCP option -"
     400             :                             "has to be list of <subnet/plen gw>");
     401           0 :             break;
     402             :         }
     403             : 
     404           0 :         value >> snetstr;
     405           0 :         host_route.gw_ = Ip4Address::from_string(snetstr, ec);
     406           0 :         if (ec) {
     407           0 :             host_route.gw_ = Ip4Address();
     408             :         }
     409             : 
     410           0 :         host_routes_.push_back(host_route);
     411           0 :     }
     412           0 : }
     413             : 
     414             : // Add host route options coming via config. Config priority is
     415             : // 1) options at VM interface level (host routes specifically set)
     416             : // 2) options at VM interface level (classless routes from --extra-dhcp-opts)
     417             : // 3) options at subnet level (host routes at subnet level - neutron config)
     418             : // 4) options at subnet level (classless routes from dhcp options)
     419             : // 5) options at IPAM level (host routes from IPAM)
     420             : // 6) options at IPAM level (classless routes from IPAM dhcp options)
     421             : // Add the options defined at the highest level in priority
     422           0 : uint16_t DhcpHandlerBase::AddClasslessRouteOption(uint16_t opt_len) {
     423           0 :     std::vector<OperDhcpOptions::HostRoute> host_routes;
     424             :     do {
     425             :         // Port specific host route options
     426             :         // TODO: should we remove host routes at port level from schema ?
     427           0 :         if (vm_itf_->oper_dhcp_options().are_host_routes_set()) {
     428           0 :             host_routes = vm_itf_->oper_dhcp_options().host_routes();
     429           0 :             break;
     430             :         }
     431             :         // Host routes from port specific DHCP options (neutron configuration)
     432           0 :         if (host_routes_level_ == InterfaceLevel && host_routes_.size()) {
     433           0 :             host_routes.swap(host_routes_);
     434           0 :             break;
     435             :         }
     436             : 
     437           0 :         if (vm_itf_->vn()) {
     438           0 :             Ip4Address ip = config_.ip_addr.to_v4();
     439           0 :             const std::vector<VnIpam> &vn_ipam = vm_itf_->vn()->GetVnIpam();
     440             :             uint32_t index;
     441           0 :             for (index = 0; index < vn_ipam.size(); ++index) {
     442           0 :                 if (vn_ipam[index].IsSubnetMember(ip)) {
     443           0 :                     break;
     444             :                 }
     445             :             }
     446           0 :             if (index < vn_ipam.size()) {
     447             :                 // Subnet level host route options
     448             :                 // Preference to host routes at subnet (neutron configuration)
     449           0 :                 if (vn_ipam[index].oper_dhcp_options.are_host_routes_set()) {
     450           0 :                     host_routes = vn_ipam[index].oper_dhcp_options.host_routes();
     451           0 :                     break;
     452             :                 }
     453             :                 // Host route options from subnet level DHCP options
     454           0 :                 if (host_routes_level_ == SubnetLevel && host_routes_.size()) {
     455           0 :                     host_routes.swap(host_routes_);
     456           0 :                     break;
     457             :                 }
     458             :             }
     459             : 
     460             :             // TODO: should remove host routes at VN level from schema ?
     461           0 :             vm_itf_->vn()->GetVnHostRoutes(ipam_name_, &host_routes);
     462           0 :             if (host_routes.size() > 0)
     463           0 :                 break;
     464             :         }
     465             : 
     466             :         // IPAM level host route options
     467           0 :         OperDhcpOptions oper_dhcp_options;
     468           0 :         oper_dhcp_options.update_host_routes(ipam_type_.host_routes.route);
     469           0 :         host_routes = oper_dhcp_options.host_routes();
     470             : 
     471             :         // Host route options from IPAM level DHCP options
     472           0 :         if (!host_routes.size() && host_routes_.size()) {
     473           0 :             host_routes.swap(host_routes_);
     474           0 :             break;
     475             :         }
     476           0 :     } while (false);
     477             : 
     478           0 :     if (host_routes.size()) {
     479           0 :         option_->SetCode(DHCP_OPTION_CLASSLESS_ROUTE);
     480           0 :         uint8_t *ptr = option_->GetData();
     481           0 :         uint8_t len = 0;
     482           0 :         for (uint32_t i = 0; i < host_routes.size(); ++i) {
     483           0 :             uint32_t prefix = host_routes[i].prefix_.to_ulong();
     484           0 :             uint32_t plen = host_routes[i].plen_;
     485           0 :             uint32_t gw = host_routes[i].gw_.to_ulong();
     486           0 :             *ptr++ = plen;
     487           0 :             len++;
     488           0 :             for (unsigned int j = 0; plen && j <= (plen - 1) / 8; ++j) {
     489           0 :                 *ptr++ = (prefix >> 8 * (3 - j)) & 0xFF;
     490           0 :                 len++;
     491             :             }
     492             :             // if GW is not specified, set it to subnet's GW
     493           0 :             if (gw)
     494           0 :                 *(uint32_t *)ptr = htonl(gw);
     495             :             else
     496           0 :                 *(uint32_t *)ptr = htonl(config_.gw_addr.to_v4().to_ulong());
     497           0 :             ptr += sizeof(uint32_t);
     498           0 :             len += sizeof(uint32_t);
     499             :         }
     500           0 :         option_->SetLen(len);
     501           0 :         opt_len += 2 + len;
     502           0 :         set_flag(DHCP_OPTION_CLASSLESS_ROUTE);
     503             :     }
     504           0 :     return opt_len;
     505           0 : }
     506             : 
     507           0 : uint16_t DhcpHandlerBase::AddDhcpOptions(
     508             :                         uint16_t opt_len,
     509             :                         std::vector<autogen::DhcpOptionType> &options,
     510             :                         DhcpOptionLevel level) {
     511           0 :     for (unsigned int i = 0; i < options.size(); ++i) {
     512             :         // get the option code
     513           0 :         uint32_t option = OptionCode(options[i].dhcp_option_name);
     514           0 :         if (!option) {
     515           0 :             DHCP_BASE_TRACE("Invalid DHCP option " <<
     516             :                             options[i].dhcp_option_name);
     517           0 :             continue;
     518           0 :         }
     519             : 
     520             :         // if option is already set in the response (from higher level), ignore
     521           0 :         if (is_flag_set(option))
     522           0 :             continue;
     523             : 
     524           0 :         uint16_t old_opt_len = opt_len;
     525           0 :         DhcpOptionCategory category = OptionCategory(option);
     526           0 :         option_->SetNextOptionPtr(opt_len);
     527             : 
     528             :         // if dhcp_option_value_bytes is set, use that for supported categories
     529           0 :         std::string &opt_value = options[i].dhcp_option_value;
     530           0 :         if (!options[i].dhcp_option_value_bytes.empty() &&
     531           0 :             CanOverrideWithBytes(category)) {
     532           0 :             category = ByteArray;
     533           0 :             opt_value = options[i].dhcp_option_value_bytes;
     534             :         }
     535             : 
     536           0 :         switch(category) {
     537           0 :             case None:
     538           0 :                 break;
     539             : 
     540           0 :             case NoData:
     541           0 :                 opt_len = AddNoDataOption(option, opt_len);
     542           0 :                 break;
     543             : 
     544           0 :             case Bool:
     545             :             case Byte:
     546           0 :                 opt_len = AddByteOption(option, opt_len,
     547           0 :                                         options[i].dhcp_option_value);
     548           0 :                 break;
     549             : 
     550           0 :             case ByteArray:
     551           0 :                 opt_len = AddByteArrayOption(option, opt_len, opt_value);
     552           0 :                 break;
     553             : 
     554           0 :             case ByteString:
     555           0 :                 opt_len = AddByteStringOption(option, opt_len,
     556           0 :                                               options[i].dhcp_option_value);
     557           0 :                 break;
     558             : 
     559           0 :             case ByteOneIPPlus:
     560           0 :                 opt_len = AddByteIPOption(option, opt_len,
     561           0 :                                           options[i].dhcp_option_value);
     562           0 :                 break;
     563             : 
     564           0 :             case String:
     565           0 :                 opt_len = AddStringOption(option, opt_len,
     566           0 :                                           options[i].dhcp_option_value);
     567           0 :                 break;
     568             : 
     569           0 :             case Int32bit:
     570             :             case Uint32bit:
     571           0 :                 if (option == DHCP_OPTION_IP_LEASE_TIME) {
     572           0 :                     set_flag(DHCP_OPTION_IP_LEASE_TIME);
     573             :                 }
     574           0 :                 opt_len = AddIntegerOption(option, opt_len,
     575           0 :                                            options[i].dhcp_option_value);
     576           0 :                 break;
     577             : 
     578           0 :             case Uint16bit:
     579           0 :                 opt_len = AddShortArrayOption(option, opt_len,
     580           0 :                                               options[i].dhcp_option_value,
     581             :                                               false);
     582           0 :                 break;
     583             : 
     584           0 :             case Uint16bitArray:
     585           0 :                 opt_len = AddShortArrayOption(option, opt_len,
     586           0 :                                               options[i].dhcp_option_value,
     587             :                                               true);
     588           0 :                 break;
     589             : 
     590           0 :             case OneIPv4:
     591           0 :                 opt_len = AddIpv4Option(option, opt_len,
     592           0 :                                         options[i].dhcp_option_value, 1, 1, 0);
     593           0 :                 break;
     594             : 
     595           0 :             case ZeroIPv4Plus:
     596           0 :                 opt_len = AddIpv4Option(option, opt_len,
     597           0 :                                         options[i].dhcp_option_value, 0, 0, 0);
     598           0 :                 break;
     599             : 
     600           0 :             case OneIPv4Plus:
     601           0 :                 if (option == DHCP_OPTION_ROUTER) {
     602             :                     // Router option is added later
     603           0 :                     routers_ = options[i].dhcp_option_value;
     604           0 :                     set_flag(DHCP_OPTION_ROUTER);
     605             :                 } else {
     606           0 :                     opt_len = AddIpv4Option(option, opt_len,
     607           0 :                                             options[i].dhcp_option_value,
     608             :                                             1, 0, 0);
     609             :                 }
     610           0 :                 break;
     611             : 
     612           0 :             case TwoIPv4Plus:
     613           0 :                 opt_len = AddIpv4Option(option, opt_len,
     614           0 :                                         options[i].dhcp_option_value, 2, 0, 2);
     615           0 :                 break;
     616             : 
     617           0 :             case OneIPv6:
     618           0 :                 opt_len = AddIpv6Option(option, opt_len,
     619           0 :                                         options[i].dhcp_option_value,
     620             :                                         false);
     621           0 :                 break;
     622             : 
     623           0 :             case OneIPv6Plus:
     624           0 :                 opt_len = AddIpv6Option(option, opt_len,
     625           0 :                                         options[i].dhcp_option_value,
     626             :                                         true);
     627           0 :                 break;
     628             : 
     629           0 :             case ClasslessRoute:
     630           0 :                 ReadClasslessRoute(option, opt_len,
     631           0 :                                    options[i].dhcp_option_value);
     632           0 :                 if (host_routes_.size()) {
     633             :                     // set flag & level for classless route so that we dont
     634             :                     // update these at other level (subnet or ipam)
     635           0 :                     set_flag(DHCP_OPTION_CLASSLESS_ROUTE);
     636           0 :                     host_routes_level_ = level;
     637             :                 }
     638           0 :                 break;
     639             : 
     640           0 :             case NameCompression:
     641           0 :                 opt_len = AddCompressedNameOption(option, opt_len,
     642           0 :                                                   options[i].dhcp_option_value,
     643             :                                                   false);
     644           0 :                 break;
     645             : 
     646           0 :             case NameCompressionArray:
     647           0 :                 opt_len = AddCompressedNameOption(option, opt_len,
     648           0 :                                                   options[i].dhcp_option_value,
     649             :                                                   true);
     650           0 :                 break;
     651             : 
     652           0 :             case ByteNameCompression:
     653           0 :                 opt_len = AddByteCompressedNameOption(option, opt_len,
     654           0 :                                                   options[i].dhcp_option_value);
     655           0 :                 break;
     656             : 
     657           0 :             default:
     658           0 :                 DHCP_BASE_TRACE("Invalid DHCP option " <<
     659             :                                 options[i].dhcp_option_name);
     660           0 :                 break;
     661             :         }
     662             : 
     663             :         // store siaddr for tftp server name to apply it later
     664           0 :         if (option == DHCP_OPTION_TFTP_SERVER_NAME) {
     665           0 :             boost::system::error_code ec;
     666             :             Ip4Address siaddr =
     667           0 :             Ip4Address::from_string(options[i].dhcp_option_value, ec);
     668           0 :             if (ec.value() == 0)
     669           0 :                 siaddr_tftp_ = htonl(siaddr.to_ulong());
     670             :         }
     671             : 
     672           0 :         if (opt_len != old_opt_len)
     673           0 :             set_flag(option);
     674             :     }
     675             : 
     676           0 :     return opt_len;
     677             : }
     678             : 
     679             : // Add the option defined at the highest level in priority
     680             : // Take all options defined at VM interface level, take those from subnet which
     681             : // are not configured at interface, then take those from ipam which are not
     682             : // configured at interface or subnet.
     683           0 : uint16_t DhcpHandlerBase::AddConfigDhcpOptions(uint16_t opt_len, bool is_v6) {
     684           0 :     std::vector<autogen::DhcpOptionType> options;
     685           0 :     if (vm_itf_->GetInterfaceDhcpOptions(&options))
     686           0 :         opt_len = AddDhcpOptions(opt_len, options, InterfaceLevel);
     687             : 
     688           0 :     if (vm_itf_->GetSubnetDhcpOptions(&options, is_v6))
     689           0 :         opt_len = AddDhcpOptions(opt_len, options, SubnetLevel);
     690             : 
     691           0 :     if (vm_itf_->GetIpamDhcpOptions(&options, is_v6))
     692           0 :         opt_len = AddDhcpOptions(opt_len, options, IpamLevel);
     693             : 
     694           0 :     return opt_len;
     695           0 : }
     696             : 
     697           0 : void DhcpHandlerBase::FindDomainName(const IpAddress &vm_addr) {
     698           0 :     if (config_.lease_time != (uint32_t) -1 ||
     699           0 :         config_.valid_time != (uint32_t) -1)
     700           0 :         return;
     701             : 
     702           0 :     if (!vm_itf_->vn() ||
     703           0 :         !vm_itf_->vn()->GetIpamData(vm_addr, &ipam_name_, &ipam_type_)) {
     704           0 :         DHCP_BASE_TRACE("Ipam data not found");
     705           0 :         return;
     706             :     }
     707             : 
     708           0 :     if (ipam_type_.ipam_dns_method != "virtual-dns-server" ||
     709           0 :         !agent()->domain_config_table()->GetVDns(ipam_type_.ipam_dns_server.
     710           0 :                                                  virtual_dns_server_name,
     711             :                                                  &vdns_type_))
     712           0 :         return;
     713             : 
     714           0 :     if (config_.domain_name_.size() &&
     715           0 :         config_.domain_name_ != vdns_type_.domain_name) {
     716           0 :         DHCP_BASE_TRACE("Client domain " << config_.domain_name_ <<
     717             :                         " doesnt match with configured domain " <<
     718             :                         vdns_type_.domain_name);
     719             :     }
     720             :     std::size_t pos;
     721           0 :     if (config_.client_name_.size() &&
     722           0 :         ((pos = config_.client_name_.find('.', 0)) != std::string::npos) &&
     723           0 :         (config_.client_name_.substr(pos + 1) != vdns_type_.domain_name)) {
     724           0 :         DHCP_BASE_TRACE("Client domain doesnt match with configured domain "
     725             :                         << vdns_type_.domain_name << "; Client name = "
     726             :                         << config_.client_name_);
     727           0 :         config_.client_name_.replace(config_.client_name_.begin() + pos + 1,
     728           0 :                                      config_.client_name_.end(),
     729           0 :                                      vdns_type_.domain_name);
     730             :     }
     731             : 
     732           0 :     config_.domain_name_ = vdns_type_.domain_name;
     733             : }
     734             : 
     735           0 : bool DhcpHandlerBase::CanOverrideWithBytes(DhcpOptionCategory category) {
     736           0 :     if (category == ByteArray ||
     737           0 :         category == ByteString ||
     738           0 :         category == String ||
     739           0 :         category == NameCompression ||
     740           0 :         category == NameCompressionArray ||
     741             :         category == ByteNameCompression)
     742           0 :         return true;
     743             : 
     744           0 :     return false;
     745             : }

Generated by: LCOV version 1.14