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

Generated by: LCOV version 1.14