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

Generated by: LCOV version 1.14