LCOV - code coverage report
Current view: top level - vnsw/agent/services - dhcp_handler.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 574 0.0 %
Date: 2026-06-08 02:02:55 Functions: 0 29 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 "base/os.h"
       7             : #include "base/address_util.h"
       8             : #include "vr_defs.h"
       9             : #include "cmn/agent_cmn.h"
      10             : #include "oper/route_common.h"
      11             : #include "oper/vn.h"
      12             : #include "pkt/pkt_init.h"
      13             : #include "services/dhcp_proto.h"
      14             : #include "services/dhcp_lease_db.h"
      15             : #include "services/services_types.h"
      16             : #include "services/services_init.h"
      17             : #include "services/dns_proto.h"
      18             : #include "services/services_sandesh.h"
      19             : #include "bind/bind_util.h"
      20             : #include "bind/xmpp_dns_agent.h"
      21             : 
      22             : #include <boost/assign/list_of.hpp>
      23             : #include <bind/bind_util.h>
      24             : 
      25             : using namespace boost::assign;
      26             : Dhcpv4NameCodeMap g_dhcpv4_namecode_map =
      27             :     map_list_of<std::string, uint32_t>
      28             :         ("subnet-mask", DHCP_OPTION_SUBNET_MASK)
      29             :         ("time-offset", DHCP_OPTION_TIME_OFFSET)
      30             :         ("routers", DHCP_OPTION_ROUTER)
      31             :         ("time-servers", DHCP_OPTION_TIME_SERVER)
      32             :         ("name-servers", DHCP_OPTION_NAME_SERVER)
      33             :         ("domain-name-servers", DHCP_OPTION_DNS)
      34             :         ("log-servers", DHCP_OPTION_LOG_SERVER)
      35             :         ("quote-servers", DHCP_OPTION_QUOTE_SERVER)
      36             :         ("lpr-servers", DHCP_OPTION_LPR_SERVER)
      37             :         ("impress-servers", DHCP_OPTION_IMPRESS_SERVER)
      38             :         ("resource-location-servers", DHCP_OPTION_RESOURCE_LOCATION_SERVER)
      39             :         ("host-name", DHCP_OPTION_HOST_NAME)
      40             :         ("boot-size", DHCP_OPTION_BOOT_FILE_SIZE)
      41             :         ("merit-dump", DHCP_OPTION_MERIT_DUMP_FILE)
      42             :         ("domain-name", DHCP_OPTION_DOMAIN_NAME)
      43             :         ("swap-server", DHCP_OPTION_SWAP_SERVER)
      44             :         ("root-path", DHCP_OPTION_ROOT_PATH)
      45             :         ("extension-path", DHCP_OPTION_EXTENSION_PATH)
      46             :         ("ip-forwarding", DHCP_OPTION_IP_FWD_CONTROL)
      47             :         ("non-local-source-routing", DHCP_OPTION_NL_SRC_ROUTING)
      48             :         ("policy-filter", DHCP_OPTION_POLICY_FILTER)
      49             :         ("max-dgram-reassembly", DHCP_OPTION_MAX_DG_REASSEMBLY_SIZE)
      50             :         ("default-ip-ttl", DHCP_OPTION_DEFAULT_IP_TTL)
      51             :         ("path-mtu-aging-timeout", DHCP_OPTION_PATH_MTU_AGING_TIMEOUT)
      52             :         ("path-mtu-plateau-table", DHCP_OPTION_PATH_MTU_PLATEAU_TABLE)
      53             :         ("interface-mtu", DHCP_OPTION_INTERFACE_MTU)
      54             :         ("all-subnets-local", DHCP_OPTION_ALL_SUBNETS_LOCAL)
      55             :         ("broadcast-address", DHCP_OPTION_BCAST_ADDRESS)
      56             :         ("perform-mask-discovery", DHCP_OPTION_PERFORM_MASK_DISCOVERY)
      57             :         ("mask-supplier", DHCP_OPTION_MASK_SUPPLIER)
      58             :         ("router-discovery", DHCP_OPTION_PERFORM_ROUTER_DISCOVERY)
      59             :         ("router-solicitation-address", DHCP_OPTION_ROUTER_SOLICIT_ADDRESS)
      60             :         ("static-routes", DHCP_OPTION_STATIC_ROUTING_TABLE)
      61             :         ("trailer-encapsulation", DHCP_OPTION_TRAILER_ENCAP)
      62             :         ("arp-cache-timeout", DHCP_OPTION_ARP_CACHE_TIMEOUT)
      63             :         ("ieee802-3-encapsulation", DHCP_OPTION_ETHERNET_ENCAP)
      64             :         ("default-tcp-ttl", DHCP_OPTION_DEFAULT_TCP_TTL)
      65             :         ("tcp-keepalive-interval", DHCP_OPTION_TCP_KEEPALIVE_INTERVAL)
      66             :         ("tcp-keepalive-garbage", DHCP_OPTION_TCP_KEEPALIVE_GARBAGE)
      67             :         ("nis-domain", DHCP_OPTION_NIS_DOMAIN)
      68             :         ("nis-servers", DHCP_OPTION_NIS_SERVERS)
      69             :         ("ntp-servers", DHCP_OPTION_NTP_SERVERS)
      70             :         ("vendor-encapsulated-options", DHCP_OPTION_VENDOR_SPECIFIC_INFO)
      71             :         ("netbios-name-servers", DHCP_OPTION_NETBIOS_OVER_TCP_NS)
      72             :         ("netbios-dd-server", DHCP_OPTION_NETBIOS_OVER_TCP_DG_DS)
      73             :         ("netbios-node-type", DHCP_OPTION_NETBIOS_OVER_TCP_NODE_TYPE)
      74             :         ("netbios-scope", DHCP_OPTION_NETBIOS_OVER_TCP_SCOPE)
      75             :         ("font-servers", DHCP_OPTION_XWINDOW_FONT_SERVER)
      76             :         ("x-display-manager", DHCP_OPTION_XWINDOW_SYSTEM_DISP_MGR)
      77             :         ("dhcp-requested-address", DHCP_OPTION_REQ_IP_ADDRESS)
      78             :         ("dhcp-lease-time", DHCP_OPTION_IP_LEASE_TIME)
      79             :         ("dhcp-option-overload", DHCP_OPTION_OVERLOAD)
      80             :         ("dhcp-message-type", DHCP_OPTION_MSG_TYPE)
      81             :         ("dhcp-server-identifier", DHCP_OPTION_SERVER_IDENTIFIER)
      82             :         ("dhcp-parameter-request-list", DHCP_OPTION_PARAMETER_REQUEST_LIST)
      83             :         ("dhcp-message", DHCP_OPTION_MESSAGE)
      84             :         ("dhcp-max-message-size", DHCP_OPTION_MAX_DHCP_MSG_SIZE)
      85             :         ("dhcp-renewal-time", DHCP_OPTION_RENEW_TIME_VALUE)
      86             :         ("dhcp-rebinding-time", DHCP_OPTION_REBIND_TIME_VALUE)
      87             :         ("class-id", DHCP_OPTION_CLASS_ID)
      88             :         ("dhcp-client-identifier", DHCP_OPTION_CLIENT_ID)
      89             :         ("nwip-domain", DHCP_OPTION_NETWARE_IP_DOMAIN_NAME)
      90             :         ("nwip-suboptions", DHCP_OPTION_NETWARE_IP_INFO)
      91             :         ("nisplus-domain", DHCP_OPTION_NIS_PLUS_DOMAIN)
      92             :         ("nisplus-servers", DHCP_OPTION_NIS_PLUS_SERVERS)
      93             :         ("tftp-server-name", DHCP_OPTION_TFTP_SERVER_NAME)
      94             :         ("bootfile-name", DHCP_OPTION_BOOTFILE_NAME)
      95             :         ("mobile-ip-home-agent", DHCP_OPTION_MOBILE_IP_HA)
      96             :         ("smtp-server", DHCP_OPTION_SMTP_SERVER)
      97             :         ("pop-server", DHCP_OPTION_POP_SERVER)
      98             :         ("nntp-server", DHCP_OPTION_NNTP_SERVER)
      99             :         ("www-server", DHCP_OPTION_DEFAULT_WWW_SERVER)
     100             :         ("finger-server", DHCP_OPTION_DEFAULT_FINGER_SERVER)
     101             :         ("irc-server", DHCP_OPTION_DEFAULT_IRC_SERVER)
     102             :         ("streettalk-server", DHCP_OPTION_STREETTALK_SERVER)
     103             :         ("streettalk-directory-assistance-server", DHCP_OPTION_STREETTALK_DA_SERVER)
     104             :         ("user-class", DHCP_OPTION_USER_CLASS_INFO)
     105             :         ("slp-directory-agent", DHCP_OPTION_SLP_DIRECTORY_AGENT)
     106             :         ("slp-service-scope", DHCP_OPTION_SLP_SERVICE_SCOPE)
     107             :         ("rapid-commit", DHCP_OPTION_RAPID_COMMIT)
     108             :         ("client-fqdn", DHCP_OPTION_CLIENT_FQDN)
     109             :         ("storage-ns", DHCP_OPTION_STORAGE_NS)
     110             :         // option 82 not required
     111             :         ("nds-servers", DHCP_OPTION_NDS_SERVERS)
     112             :         ("nds-tree-name", DHCP_OPTION_NDS_TREE_NAME)
     113             :         ("nds-context", DHCP_OPTION_NDS_CONTEXT)
     114             :         ("bcms-controller-names", DHCP_OPTION_BCMCS_DN_LIST)
     115             :         ("bcms-controller-address", DHCP_OPTION_BCMCS_ADDR_LIST)
     116             :         ("dhcp-auth", DHCP_OPTION_AUTH)
     117             :         ("dhcp-client-last-time", DHCP_OPTION_CLIENT_LAST_XTIME)
     118             :         ("associated-ip", DHCP_OPTION_ASSOCIATE_IP)
     119             :         ("system-architecture", DHCP_OPTION_CLIENT_SYSARCH_TYPE)
     120             :         ("interface-id", DHCP_OPTION_CLIENT_NW_INTERFACE_ID)
     121             :         ("ldap-servers", DHCP_OPTION_LDAP)
     122             :         ("machine-id", DHCP_OPTION_CLIENT_MACHINE_ID)
     123             :         ("user-auth", DHCP_OPTION_OPENGROUP_USER_AUTH)
     124             :         ("geoconf-civic", DHCP_OPTION_GEOCONF_CIVIC)
     125             :         ("ieee-1003-1-tz", DHCP_OPTION_IEEE_1003_1_TZ)
     126             :         ("ref-tz-db", DHCP_OPTION_REF_TZ_DB)
     127             :         ("netinfo-server-address", DHCP_OPTION_NETINFO_PARENT_SERVER_ADDR)
     128             :         ("netinfo-server-tag", DHCP_OPTION_NETINFO_PARENT_SERVER_TAG)
     129             :         ("default-url", DHCP_OPTION_URL)
     130             :         ("auto-configure", DHCP_OPTION_AUTO_CONFIGURE)
     131             :         ("name-search", DHCP_OPTION_NAME_SERVICE_SEARCH)
     132             :         ("subnet-selection", DHCP_OPTION_SUBNET_SELECTION)
     133             :         ("domain-search", DHCP_OPTION_DNS_DOMAIN_SEARCH_LIST)
     134             :         ("sip-servers", DHCP_OPTION_SIP_SERVERS)
     135             :         ("classless-static-routes", DHCP_OPTION_CLASSLESS_ROUTE)
     136             :         ("dhcp-ccc", DHCP_OPTION_CCC)
     137             :         ("dhcp-geoconf", DHCP_OPTION_GEOCONF)
     138             :         ("vendor-class-identifier", DHCP_OPTION_VENDOR_ID_VENDOR_CLASS)
     139             :         ("vivso", DHCP_OPTION_VENDOR_ID_VENDOR_SPECIFIC)
     140             :         ("tftp-server", DHCP_OPTION_TFTP_SERVER)
     141             :         ("pxe-vendor-specific-129", DHCP_OPTION_PXE_VENDOR_SPECIFIC_129)
     142             :         ("pxe-vendor-specific-130", DHCP_OPTION_PXE_VENDOR_SPECIFIC_130)
     143             :         ("pxe-vendor-specific-131", DHCP_OPTION_PXE_VENDOR_SPECIFIC_131)
     144             :         ("pxe-vendor-specific-132", DHCP_OPTION_PXE_VENDOR_SPECIFIC_132)
     145             :         ("pxe-vendor-specific-133", DHCP_OPTION_PXE_VENDOR_SPECIFIC_133)
     146             :         ("pxe-vendor-specific-134", DHCP_OPTION_PXE_VENDOR_SPECIFIC_134)
     147             :         ("pxe-vendor-specific-135", DHCP_OPTION_PXE_VENDOR_SPECIFIC_135)
     148             :         ("pana-agent", DHCP_OPTION_PANA_AUTH_AGENT)
     149             :         ("lost-server", DHCP_OPTION_LOST_SERVER)
     150             :         ("capwap-ac-v4", DHCP_OPTION_CAPWAP_AC_ADDRESS)
     151             :         ("dhcp-mos", DHCP_OPTION_IPV4_ADDRESS_MOS)
     152             :         ("dhcp-fqdn-mos", DHCP_OPTION_IPV4_FQDN_MOS)
     153             :         ("sip-ua-config-domain", DHCP_OPTION_SIP_UA_CONFIG_DOMAIN)
     154             :         ("andsf-servers", DHCP_OPTION_IPV4_ADDRESS_ANDSF)
     155             :         ("dhcp-geoloc", DHCP_OPTION_GEOLOC)
     156             :         ("force-renew-nonce-cap", DHCP_OPTION_FORCERENEW_NONCE_CAP)
     157             :         ("rdnss-selection", DHCP_OPTION_RDNSS_SELECTION)
     158             :         ("tftp-server-address", DHCP_OPTION_TFTP_SERVER_ADDRESS)
     159             :         ("status-code", DHCP_OPTION_STATUS_CODE)
     160             :         ("dhcp-base-time", DHCP_OPTION_BASE_TIME)
     161             :         ("dhcp-state-start-time", DHCP_OPTION_START_TIME_OF_STATE)
     162             :         ("dhcp-query-start-time", DHCP_OPTION_QUERY_START_TIME)
     163             :         ("dhcp-query-end-time", DHCP_OPTION_QUERY_END_TIME)
     164             :         ("dhcp-state", DHCP_OPTION_DHCP_STATE)
     165             :         ("data-source", DHCP_OPTION_DATA_SOURCE)
     166             :         ("pcp-server", DHCP_OPTION_PCP_SERVER)
     167             :         ("dhcp-pxe-magic", DHCP_OPTION_PXELINUX_MAGIC)
     168             :         ("config-file", DHCP_OPTION_CONFIG_FILE)
     169             :         ("path-prefix", DHCP_OPTION_PATH_PREFIX)
     170             :         ("reboot-time", DHCP_OPTION_REBOOT_TIME)
     171             :         ("dhcp-6rd", DHCP_OPTION_6RD)
     172             :         ("dhcp-access-domain", DHCP_OPTION_V4_ACCESS_DOMAIN)
     173             :         ("subnet-allocation", DHCP_OPTION_SUBNET_ALLOCATION)
     174             :         ("dhcp-vss", DHCP_OPTION_VSS);
     175             : 
     176             : Dhcpv4CategoryMap g_dhcpv4_category_map =
     177             :     map_list_of<uint32_t, DhcpHandler::DhcpOptionCategory>
     178             :         // (DHCP_OPTION_SUBNET_MASK, DhcpHandler::OneIPv4)       // agent adds this option
     179             :         (DHCP_OPTION_TIME_OFFSET, DhcpHandler::Int32bit)
     180             :         (DHCP_OPTION_ROUTER, DhcpHandler::OneIPv4Plus)
     181             :         (DHCP_OPTION_TIME_SERVER, DhcpHandler::OneIPv4Plus)
     182             :         (DHCP_OPTION_NAME_SERVER, DhcpHandler::OneIPv4Plus)
     183             :         (DHCP_OPTION_DNS, DhcpHandler::OneIPv4Plus)
     184             :         (DHCP_OPTION_LOG_SERVER, DhcpHandler::OneIPv4Plus)
     185             :         (DHCP_OPTION_QUOTE_SERVER, DhcpHandler::OneIPv4Plus)
     186             :         (DHCP_OPTION_LPR_SERVER, DhcpHandler::OneIPv4Plus)
     187             :         (DHCP_OPTION_IMPRESS_SERVER, DhcpHandler::OneIPv4Plus)
     188             :         (DHCP_OPTION_RESOURCE_LOCATION_SERVER, DhcpHandler::OneIPv4Plus)
     189             :         (DHCP_OPTION_HOST_NAME, DhcpHandler::String)
     190             :         (DHCP_OPTION_BOOT_FILE_SIZE, DhcpHandler::Uint16bit)
     191             :         (DHCP_OPTION_MERIT_DUMP_FILE, DhcpHandler::String)
     192             :         (DHCP_OPTION_DOMAIN_NAME, DhcpHandler::String)
     193             :         (DHCP_OPTION_SWAP_SERVER, DhcpHandler::OneIPv4)
     194             :         (DHCP_OPTION_ROOT_PATH, DhcpHandler::String)
     195             :         (DHCP_OPTION_EXTENSION_PATH, DhcpHandler::String)
     196             :         (DHCP_OPTION_IP_FWD_CONTROL, DhcpHandler::Bool)
     197             :         (DHCP_OPTION_NL_SRC_ROUTING, DhcpHandler::Bool)
     198             :         (DHCP_OPTION_POLICY_FILTER, DhcpHandler::TwoIPv4Plus)
     199             :         (DHCP_OPTION_MAX_DG_REASSEMBLY_SIZE, DhcpHandler::Uint16bit)
     200             :         (DHCP_OPTION_DEFAULT_IP_TTL, DhcpHandler::Byte)
     201             :         (DHCP_OPTION_PATH_MTU_AGING_TIMEOUT, DhcpHandler::Uint32bit)
     202             :         (DHCP_OPTION_PATH_MTU_PLATEAU_TABLE, DhcpHandler::Uint16bitArray)
     203             :         (DHCP_OPTION_INTERFACE_MTU, DhcpHandler::Uint16bit)
     204             :         (DHCP_OPTION_ALL_SUBNETS_LOCAL, DhcpHandler::Bool)
     205             :         // (DHCP_OPTION_BCAST_ADDRESS, DhcpHandler::OneIPv4)     // agent adds this option
     206             :         (DHCP_OPTION_PERFORM_MASK_DISCOVERY, DhcpHandler::Bool)
     207             :         (DHCP_OPTION_MASK_SUPPLIER, DhcpHandler::Bool)
     208             :         (DHCP_OPTION_PERFORM_ROUTER_DISCOVERY, DhcpHandler::Bool)
     209             :         (DHCP_OPTION_ROUTER_SOLICIT_ADDRESS, DhcpHandler::OneIPv4)
     210             :         (DHCP_OPTION_STATIC_ROUTING_TABLE, DhcpHandler::TwoIPv4Plus)
     211             :         (DHCP_OPTION_TRAILER_ENCAP, DhcpHandler::Bool)
     212             :         (DHCP_OPTION_ARP_CACHE_TIMEOUT, DhcpHandler::Uint32bit)
     213             :         (DHCP_OPTION_ETHERNET_ENCAP, DhcpHandler::Bool)
     214             :         (DHCP_OPTION_DEFAULT_TCP_TTL, DhcpHandler::Byte)
     215             :         (DHCP_OPTION_TCP_KEEPALIVE_INTERVAL, DhcpHandler::Uint32bit)
     216             :         (DHCP_OPTION_TCP_KEEPALIVE_GARBAGE, DhcpHandler::Bool)
     217             :         (DHCP_OPTION_NIS_DOMAIN, DhcpHandler::String)
     218             :         (DHCP_OPTION_NIS_SERVERS, DhcpHandler::OneIPv4Plus)
     219             :         (DHCP_OPTION_NTP_SERVERS, DhcpHandler::OneIPv4Plus)
     220             :         (DHCP_OPTION_VENDOR_SPECIFIC_INFO, DhcpHandler::String)
     221             :         (DHCP_OPTION_NETBIOS_OVER_TCP_NS, DhcpHandler::OneIPv4Plus)
     222             :         (DHCP_OPTION_NETBIOS_OVER_TCP_DG_DS, DhcpHandler::OneIPv4Plus)
     223             :         (DHCP_OPTION_NETBIOS_OVER_TCP_NODE_TYPE, DhcpHandler::Byte)
     224             :         (DHCP_OPTION_NETBIOS_OVER_TCP_SCOPE, DhcpHandler::String)
     225             :         (DHCP_OPTION_XWINDOW_FONT_SERVER, DhcpHandler::OneIPv4Plus)
     226             :         (DHCP_OPTION_XWINDOW_SYSTEM_DISP_MGR, DhcpHandler::OneIPv4Plus)
     227             :         (DHCP_OPTION_REQ_IP_ADDRESS, DhcpHandler::OneIPv4)
     228             :         (DHCP_OPTION_IP_LEASE_TIME, DhcpHandler::Uint32bit)
     229             :         (DHCP_OPTION_OVERLOAD, DhcpHandler::Byte)
     230             :         // (DHCP_OPTION_MSG_TYPE, DhcpHandler::Byte)           // agent adds this option
     231             :         // (DHCP_OPTION_SERVER_IDENTIFIER, DhcpHandler::OneIPv4) // agent adds this option
     232             :         (DHCP_OPTION_PARAMETER_REQUEST_LIST, DhcpHandler::ByteArray)
     233             :         (DHCP_OPTION_MESSAGE, DhcpHandler::String)
     234             :         (DHCP_OPTION_MAX_DHCP_MSG_SIZE, DhcpHandler::Uint16bit)
     235             :         (DHCP_OPTION_RENEW_TIME_VALUE, DhcpHandler::Uint32bit)
     236             :         (DHCP_OPTION_REBIND_TIME_VALUE, DhcpHandler::Uint32bit)
     237             :         (DHCP_OPTION_CLASS_ID, DhcpHandler::String)
     238             :         (DHCP_OPTION_CLIENT_ID, DhcpHandler::ByteString)
     239             :         (DHCP_OPTION_NETWARE_IP_DOMAIN_NAME, DhcpHandler::String)
     240             :         (DHCP_OPTION_NETWARE_IP_INFO, DhcpHandler::ByteArray)  // send encoded data
     241             :         (DHCP_OPTION_NIS_PLUS_DOMAIN, DhcpHandler::String)
     242             :         (DHCP_OPTION_NIS_PLUS_SERVERS, DhcpHandler::OneIPv4Plus)
     243             :         (DHCP_OPTION_TFTP_SERVER_NAME, DhcpHandler::String)
     244             :         (DHCP_OPTION_BOOTFILE_NAME, DhcpHandler::String)
     245             :         (DHCP_OPTION_MOBILE_IP_HA, DhcpHandler::ZeroIPv4Plus)
     246             :         (DHCP_OPTION_SMTP_SERVER, DhcpHandler::OneIPv4Plus)
     247             :         (DHCP_OPTION_POP_SERVER, DhcpHandler::OneIPv4Plus)
     248             :         (DHCP_OPTION_NNTP_SERVER, DhcpHandler::OneIPv4Plus)
     249             :         (DHCP_OPTION_DEFAULT_WWW_SERVER, DhcpHandler::OneIPv4Plus)
     250             :         (DHCP_OPTION_DEFAULT_FINGER_SERVER, DhcpHandler::OneIPv4Plus)
     251             :         (DHCP_OPTION_DEFAULT_IRC_SERVER, DhcpHandler::OneIPv4Plus)
     252             :         (DHCP_OPTION_STREETTALK_SERVER, DhcpHandler::OneIPv4Plus)
     253             :         (DHCP_OPTION_STREETTALK_DA_SERVER, DhcpHandler::OneIPv4Plus)
     254             :         (DHCP_OPTION_USER_CLASS_INFO, DhcpHandler::ByteArray)  // send encoded data
     255             :         (DHCP_OPTION_SLP_DIRECTORY_AGENT, DhcpHandler::ByteOneIPPlus)
     256             :         (DHCP_OPTION_SLP_SERVICE_SCOPE, DhcpHandler::ByteString)
     257             :         (DHCP_OPTION_RAPID_COMMIT, DhcpHandler::NoData)
     258             :         // (DHCP_OPTION_CLIENT_FQDN, DhcpHandler::ByteArray)   // sent by clients
     259             :         (DHCP_OPTION_STORAGE_NS, DhcpHandler::ByteArray)       // send encoded data
     260             :         (DHCP_OPTION_NDS_SERVERS, DhcpHandler::OneIPv4Plus)
     261             :         (DHCP_OPTION_NDS_TREE_NAME, DhcpHandler::ByteArray)    // send encoded data
     262             :         (DHCP_OPTION_NDS_CONTEXT, DhcpHandler::ByteArray)      // send encoded data
     263             :         (DHCP_OPTION_BCMCS_DN_LIST, DhcpHandler::ByteArray)    // send encoded data
     264             :         (DHCP_OPTION_BCMCS_ADDR_LIST, DhcpHandler::ByteArray)  // send encoded data
     265             :         (DHCP_OPTION_AUTH, DhcpHandler::ByteArray)             // send encoded data
     266             :         (DHCP_OPTION_CLIENT_LAST_XTIME, DhcpHandler::Uint32bit)
     267             :         (DHCP_OPTION_ASSOCIATE_IP, DhcpHandler::OneIPv4Plus)
     268             :         (DHCP_OPTION_CLIENT_SYSARCH_TYPE, DhcpHandler::Uint16bit)
     269             :         (DHCP_OPTION_CLIENT_NW_INTERFACE_ID, DhcpHandler::ByteArray)
     270             :         (DHCP_OPTION_LDAP, DhcpHandler::OneIPv4Plus)
     271             :         (DHCP_OPTION_CLIENT_MACHINE_ID, DhcpHandler::String)
     272             :         (DHCP_OPTION_OPENGROUP_USER_AUTH, DhcpHandler::String)
     273             :         (DHCP_OPTION_GEOCONF_CIVIC, DhcpHandler::ByteArray)    // send encoded data
     274             :         (DHCP_OPTION_IEEE_1003_1_TZ, DhcpHandler::String)
     275             :         (DHCP_OPTION_REF_TZ_DB, DhcpHandler::String)
     276             :         (DHCP_OPTION_NETINFO_PARENT_SERVER_TAG, DhcpHandler::String)
     277             :         (DHCP_OPTION_NETINFO_PARENT_SERVER_ADDR, DhcpHandler::OneIPv4Plus)
     278             :         (DHCP_OPTION_URL, DhcpHandler::String)
     279             :         (DHCP_OPTION_AUTO_CONFIGURE, DhcpHandler::Bool)
     280             :         (DHCP_OPTION_NAME_SERVICE_SEARCH, DhcpHandler::Uint16bitArray)
     281             :         (DHCP_OPTION_SUBNET_SELECTION, DhcpHandler::OneIPv4)
     282             :         (DHCP_OPTION_DNS_DOMAIN_SEARCH_LIST, DhcpHandler::NameCompression)
     283             :         (DHCP_OPTION_SIP_SERVERS, DhcpHandler::ByteArray)                // send encoded data
     284             :         (DHCP_OPTION_CLASSLESS_ROUTE, DhcpHandler::ClasslessRoute)
     285             :         (DHCP_OPTION_CCC, DhcpHandler::ByteArray)                        // send encoded data
     286             :         (DHCP_OPTION_GEOCONF, DhcpHandler::ByteArray)                    // send encoded data
     287             :         (DHCP_OPTION_VENDOR_ID_VENDOR_CLASS, DhcpHandler::ByteArray)     // send encoded data
     288             :         (DHCP_OPTION_VENDOR_ID_VENDOR_SPECIFIC, DhcpHandler::ByteArray)  // send encoded data
     289             :         (DHCP_OPTION_TFTP_SERVER, DhcpHandler::OneIPv4Plus)
     290             :         (DHCP_OPTION_PXE_VENDOR_SPECIFIC_129, DhcpHandler::String)
     291             :         (DHCP_OPTION_PXE_VENDOR_SPECIFIC_130, DhcpHandler::String)
     292             :         (DHCP_OPTION_PXE_VENDOR_SPECIFIC_131, DhcpHandler::String)
     293             :         (DHCP_OPTION_PXE_VENDOR_SPECIFIC_132, DhcpHandler::String)
     294             :         (DHCP_OPTION_PXE_VENDOR_SPECIFIC_133, DhcpHandler::String)
     295             :         (DHCP_OPTION_PXE_VENDOR_SPECIFIC_134, DhcpHandler::String)
     296             :         (DHCP_OPTION_PXE_VENDOR_SPECIFIC_135, DhcpHandler::String)
     297             :         (DHCP_OPTION_PANA_AUTH_AGENT, DhcpHandler::OneIPv4Plus)
     298             :         (DHCP_OPTION_LOST_SERVER, DhcpHandler::ByteArray)         // send encoded data
     299             :         (DHCP_OPTION_CAPWAP_AC_ADDRESS, DhcpHandler::OneIPv4Plus)
     300             :         (DHCP_OPTION_IPV4_ADDRESS_MOS, DhcpHandler::ByteArray)     // send encoded data
     301             :         (DHCP_OPTION_IPV4_FQDN_MOS, DhcpHandler::ByteArray)        // send encoded data
     302             :         (DHCP_OPTION_SIP_UA_CONFIG_DOMAIN, DhcpHandler::ByteArray) // send encoded data
     303             :         (DHCP_OPTION_IPV4_ADDRESS_ANDSF, DhcpHandler::OneIPv4Plus)
     304             :         (DHCP_OPTION_GEOLOC, DhcpHandler::ByteArray)               // send encoded data
     305             :         (DHCP_OPTION_FORCERENEW_NONCE_CAP, DhcpHandler::ByteArray) // send encoded data
     306             :         (DHCP_OPTION_RDNSS_SELECTION, DhcpHandler::ByteArray)      // send encoded data
     307             :         (DHCP_OPTION_TFTP_SERVER_ADDRESS, DhcpHandler::OneIPv4Plus)
     308             :         (DHCP_OPTION_STATUS_CODE, DhcpHandler::ByteString)
     309             :         (DHCP_OPTION_BASE_TIME, DhcpHandler::Uint32bit)
     310             :         (DHCP_OPTION_START_TIME_OF_STATE, DhcpHandler::Uint32bit)
     311             :         (DHCP_OPTION_QUERY_START_TIME, DhcpHandler::Uint32bit)
     312             :         (DHCP_OPTION_QUERY_END_TIME, DhcpHandler::Uint32bit)
     313             :         (DHCP_OPTION_DHCP_STATE, DhcpHandler::Byte)
     314             :         (DHCP_OPTION_DATA_SOURCE, DhcpHandler::Byte)
     315             :         (DHCP_OPTION_PCP_SERVER, DhcpHandler::ByteArray)      // send encoded data
     316             :         (DHCP_OPTION_PXELINUX_MAGIC, DhcpHandler::Uint32bit)
     317             :         (DHCP_OPTION_CONFIG_FILE, DhcpHandler::String)
     318             :         (DHCP_OPTION_PATH_PREFIX, DhcpHandler::String)
     319             :         (DHCP_OPTION_REBOOT_TIME, DhcpHandler::Uint32bit)
     320             :         (DHCP_OPTION_6RD, DhcpHandler::ByteArray)               // send encoded data
     321             :         (DHCP_OPTION_SUBNET_ALLOCATION, DhcpHandler::ByteArray)
     322             :         (DHCP_OPTION_V4_ACCESS_DOMAIN, DhcpHandler::ByteArray)  // send encoded data
     323             :         (DHCP_OPTION_VSS, DhcpHandler::ByteString)
     324             :         (DHCP_OPTION_PAD, DhcpHandler::None)
     325             :         (DHCP_OPTION_END, DhcpHandler::None);
     326             : 
     327           0 : DhcpHandler::DhcpHandler(Agent *agent, boost::shared_ptr<PktInfo> info,
     328           0 :                          boost::asio::io_context &io)
     329           0 :         : DhcpHandlerBase(agent, info, io), msg_type_(DHCP_UNKNOWN),
     330           0 :           out_msg_type_(DHCP_UNKNOWN),
     331           0 :           nak_msg_("cannot assign requested address") {
     332           0 :     option_.reset(new Dhcpv4OptionHandler(NULL));
     333           0 : }
     334             : 
     335           0 : DhcpHandler::~DhcpHandler() {
     336           0 : }
     337             : 
     338           0 : bool DhcpHandler::Run() {
     339           0 :     switch(pkt_info_->type) {
     340           0 :         case PktType::MESSAGE:
     341           0 :             return HandleMessage();
     342             : 
     343           0 :        default:
     344           0 :             return HandleVmRequest();
     345             :     }
     346             : }
     347             : 
     348           0 : bool DhcpHandler::HandleVmRequest() {
     349           0 :     DhcpProto *dhcp_proto = agent()->GetDhcpProto();
     350             :     // options length = pkt length - size of headers
     351           0 :     int16_t options_len = pkt_info_->len -
     352           0 :                           (pkt_info_->data - (uint8_t *)pkt_info_->pkt)
     353           0 :                           - DHCP_FIXED_LEN;
     354           0 :     if (options_len < 0) {
     355           0 :         agent()->GetDhcpProto()->IncrStatsErrors();
     356           0 :         DHCP_TRACE(Error, "Improper DHCP packet length; vrf = " <<
     357             :                    pkt_info_->vrf << " ifindex = " << GetInterfaceIndex());
     358           0 :         return true;
     359             :     }
     360             : 
     361           0 :     dhcp_ = (dhcphdr *) pkt_info_->data;
     362           0 :     option_->SetDhcpOptionPtr(dhcp_->options);
     363           0 :     request_.UpdateData(dhcp_->xid, ntohs(dhcp_->flags), dhcp_->chaddr);
     364             :     Interface *itf =
     365           0 :         agent()->interface_table()->FindInterface(GetInterfaceIndex());
     366           0 :     if (itf == NULL) {
     367           0 :         dhcp_proto->IncrStatsOther();
     368           0 :         DHCP_TRACE(Error, "Received DHCP packet on invalid interface : "
     369             :                    << GetInterfaceIndex());
     370           0 :         return true;
     371             :     }
     372             : 
     373           0 :     if (itf->type() != Interface::VM_INTERFACE) {
     374           0 :         dhcp_proto->IncrStatsErrors();
     375           0 :         DHCP_TRACE(Error, "Received DHCP packet on non VM port interface : "
     376             :                    << GetInterfaceIndex());
     377           0 :         return true;
     378             :     }
     379           0 :     vm_itf_ = static_cast<VmInterface *>(itf);
     380           0 :     if (!vm_itf_->dhcp_enable_config()) {
     381           0 :         dhcp_proto->IncrDhcpDisabledDrops();
     382           0 :         DHCP_TRACE(Error, "DHCP request on VM port with dhcp services disabled: "
     383             :                    << GetInterfaceIndex());
     384           0 :         return true;
     385             :     }
     386             : 
     387           0 :     if (vm_itf_->vm_mac() != request_.mac_addr) {
     388           0 :         dhcp_proto->IncrIncorrectMac();
     389           0 :         DHCP_TRACE(Error, "DHCP request for incorrect MAC: interface = "
     390             :                    << GetInterfaceIndex() << " interface MAC = "
     391             :                    << vm_itf_->vm_mac().ToString() << " requested MAC = "
     392             :                    << request_.mac_addr.ToString());
     393           0 :         return true;
     394             :     }
     395             : 
     396             :     // For VM interfaces in default VRF, if the config doesnt have IP address,
     397             :     // send the request to fabric
     398           0 :     if (dhcp_proto->dhcp_relay_mode() &&
     399           0 :         vm_itf_->vrf() && vm_itf_->do_dhcp_relay()) {
     400           0 :         RelayRequestToFabric();
     401           0 :         return true;
     402             :     }
     403             : 
     404           0 :     if (!ReadOptions(options_len))
     405           0 :         return true;
     406             : 
     407           0 :     switch (msg_type_) {
     408           0 :         case DHCP_DISCOVER:
     409           0 :             out_msg_type_ = DHCP_OFFER;
     410           0 :             dhcp_proto->IncrStatsDiscover();
     411           0 :             DHCP_TRACE(Trace, "DHCP discover received on interface : "
     412             :                        << vm_itf_->name() << " Mac : " <<
     413             :                        request_.mac_addr.ToString());
     414           0 :             break;
     415             : 
     416           0 :         case DHCP_REQUEST:
     417           0 :             out_msg_type_ = DHCP_ACK;
     418           0 :             dhcp_proto->IncrStatsRequest();
     419           0 :             DHCP_TRACE(Trace, "DHCP request received on interface : "
     420             :                        << vm_itf_->name() << " Mac : " <<
     421             :                        request_.mac_addr.ToString());
     422           0 :             break;
     423             : 
     424           0 :         case DHCP_INFORM:
     425           0 :             out_msg_type_ = DHCP_ACK;
     426           0 :             dhcp_proto->IncrStatsInform();
     427           0 :             DHCP_TRACE(Trace, "DHCP inform received on interface : "
     428             :                        << vm_itf_->name() << " Mac : " <<
     429             :                        request_.mac_addr.ToString());
     430           0 :             break;
     431             : 
     432           0 :         case DHCP_DECLINE:
     433           0 :             dhcp_proto->IncrStatsDecline();
     434           0 :             DHCP_TRACE(Error, "DHCP Client declined the offer : vrf = " <<
     435             :                        pkt_info_->vrf << " ifindex = " << GetInterfaceIndex() <<
     436             :                        " Mac : " << request_.mac_addr.ToString());
     437           0 :             if (vm_itf_->vmi_type() == VmInterface::GATEWAY) {
     438           0 :                 ReleaseGatewayInterfaceLease();
     439             :             }
     440           0 :             return true;
     441             : 
     442           0 :         case DHCP_RELEASE:
     443           0 :             DHCP_TRACE(Error, "DHCP lease released : vrf = " <<
     444             :                        pkt_info_->vrf << " ifindex = " << GetInterfaceIndex() <<
     445             :                        " Mac : " << request_.mac_addr.ToString());
     446           0 :             if (vm_itf_->vmi_type() == VmInterface::GATEWAY) {
     447           0 :                 ReleaseGatewayInterfaceLease();
     448             :             }
     449           0 :             dhcp_proto->IncrStatsRelease();
     450           0 :             return true;
     451             : 
     452           0 :         case DHCP_ACK:
     453             :         case DHCP_NAK:
     454             :         case DHCP_LEASE_QUERY:
     455             :         case DHCP_LEASE_UNASSIGNED:
     456             :         case DHCP_LEASE_UNKNOWN:
     457             :         case DHCP_LEASE_ACTIVE:
     458             :         default:
     459           0 :             DHCP_TRACE(Trace, ServicesSandesh::DhcpMsgType(msg_type_) <<
     460             :                        " received on interface : " << vm_itf_->name() <<
     461             :                        " Mac : " << request_.mac_addr.ToString() <<
     462             :                        "; ignoring");
     463           0 :             dhcp_proto->IncrStatsOther();
     464           0 :             return true;
     465             :     }
     466             : 
     467           0 :     if (FindLeaseData()) {
     468           0 :         SendDhcpResponse();
     469           0 :         DHCP_TRACE(Trace, "DHCP response sent; message = " <<
     470             :                    ServicesSandesh::DhcpMsgType(out_msg_type_) <<
     471             :                    "; ip = " << config_.ip_addr.to_string());
     472             :     }
     473             : 
     474           0 :     return true;
     475             : }
     476             : 
     477           0 : bool DhcpHandler::HandleMessage() {
     478           0 :     switch (pkt_info_->ipc->cmd) {
     479           0 :         case DhcpProto::DHCP_VHOST_MSG:
     480             :             // DHCP message from DHCP server port that we listen on
     481           0 :             if (agent()->GetDhcpProto()->dhcp_relay_mode())
     482           0 :                 return HandleDhcpFromFabric();
     483             : 
     484             :         default:
     485           0 :             agent()->GetDhcpProto()->IncrUnknownMsgDrops();
     486           0 :             assert(0);
     487             :     }
     488             : 
     489             :     return true;
     490             : }
     491             : 
     492             : // Handle any DHCP response coming from fabric for a request that we relayed
     493           0 : bool DhcpHandler::HandleDhcpFromFabric() {
     494           0 :     DhcpProto::DhcpVhostMsg *ipc = static_cast<DhcpProto::DhcpVhostMsg *>(pkt_info_->ipc);
     495           0 :     pkt_info_->len = ipc->len;
     496           0 :     dhcp_ = reinterpret_cast<dhcphdr *>(ipc->pkt);
     497           0 :     option_->SetDhcpOptionPtr(dhcp_->options);
     498           0 :     request_.UpdateData(dhcp_->xid, ntohs(dhcp_->flags), dhcp_->chaddr);
     499             : 
     500           0 :     int16_t options_len = ipc->len - DHCP_FIXED_LEN;
     501           0 :     if (ReadOptions(options_len) && vm_itf_ &&
     502           0 :         agent()->interface_table()->FindInterface(vm_itf_index_) == vm_itf_) {
     503             :         // this is a DHCP relay response for our request
     504           0 :         RelayResponseFromFabric();
     505             :     }
     506             : 
     507           0 :     delete ipc;
     508           0 :     return true;
     509             : }
     510             : 
     511             : // read DHCP options in the incoming packet
     512           0 : bool DhcpHandler::ReadOptions(int16_t opt_rem_len) {
     513             :     // verify magic cookie
     514           0 :     if ((opt_rem_len < 4) ||
     515           0 :         memcmp(dhcp_->options, DHCP_OPTIONS_COOKIE, 4)) {
     516           0 :         agent()->GetDhcpProto()->IncrStatsErrors();
     517           0 :         DHCP_TRACE(Error, "DHCP options cookie missing; vrf = " <<
     518             :                    pkt_info_->vrf << " ifindex = " << GetInterfaceIndex());
     519           0 :         return false;
     520             :     }
     521             : 
     522           0 :     opt_rem_len -= 4;
     523           0 :     Dhcpv4Options *opt = (Dhcpv4Options *)(dhcp_->options + 4);
     524             :     // parse thru the option fields
     525           0 :     while ((opt_rem_len > 0) && (opt->code != DHCP_OPTION_END)) {
     526           0 :         switch (opt->code) {
     527           0 :             case DHCP_OPTION_PAD:
     528           0 :                 opt_rem_len -= 1;
     529           0 :                 opt = (Dhcpv4Options *)((uint8_t *)opt + 1);
     530           0 :                 continue;
     531             : 
     532           0 :             case DHCP_OPTION_MSG_TYPE:
     533           0 :                 if (opt_rem_len >= opt->len + 2)
     534           0 :                     msg_type_ = *(uint8_t *)opt->data;
     535           0 :                 break;
     536             : 
     537           0 :             case DHCP_OPTION_REQ_IP_ADDRESS:
     538           0 :                 if (opt_rem_len >= opt->len + 2) {
     539             :                     union {
     540             :                         uint8_t data[sizeof(in_addr_t)];
     541             :                         in_addr_t addr;
     542             :                     } bytes;
     543           0 :                     memcpy(bytes.data, opt->data, sizeof(in_addr_t));
     544           0 :                     request_.ip_addr = ntohl(bytes.addr);
     545             :                 }
     546           0 :                 break;
     547             : 
     548           0 :             case DHCP_OPTION_HOST_NAME:
     549           0 :                 if (opt_rem_len >= opt->len + 2)
     550           0 :                     config_.client_name_.assign((char *)opt->data, opt->len);
     551           0 :                 break;
     552             : 
     553           0 :             case DHCP_OPTION_DOMAIN_NAME:
     554           0 :                 if (opt_rem_len >= opt->len + 2)
     555           0 :                     config_.domain_name_.assign((char *)opt->data, opt->len);
     556           0 :                 break;
     557             : 
     558           0 :             case DHCP_OPTION_PARAMETER_REQUEST_LIST:
     559           0 :                 if (opt_rem_len >= opt->len + 2)
     560           0 :                     parameters_.assign((char *)opt->data, opt->len);
     561           0 :                 break;
     562             : 
     563           0 :             case DHCP_OPTION_82:
     564           0 :                 ReadOption82(opt);
     565           0 :                 break;
     566             : 
     567           0 :             default:
     568           0 :                 break;
     569           0 :         }
     570           0 :         opt_rem_len -= (2 + opt->len);
     571           0 :         opt = (Dhcpv4Options *)((uint8_t *)opt + 2 + opt->len);
     572             :     }
     573             : 
     574           0 :     return true;
     575             : }
     576             : 
     577           0 : void DhcpHandler::FillDhcpInfo(Ip4Address &addr, int plen,
     578             :                                Ip4Address &gw, Ip4Address &dns) {
     579           0 :     config_.ip_addr = addr;
     580           0 :     config_.plen = plen;
     581           0 :     uint32_t mask = plen? (0xFFFFFFFF << (32 - plen)) : 0;
     582           0 :     config_.subnet_mask = mask;
     583           0 :     config_.bcast_addr = (addr.to_ulong() & mask) | ~mask;
     584           0 :     config_.gw_addr = gw;
     585           0 :     config_.dns_addr = dns;
     586           0 : }
     587             : 
     588             : 
     589           0 : bool DhcpHandler::GetGatewayInterfaceLease() {
     590           0 :     DhcpLeaseDb *dhcp_lease_db = agent()->GetDhcpProto()->GetLeaseDb(vm_itf_);
     591           0 :     if (dhcp_lease_db) {
     592           0 :         Ip4Address ip;
     593           0 :         const VnIpam *vn_ipam = (vm_itf_->vn()) ?
     594           0 :             vm_itf_->vn()->GetIpam(IpAddress(vm_itf_->subnet())) : NULL;
     595           0 :         if (!vn_ipam || !dhcp_lease_db->Allocate(request_.mac_addr, &ip,
     596             :                                                  DHCP_GW_LEASE_TIME)) {
     597           0 :             agent()->GetDhcpProto()->IncrStatsErrors();
     598           0 :             DHCP_TRACE(Error, "DHCP request from Gateway interface failed :"
     599             :                        " could not allocate IP address for Mac : " <<
     600             :                        request_.mac_addr.ToString() << " on VMI : " <<
     601             :                        vm_itf_->name());
     602           0 :             return false;
     603             :         }
     604           0 :         config_.lease_time = DHCP_GW_LEASE_TIME;
     605           0 :         Ip4Address gw = vn_ipam->default_gw.to_v4();
     606           0 :         Ip4Address dns = vn_ipam->dns_server.to_v4();
     607           0 :         FillDhcpInfo(ip, dhcp_lease_db->plen(), gw, dns);
     608           0 :         return true;
     609             :     }
     610             : 
     611           0 :     DHCP_TRACE(Error, "DHCP request on VMI " << vm_itf_->name() <<
     612             :                " could not be served - DHCP lease db is not created");
     613           0 :     return false;
     614             : }
     615             : 
     616           0 : void DhcpHandler::ReleaseGatewayInterfaceLease() {
     617           0 :     DhcpLeaseDb *dhcp_lease_db = agent()->GetDhcpProto()->GetLeaseDb(vm_itf_);
     618           0 :     if (!dhcp_lease_db || !dhcp_lease_db->Release(request_.mac_addr)) {
     619           0 :         agent()->GetDhcpProto()->IncrStatsErrors();
     620           0 :         DHCP_TRACE(Error, "DHCP lease release failed : vrf = " <<
     621             :                    pkt_info_->vrf << " ifindex = " << GetInterfaceIndex() <<
     622             :                    " Mac : " << request_.mac_addr.ToString());
     623             :     }
     624           0 : }
     625             : 
     626           0 : bool DhcpHandler::FindLeaseData() {
     627           0 :     Ip4Address unspecified;
     628           0 :     Ip4Address ip = vm_itf_->primary_ip_addr();
     629             :     // Change client name to VM name; this is the name assigned to the VM
     630           0 :     config_.client_name_ = vm_itf_->vm_name();
     631           0 :     FindDomainName(ip);
     632           0 :     if (vm_itf_->IsActive() || vm_itf_->device_type() == VmInterface::TOR) {
     633             :         // if the request is from a Gateway interface, get an address from the
     634             :         // relevant subnet
     635           0 :         if (vm_itf_->vmi_type() == VmInterface::GATEWAY) {
     636           0 :             return GetGatewayInterfaceLease();
     637             :         }
     638             : 
     639           0 :         if (vm_itf_->fabric_port()) {
     640             :             InetUnicastRouteEntry *rt =
     641           0 :                 InetUnicastAgentRouteTable::FindResolveRoute(
     642           0 :                              vm_itf_->vrf()->GetName(), ip);
     643           0 :             if (rt) {
     644           0 :                 Ip4Address gw = agent()->vhost_default_gateway()[0];
     645           0 :                 boost::system::error_code ec;
     646           0 :                 if (IsIp4SubnetMember(rt->prefix_address().to_v4(),
     647           0 :                     Ip4Address::from_string("169.254.0.0", ec), rt->prefix_length())) {
     648           0 :                     gw = unspecified;
     649             :                 }
     650           0 :                 FillDhcpInfo(ip, rt->prefix_length(), gw, gw);
     651           0 :                 return true;
     652             :             }
     653           0 :             agent()->GetDhcpProto()->IncrStatsErrors();
     654           0 :             DHCP_TRACE(Error, "DHCP fabric port request failed : "
     655             :                        "could not find route for " << ip.to_string());
     656           0 :             return false;
     657             :         }
     658             : 
     659           0 :         const std::vector<VnIpam> &ipam = vm_itf_->vn()->GetVnIpam();
     660             :         unsigned int i;
     661           0 :         for (i = 0; i < ipam.size(); ++i) {
     662           0 :             if (!ipam[i].IsV4()) {
     663           0 :                 continue;
     664             :             }
     665           0 :             if (IsIp4SubnetMember(ip, ipam[i].ip_prefix.to_v4(),
     666           0 :                                   ipam[i].plen)) {
     667           0 :                 Ip4Address default_gw = ipam[i].default_gw.to_v4();
     668           0 :                 Ip4Address service_address = ipam[i].dns_server.to_v4();
     669           0 :                 if (service_address.is_unspecified())
     670           0 :                     service_address = default_gw;
     671           0 :                 FillDhcpInfo(ip, ipam[i].plen, default_gw, service_address);
     672           0 :                 return true;
     673             :             }
     674             :         }
     675             :     }
     676             : 
     677             :     // We dont have the config yet; give a short lease
     678           0 :     config_.lease_time = DHCP_SHORTLEASE_TIME;
     679           0 :     if (ip.to_ulong()) {
     680             :         // Give address received from Nova
     681           0 :         FillDhcpInfo(ip, 32, unspecified, unspecified);
     682             :     } else {
     683             :         // Give a link local address
     684           0 :         boost::system::error_code ec;
     685             :         Ip4Address gwip = Ip4Address::from_string
     686           0 :             (agent()->v4_link_local_subnet(), ec);
     687           0 :         gwip = Ip4Address((gwip.to_ulong() & 0xFFFF0000) | (vm_itf_->id() & 0xFF));
     688           0 :         FillDhcpInfo(gwip, 16, unspecified, unspecified);
     689             :     }
     690           0 :     return true;
     691             : }
     692             : 
     693           0 : void DhcpHandler::WriteOption82(Dhcpv4Options *opt, uint16_t *optlen) {
     694           0 :     *optlen += 2;
     695           0 :     opt->code = DHCP_OPTION_82;
     696           0 :     opt->len = sizeof(uint32_t) + 2 + sizeof(VmInterface *) + 2;
     697           0 :     Dhcpv4Options *subopt = reinterpret_cast<Dhcpv4Options *>(opt->data);
     698           0 :     uint32_t value = htonl(vm_itf_->id());
     699           0 :     subopt->WriteData(DHCP_SUBOP_CKTID, 4, &value, optlen);
     700           0 :     subopt = subopt->GetNextOptionPtr();
     701           0 :     subopt->WriteData(DHCP_SUBOP_REMOTEID, sizeof(VmInterface *),
     702           0 :                       &vm_itf_, optlen);
     703           0 : }
     704             : 
     705           0 : bool DhcpHandler::ReadOption82(Dhcpv4Options *opt) {
     706           0 :     if (opt->len != sizeof(uint32_t) + 2 + sizeof(VmInterface *) + 2)
     707           0 :         return false;
     708             : 
     709           0 :     Dhcpv4Options *subopt = reinterpret_cast<Dhcpv4Options *>(opt->data);
     710           0 :     for (int i = 0; i < 2; i++) {
     711           0 :         switch (subopt->code) {
     712           0 :             case DHCP_SUBOP_CKTID:
     713           0 :                 if (subopt->len != sizeof(uint32_t))
     714           0 :                     return false;
     715             :                 union {
     716             :                     uint8_t data[sizeof(uint32_t)];
     717             :                     uint32_t index;
     718             :                 } bytes;
     719             : 
     720           0 :                 memcpy(bytes.data, subopt->data, sizeof(uint32_t));
     721           0 :                 vm_itf_index_ = ntohl(bytes.index);
     722           0 :                 break;
     723             : 
     724           0 :             case DHCP_SUBOP_REMOTEID:
     725           0 :                 if (subopt->len != sizeof(VmInterface *))
     726           0 :                     return false;
     727           0 :                 memcpy(&vm_itf_, subopt->data, subopt->len);
     728           0 :                 break;
     729             : 
     730           0 :             default:
     731           0 :                 return false;
     732             :         }
     733           0 :         subopt = subopt->GetNextOptionPtr();
     734             :     }
     735             : 
     736           0 :     return true;
     737             : }
     738             : 
     739           0 : bool DhcpHandler::CreateRelayPacket() {
     740           0 :     PktInfo in_pkt_info = *pkt_info_.get();
     741             : 
     742           0 :     pkt_info_->AllocPacketBuffer(agent(), PktHandler::DHCP, DHCP_PKT_SIZE, 0);
     743           0 :     memset(pkt_info_->pkt, 0, DHCP_PKT_SIZE);
     744           0 :     pkt_info_->vrf = in_pkt_info.vrf;
     745           0 :     pkt_info_->eth = (struct ether_header *)(pkt_info_->pkt);
     746           0 :     int eth_len = 0;
     747           0 :     eth_len = EthHdr((char *)pkt_info_->eth, DHCP_PKT_SIZE,
     748             :                      agent()->GetDhcpProto()->ip_fabric_interface_index(),
     749             :                      agent()->GetDhcpProto()->ip_fabric_interface_mac(),
     750           0 :                      MacAddress(in_pkt_info.eth->ether_dhost), ETHERTYPE_IP);
     751             : 
     752           0 :     pkt_info_->ip = (struct ip *)((char *)pkt_info_->eth + eth_len);
     753           0 :     pkt_info_->transp.udp = (udphdr *)(pkt_info_->ip + 1);
     754           0 :     dhcphdr *dhcp = (dhcphdr *)(pkt_info_->transp.udp + 1);
     755             : 
     756           0 :     memcpy((uint8_t *)dhcp, (uint8_t *)dhcp_, DHCP_FIXED_LEN);
     757           0 :     memcpy(dhcp->options, DHCP_OPTIONS_COOKIE, 4);
     758             : 
     759           0 :     int16_t opt_rem_len = in_pkt_info.len - eth_len - sizeof(struct ip)
     760           0 :         - sizeof(udphdr) - DHCP_FIXED_LEN - 4;
     761           0 :     uint16_t opt_len = 4;
     762           0 :     Dhcpv4Options *read_opt = (Dhcpv4Options *)(dhcp_->options + 4);
     763           0 :     Dhcpv4Options *write_opt = (Dhcpv4Options *)(dhcp->options + 4);
     764           0 :     while ((opt_rem_len > 0) && (read_opt->code != DHCP_OPTION_END)) {
     765           0 :         switch (read_opt->code) {
     766           0 :             case DHCP_OPTION_PAD:
     767           0 :                 write_opt->WriteByte(DHCP_OPTION_PAD, &opt_len);
     768           0 :                 write_opt = write_opt->GetNextOptionPtr();
     769           0 :                 opt_rem_len -= 1;
     770           0 :                 read_opt = read_opt->GetNextOptionPtr();
     771           0 :                 continue;
     772             : 
     773           0 :             case DHCP_OPTION_82:
     774           0 :                 break;
     775             : 
     776           0 :             case DHCP_OPTION_MSG_TYPE:
     777           0 :                 msg_type_ = *(uint8_t *)read_opt->data;
     778           0 :                 write_opt->WriteData(read_opt->code, read_opt->len, &msg_type_, &opt_len);
     779           0 :                 write_opt = write_opt->GetNextOptionPtr();
     780           0 :                 break;
     781             : 
     782           0 :             case DHCP_OPTION_HOST_NAME:
     783           0 :                 config_.client_name_ = vm_itf_->vm_name();
     784           0 :                 write_opt->WriteData(DHCP_OPTION_HOST_NAME,
     785           0 :                                      config_.client_name_.size(),
     786           0 :                                      config_.client_name_.c_str(), &opt_len);
     787           0 :                 write_opt = write_opt->GetNextOptionPtr();
     788           0 :                 break;
     789             : 
     790           0 :             default:
     791           0 :                 write_opt->WriteData(read_opt->code, read_opt->len, &read_opt->data, &opt_len);
     792           0 :                 write_opt = write_opt->GetNextOptionPtr();
     793           0 :                 break;
     794             : 
     795             :         }
     796           0 :         opt_rem_len -= (2 + read_opt->len);
     797           0 :         read_opt = read_opt->GetNextOptionPtr();
     798             :     }
     799           0 :     dhcp_ = dhcp;
     800           0 :     option_->SetDhcpOptionPtr(dhcp_->options);
     801           0 :     dhcp->giaddr = htonl(agent()->router_id().to_ulong());
     802           0 :     WriteOption82(write_opt, &opt_len);
     803           0 :     write_opt = write_opt->GetNextOptionPtr();
     804           0 :     pkt_info_->sport = DHCP_SERVER_PORT;
     805           0 :     pkt_info_->dport = DHCP_SERVER_PORT;
     806           0 :     write_opt->WriteByte(DHCP_OPTION_END, &opt_len);
     807             : 
     808           0 :     uint32_t len = DHCP_FIXED_LEN + opt_len + eth_len + sizeof(udphdr);
     809             : 
     810           0 :     UdpHdr(len, in_pkt_info.ip->ip_src.s_addr, pkt_info_->sport,
     811           0 :            in_pkt_info.ip->ip_dst.s_addr, pkt_info_->dport);
     812           0 :     len += sizeof(struct ip);
     813           0 :     IpHdr(len, htonl(agent()->router_id().to_ulong()),
     814             :           0xFFFFFFFF, IPPROTO_UDP, DEFAULT_IP_ID, DEFAULT_IP_TTL);
     815             : 
     816           0 :     pkt_info_->set_len(len);
     817           0 :     return true;
     818           0 : }
     819             : 
     820           0 : bool DhcpHandler::CreateRelayResponsePacket() {
     821           0 :     PktInfo in_pkt_info = *pkt_info_.get();
     822           0 :     pkt_info_->AllocPacketBuffer(agent(), PktHandler::DHCP, DHCP_PKT_SIZE, 0);
     823           0 :     memset(pkt_info_->pkt, 0, DHCP_PKT_SIZE);
     824           0 :     pkt_info_->vrf = vm_itf_->vrf()->vrf_id();
     825           0 :     pkt_info_->eth = (struct ether_header *)(pkt_info_->pkt);
     826             : 
     827           0 :     uint16_t eth_len = 0;
     828           0 :     eth_len = EthHdr((char *)pkt_info_->eth, DHCP_PKT_SIZE, vm_itf_index_,
     829             :                      agent()->vhost_interface()->mac(),
     830           0 :                      MacAddress(dhcp_->chaddr), ETHERTYPE_IP);
     831             : 
     832           0 :     pkt_info_->ip = (struct ip *)((char *)pkt_info_->eth + eth_len);
     833           0 :     pkt_info_->transp.udp = (udphdr *)(pkt_info_->ip + 1);
     834           0 :     dhcphdr *dhcp = (dhcphdr *)(pkt_info_->transp.udp + 1);
     835             : 
     836           0 :     memcpy((uint8_t *)dhcp, (uint8_t *)dhcp_, DHCP_FIXED_LEN);
     837           0 :     memcpy(dhcp->options, DHCP_OPTIONS_COOKIE, 4);
     838             : 
     839           0 :     int16_t opt_rem_len = in_pkt_info.len - DHCP_FIXED_LEN - 4;
     840           0 :     uint16_t opt_len = 4;
     841           0 :     Dhcpv4Options *read_opt = (Dhcpv4Options *)(dhcp_->options + 4);
     842           0 :     Dhcpv4Options *write_opt = (Dhcpv4Options *)(dhcp->options + 4);
     843           0 :     while ((opt_rem_len > 0) && (read_opt->code != DHCP_OPTION_END)) {
     844           0 :         switch (read_opt->code) {
     845           0 :             case DHCP_OPTION_PAD:
     846           0 :                 write_opt->WriteByte(DHCP_OPTION_PAD, &opt_len);
     847           0 :                 write_opt = write_opt->GetNextOptionPtr();
     848           0 :                 opt_rem_len -= 1;
     849           0 :                 read_opt = read_opt->GetNextOptionPtr();
     850           0 :                 continue;
     851             : 
     852           0 :             case DHCP_OPTION_82:
     853           0 :                 break;
     854             : 
     855           0 :             case DHCP_OPTION_MSG_TYPE:
     856           0 :                 msg_type_ = *(uint8_t *)read_opt->data;
     857           0 :                 write_opt->WriteData(read_opt->code, read_opt->len, &msg_type_, &opt_len);
     858           0 :                 write_opt = write_opt->GetNextOptionPtr();
     859           0 :                 break;
     860             : 
     861           0 :             default:
     862           0 :                 write_opt->WriteData(read_opt->code, read_opt->len, &read_opt->data, &opt_len);
     863           0 :                 write_opt = write_opt->GetNextOptionPtr();
     864           0 :                 break;
     865             : 
     866             :         }
     867           0 :         opt_rem_len -= (2 + read_opt->len);
     868           0 :         read_opt = read_opt->GetNextOptionPtr();
     869             :     }
     870           0 :     dhcp_ = dhcp;
     871           0 :     option_->SetDhcpOptionPtr(dhcp_->options);
     872           0 :     dhcp->giaddr = 0;
     873           0 :     config_.client_name_ = vm_itf_->vm_name();
     874           0 :     write_opt->WriteData(DHCP_OPTION_HOST_NAME, config_.client_name_.size(),
     875           0 :                          config_.client_name_.c_str(), &opt_len);
     876           0 :     write_opt = write_opt->GetNextOptionPtr();
     877           0 :     pkt_info_->sport = DHCP_SERVER_PORT;
     878           0 :     pkt_info_->dport = DHCP_CLIENT_PORT;
     879           0 :     write_opt->WriteByte(DHCP_OPTION_END, &opt_len);
     880             : 
     881           0 :     uint32_t len = DHCP_FIXED_LEN + opt_len + sizeof(udphdr) + eth_len;
     882             : 
     883           0 :     UdpHdr(len, agent()->router_id().to_ulong(), pkt_info_->sport,
     884           0 :            0xFFFFFFFF, pkt_info_->dport);
     885           0 :     len += sizeof(struct ip);
     886           0 :     IpHdr(len, htonl(agent()->router_id().to_ulong()),
     887             :           0xFFFFFFFF, IPPROTO_UDP, DEFAULT_IP_ID, DEFAULT_IP_TTL);
     888             : 
     889           0 :     pkt_info_->set_len(len);
     890           0 :     return true;
     891           0 : }
     892             : 
     893           0 : void DhcpHandler::RelayRequestToFabric() {
     894           0 :     CreateRelayPacket();
     895           0 :     DhcpProto *dhcp_proto = agent()->GetDhcpProto();
     896           0 :     Send(dhcp_proto->ip_fabric_interface_index(), pkt_info_->vrf,
     897             :          AgentHdr::TX_SWITCH, PktHandler::DHCP);
     898           0 :     dhcp_proto->IncrStatsRelayReqs();
     899           0 : }
     900             : 
     901           0 : void DhcpHandler::RelayResponseFromFabric() {
     902           0 :     if (!CreateRelayResponsePacket()) {
     903           0 :         DHCP_TRACE(Trace, "Ignoring received DHCP packet from fabric interface");
     904           0 :         return;
     905             :     }
     906             : 
     907           0 :     if (msg_type_ == DHCP_ACK) {
     908             :         // Populate the DHCP Snoop table
     909             :         agent()->interface_table()->AddDhcpSnoopEntry
     910           0 :             (vm_itf_->name(), Ip4Address(ntohl(dhcp_->yiaddr)));
     911             :         // Enqueue RESYNC to update the IP address
     912           0 :         DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
     913           0 :         req.key.reset(new VmInterfaceKey(AgentKey::RESYNC, vm_itf_->GetUuid(),
     914           0 :                                          vm_itf_->name()));
     915           0 :         req.data.reset(new VmInterfaceIpAddressData());
     916           0 :         agent()->interface_table()->Enqueue(&req);
     917           0 :     }
     918             : 
     919           0 :     Send(vm_itf_index_, pkt_info_->vrf, AgentHdr::TX_SWITCH, PktHandler::DHCP);
     920           0 :     agent()->GetDhcpProto()->IncrStatsRelayResps();
     921             : }
     922             : 
     923             : // Add an IP address to the option
     924           0 : uint16_t DhcpHandler::AddIP(uint16_t opt_len, const std::string &input) {
     925           0 :     boost::system::error_code ec;
     926           0 :     uint32_t ip = Ip4Address::from_string(input, ec).to_ulong();
     927           0 :     if (!ec.value() && ip) {
     928           0 :         ip = htonl(ip);
     929           0 :         option_->AppendData(4, &ip, &opt_len);
     930             :     } else {
     931           0 :         DHCP_TRACE(Error, "Invalid DHCP option " << option_->GetCode() <<
     932             :                    " data : " << input << " for VM " <<
     933             :                    config_.ip_addr.to_string() << "; has to be IP address");
     934             :     }
     935           0 :     return opt_len;
     936             : }
     937             : 
     938             : // Add domain name from IPAM to the option
     939           0 : uint16_t DhcpHandler::AddDomainNameOption(uint16_t opt_len) {
     940           0 :     if (ipam_type_.ipam_dns_method == "virtual-dns-server") {
     941           0 :         if (is_dns_enabled() && config_.domain_name_.size()) {
     942           0 :             option_->WriteData(DHCP_OPTION_DOMAIN_NAME, 0, NULL, &opt_len);
     943           0 :             option_->AppendData(config_.domain_name_.size(),
     944           0 :                                 config_.domain_name_.c_str(), &opt_len);
     945             :         }
     946             :     }
     947           0 :     return opt_len;
     948             : }
     949             : 
     950           0 : uint16_t DhcpHandler::DhcpHdr(in_addr_t yiaddr, in_addr_t siaddr) {
     951           0 :     dhcp_->op = BOOT_REPLY;
     952           0 :     dhcp_->htype = HW_TYPE_ETHERNET;
     953           0 :     dhcp_->hlen = ETHER_ADDR_LEN;
     954           0 :     dhcp_->hops = 0;
     955           0 :     dhcp_->xid = request_.xid;
     956           0 :     dhcp_->secs = 0;
     957           0 :     dhcp_->flags = htons(request_.flags);
     958           0 :     dhcp_->ciaddr = 0;
     959           0 :     dhcp_->yiaddr = yiaddr;
     960           0 :     dhcp_->siaddr = siaddr;
     961           0 :     dhcp_->giaddr = 0;
     962           0 :     memset (dhcp_->chaddr, 0, DHCP_CHADDR_LEN);
     963           0 :     request_.mac_addr.ToArray(dhcp_->chaddr, ETHER_ADDR_LEN);
     964             :     // not supporting dhcp_->sname, dhcp_->file for now
     965           0 :     memset(dhcp_->sname, '\0', DHCP_NAME_LEN);
     966           0 :     memset(dhcp_->file, '\0', DHCP_FILE_LEN);
     967             : 
     968           0 :     memcpy(dhcp_->options, DHCP_OPTIONS_COOKIE, 4);
     969             : 
     970           0 :     uint16_t opt_len = 4;
     971           0 :     option_->SetNextOptionPtr(opt_len);
     972           0 :     option_->WriteData(DHCP_OPTION_MSG_TYPE, 1, &out_msg_type_, &opt_len);
     973             : 
     974           0 :     option_->SetNextOptionPtr(opt_len);
     975           0 :     option_->WriteData(DHCP_OPTION_SERVER_IDENTIFIER, 4, &siaddr, &opt_len);
     976             : 
     977           0 :     if (out_msg_type_ == DHCP_NAK) {
     978           0 :         option_->SetNextOptionPtr(opt_len);
     979           0 :         option_->WriteData(DHCP_OPTION_MESSAGE, nak_msg_.size(),
     980           0 :                             nak_msg_.data(), &opt_len);
     981             :     }
     982             :     else {
     983             : 
     984           0 :         if (config_.subnet_mask) {
     985           0 :             option_->SetNextOptionPtr(opt_len);
     986           0 :             uint32_t value = htonl(config_.subnet_mask);
     987           0 :             option_->WriteData(DHCP_OPTION_SUBNET_MASK, 4, &value, &opt_len);
     988             :         }
     989             : 
     990           0 :         if (config_.bcast_addr) {
     991           0 :             option_->SetNextOptionPtr(opt_len);
     992           0 :             uint32_t value = htonl(config_.bcast_addr);
     993           0 :             option_->WriteData(DHCP_OPTION_BCAST_ADDRESS, 4, &value, &opt_len);
     994             :         }
     995             : 
     996             :         // Add dhcp options coming from Config
     997           0 :         opt_len = AddConfigDhcpOptions(opt_len, false);
     998             : 
     999           0 :         if (msg_type_ != DHCP_INFORM &&
    1000           0 :             !is_flag_set(DHCP_OPTION_IP_LEASE_TIME)) {
    1001           0 :             option_->SetNextOptionPtr(opt_len);
    1002           0 :             uint32_t value = htonl(config_.lease_time);
    1003           0 :             option_->WriteData(DHCP_OPTION_IP_LEASE_TIME, 4, &value, &opt_len);
    1004             :         }
    1005             : 
    1006             :         // Add classless route option
    1007           0 :         option_->SetNextOptionPtr(opt_len);
    1008           0 :         opt_len = AddClasslessRouteOption(opt_len);
    1009             : 
    1010           0 :         if (IsRouterOptionNeeded()) {
    1011           0 :             option_->SetNextOptionPtr(opt_len);
    1012           0 :             opt_len = AddIpv4Option(DHCP_OPTION_ROUTER, opt_len,
    1013           0 :                                     routers_, 1, 0, 0);
    1014             :         }
    1015             : 
    1016           0 :         if (!is_flag_set(DHCP_OPTION_HOST_NAME) &&
    1017           0 :             config_.client_name_.size()) {
    1018           0 :             option_->SetNextOptionPtr(opt_len);
    1019           0 :             option_->WriteData(DHCP_OPTION_HOST_NAME, config_.client_name_.size(),
    1020           0 :                                config_.client_name_.c_str(), &opt_len);
    1021             :         }
    1022             : 
    1023           0 :         if (!is_flag_set(DHCP_OPTION_DNS)) {
    1024           0 :             uint16_t old_opt_len = opt_len;
    1025           0 :             option_->SetNextOptionPtr(opt_len);
    1026           0 :             option_->WriteData(DHCP_OPTION_DNS, 0, NULL, &opt_len);
    1027           0 :             opt_len = AddDnsServers(opt_len);
    1028             :             // if there was no DNS server, revert the option
    1029           0 :             if (opt_len == old_opt_len + option_->GetFixedLen())
    1030           0 :                 opt_len = old_opt_len;
    1031             :         }
    1032             : 
    1033           0 :         if (!is_flag_set(DHCP_OPTION_DOMAIN_NAME)) {
    1034           0 :             option_->SetNextOptionPtr(opt_len);
    1035           0 :             opt_len = AddDomainNameOption(opt_len);
    1036             :         }
    1037             : 
    1038             :         // update dhcp siaddr with stored value
    1039           0 :         if (is_flag_set(DHCP_OPTION_TFTP_SERVER_NAME)) {
    1040           0 :             dhcp_->siaddr = siaddr_tftp_;
    1041             :         }
    1042             :     }
    1043             : 
    1044           0 :     option_->SetNextOptionPtr(opt_len);
    1045           0 :     option_->SetCode(DHCP_OPTION_END);
    1046           0 :     opt_len += 1;
    1047             : 
    1048           0 :     return (DHCP_FIXED_LEN + opt_len);
    1049             : }
    1050             : 
    1051           0 : uint16_t DhcpHandler::FillDhcpResponse(const MacAddress &dest_mac,
    1052             :                                        in_addr_t src_ip, in_addr_t dest_ip,
    1053             :                                        in_addr_t siaddr, in_addr_t yiaddr) {
    1054           0 :     pkt_info_->eth = (struct ether_header *)(pkt_info_->pkt);
    1055             : 
    1056           0 :     uint16_t eth_len = 0;
    1057           0 :     eth_len = EthHdr((char *)pkt_info_->eth,
    1058           0 :                      pkt_info_->packet_buffer()->data_len(),
    1059             :                      GetInterfaceIndex(),
    1060             :                      agent()->vhost_interface()->mac(), dest_mac, ETHERTYPE_IP);
    1061             : 
    1062           0 :     pkt_info_->ip = (struct ip *)((char *)pkt_info_->eth + eth_len);
    1063           0 :     pkt_info_->transp.udp = (udphdr *)(pkt_info_->ip + 1);
    1064           0 :     dhcphdr *dhcp = (dhcphdr *)(pkt_info_->transp.udp + 1);
    1065           0 :     dhcp_ = dhcp;
    1066           0 :     option_->SetDhcpOptionPtr(dhcp_->options);
    1067             : 
    1068           0 :     uint16_t len = DhcpHdr(yiaddr, siaddr);
    1069           0 :     len += sizeof(udphdr);
    1070           0 :     UdpHdr(len, src_ip, DHCP_SERVER_PORT, dest_ip, DHCP_CLIENT_PORT);
    1071           0 :     len += sizeof(struct ip);
    1072           0 :     IpHdr(len, src_ip, dest_ip, IPPROTO_UDP, DEFAULT_IP_ID, DEFAULT_IP_TTL);
    1073             : 
    1074           0 :     pkt_info_->set_len(len + eth_len);
    1075           0 :     return pkt_info_->packet_buffer()->data_len();
    1076             : }
    1077             : 
    1078           0 : void DhcpHandler::SendDhcpResponse() {
    1079             :     // TODO: If giaddr is set, what to do ?
    1080             : 
    1081             :     // In TSN, the source address for DHCP response should be the address
    1082             :     // in the subnet reserved for service node. Otherwise, it will be the
    1083             :     // GW address. dns_addr field has this address, use it as the source IP.
    1084           0 :     in_addr_t src_ip = htonl(config_.dns_addr.to_v4().to_ulong());
    1085           0 :     in_addr_t dest_ip = 0xFFFFFFFF;
    1086           0 :     in_addr_t yiaddr = htonl(config_.ip_addr.to_v4().to_ulong());
    1087           0 :     in_addr_t siaddr = src_ip;
    1088           0 :     MacAddress dest_mac = MacAddress::BroadcastMac();
    1089             : 
    1090             :     // If requested IP address is not available, send NAK
    1091           0 :     if ((msg_type_ == DHCP_REQUEST) && (request_.ip_addr) &&
    1092           0 :         (config_.ip_addr.to_v4().to_ulong() != request_.ip_addr)) {
    1093           0 :         out_msg_type_ = DHCP_NAK;
    1094           0 :         yiaddr = 0;
    1095           0 :         siaddr = 0;
    1096             :     }
    1097             : 
    1098             :     // send a unicast response when responding to INFORM
    1099             :     // or when incoming giaddr is zero and ciaddr is set
    1100             :     // or when incoming bcast flag is not set (with giaddr & ciaddr being zero)
    1101           0 :     if ((msg_type_ == DHCP_INFORM) ||
    1102           0 :         (!dhcp_->giaddr && (dhcp_->ciaddr ||
    1103           0 :                             !(request_.flags & DHCP_BCAST_FLAG)))) {
    1104           0 :         dest_ip = yiaddr;
    1105           0 :         dest_mac = dhcp_->chaddr;
    1106           0 :         if (msg_type_ == DHCP_INFORM)
    1107           0 :             yiaddr = 0;
    1108             :     }
    1109             : 
    1110           0 :     UpdateStats();
    1111             : 
    1112           0 :     FillDhcpResponse(dest_mac, src_ip, dest_ip, siaddr, yiaddr);
    1113             :     uint32_t interface =
    1114           0 :         (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
    1115           0 :         agent_->GetDhcpProto()->pkt_interface_index() : GetInterfaceIndex();
    1116             :     uint16_t command =
    1117           0 :         (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
    1118           0 :         (uint16_t)AgentHdr::TX_ROUTE : AgentHdr::TX_SWITCH;
    1119           0 :     Send(interface, pkt_info_->vrf, command, PktHandler::DHCP);
    1120           0 : }
    1121             : 
    1122             : // Check if the option is requested by the client or not
    1123           0 : bool DhcpHandler::IsOptionRequested(uint8_t option) {
    1124           0 :     for (uint32_t i = 0; i < parameters_.size(); i++) {
    1125           0 :         if (parameters_[i] == option)
    1126           0 :             return true;
    1127             :     }
    1128           0 :     return false;
    1129             : }
    1130             : 
    1131           0 : bool DhcpHandler::IsRouterOptionNeeded() {
    1132             :     // If GW is not configured, dont include
    1133           0 :     if (config_.gw_addr.is_unspecified() && routers_.empty())
    1134           0 :         return false;
    1135             : 
    1136             :     // When client requests Classless Static Routes option and this is
    1137             :     // included in the response, Router option is not included (RFC3442)
    1138           0 :     if (IsOptionRequested(DHCP_OPTION_CLASSLESS_ROUTE) &&
    1139           0 :         is_flag_set(DHCP_OPTION_CLASSLESS_ROUTE))
    1140           0 :         return false;
    1141             : 
    1142           0 :     return true;
    1143             : }
    1144             : 
    1145           0 : void DhcpHandler::UpdateStats() {
    1146           0 :     DhcpProto *dhcp_proto = agent()->GetDhcpProto();
    1147           0 :     (out_msg_type_ == DHCP_OFFER) ? dhcp_proto->IncrStatsOffers() :
    1148           0 :         ((out_msg_type_ == DHCP_ACK) ? dhcp_proto->IncrStatsAcks() :
    1149           0 :                                        dhcp_proto->IncrStatsNacks());
    1150           0 : }
    1151             : 
    1152             : DhcpHandler::DhcpOptionCategory
    1153           0 : DhcpHandler::OptionCategory(uint32_t option) const {
    1154           0 :     Dhcpv4CategoryIter iter = g_dhcpv4_category_map.find(option);
    1155           0 :     if (iter == g_dhcpv4_category_map.end())
    1156           0 :         return None;
    1157           0 :     return iter->second;
    1158             : }
    1159             : 
    1160           0 : uint32_t DhcpHandler::OptionCode(const std::string &option) const {
    1161             :     // if the option name is a number, use it as DHCP code
    1162             :     // otherwise, use it as option name
    1163           0 :     std::stringstream str(option);
    1164             : 
    1165           0 :     uint32_t code = 0;
    1166           0 :     str >> code;
    1167           0 :     if (code) return code;
    1168             : 
    1169             :     Dhcpv4NameCodeIter iter =
    1170           0 :         g_dhcpv4_namecode_map.find(boost::to_lower_copy(option));
    1171             : 
    1172           0 :     if(iter != g_dhcpv4_namecode_map.end()){
    1173           0 :         return iter->second;
    1174             :     }
    1175             : 
    1176           0 :     std::stringstream str_new(option);
    1177             :     //Checking if there is comma in the option
    1178           0 :     bool is_delimeter_set = false;
    1179           0 :     while(!(str_new.eof())){
    1180           0 :         str_new.get();
    1181           0 :         if (str_new.peek() == ','){
    1182           0 :             is_delimeter_set = true;
    1183             :         }
    1184             :     }
    1185           0 :     std::stringstream str_orig(option);
    1186             :     //If option name has a comma in it,
    1187             :     //eg: tag:!ipxe,67 , we should pick 67
    1188           0 :         if(is_delimeter_set){
    1189           0 :             vector<string> v;
    1190           0 :             while (str_orig.good()) {
    1191           0 :                 string substr;
    1192           0 :                 getline(str_orig, substr, ',');
    1193           0 :                 v.push_back(substr);
    1194           0 :             }
    1195           0 :             std::stringstream str_temp(v[1]);
    1196           0 :             str_temp >> code;
    1197           0 :            }
    1198             : 
    1199           0 :     return code;
    1200           0 : }
    1201             : 
    1202             : 
    1203           0 : void DhcpHandler::DhcpTrace(const std::string &msg) const {
    1204           0 :     DHCP_TRACE(Error, "VM " << config_.ip_addr.to_string() << " : " << msg);
    1205           0 : }

Generated by: LCOV version 1.14