1*0Sstevel@tonic-gate# 2*0Sstevel@tonic-gate# CDDL HEADER START 3*0Sstevel@tonic-gate# 4*0Sstevel@tonic-gate# The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate# Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate# (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate# with the License. 8*0Sstevel@tonic-gate# 9*0Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate# See the License for the specific language governing permissions 12*0Sstevel@tonic-gate# and limitations under the License. 13*0Sstevel@tonic-gate# 14*0Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate# 20*0Sstevel@tonic-gate# CDDL HEADER END 21*0Sstevel@tonic-gate# 22*0Sstevel@tonic-gate# 23*0Sstevel@tonic-gate# Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate# Use is subject to license terms. 25*0Sstevel@tonic-gate# 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gateThe DHCP server cache implementation 28*0Sstevel@tonic-gateZhenghui.Xie@sun.com 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate#ident "%Z%%M% %I% %E% SMI" 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gateINTRODUCTION 34*0Sstevel@tonic-gate============ 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gateThe Solaris DHCP server implements a caching mechanism to: 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate * Ensure the ACK is consistent with the original OFFER, so that 39*0Sstevel@tonic-gate subsequent requests get the same answer. 40*0Sstevel@tonic-gate * Ensure the same IP address isn't offered to a different client. 41*0Sstevel@tonic-gate * Improve performance by reducing the frequency of datastore lookups. 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gateIMPLEMENTATION OVERVIEW 44*0Sstevel@tonic-gate======================= 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gateThe cache implementation consists of a number of hash tables and lists, 47*0Sstevel@tonic-gateenumerated below, along with a timeout and refresh mechanism: 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate * A global DHCP table hash (ntable): 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate Each active network table (dvsc_dnet_t) is hashed by subnet number 52*0Sstevel@tonic-gate into a global hash called 'ntable'. The dsvc_dnet_t itself 53*0Sstevel@tonic-gate contains a variety of information about each subnet, an access 54*0Sstevel@tonic-gate handle to the underlying datastore, and a variety of caches which 55*0Sstevel@tonic-gate we describe next. 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate An ntable hash entry will be removed after DHCP_NET_THRESHOLD 58*0Sstevel@tonic-gate seconds of inactivity. 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate * A per-network client hash (ctable): 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate Each client structure (dsvc_clnt_t) is hashed by client identifier 63*0Sstevel@tonic-gate into the per-network ctable. This table is used by the interface 64*0Sstevel@tonic-gate worker thread to get client information. 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate A ctable hash entry will be removed if the client does not communicate 67*0Sstevel@tonic-gate with the server for DHCP_CLIENT_THRESHOLD seconds. 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate * A per-network offer hash (itable): 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate The IP address associated with each pending OFFER is hashed into 72*0Sstevel@tonic-gate the per-network itable. This table is used to reserve the offered 73*0Sstevel@tonic-gate and in-use IP addresses on the given network. 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate An itable hash entry will be removed if more than DSVC_CV_OFFER_TTL 76*0Sstevel@tonic-gate seconds elapse without update_offer() being called on it. 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate * A per-network free record list (freerec): 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate This is a cache of free records, populated with any unused records 81*0Sstevel@tonic-gate retrieved from previous datastore lookups or from IP addresses that 82*0Sstevel@tonic-gate have been explicitly released by DHCP clients. This is the first 83*0Sstevel@tonic-gate list select_offer() consults. 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate An entry in the freerec list expires after DSVC_CV_CACHE_TTL seconds. 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate * A per-network least recently used record list (lrurec) 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate This is a cache of least recently used records, populated with any 90*0Sstevel@tonic-gate unused records retrieved from a previous datastore lookup for 91*0Sstevel@tonic-gate LRU records. This is the second list select_offer() consults, after 92*0Sstevel@tonic-gate checking freerec. 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate An entry in the lrurec list expires after DSVC_CV_CACHE_TTL seconds. 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gateThe concurrency between the datastore and cached records is handled by the 97*0Sstevel@tonic-gateunderlying datastore implementation using perimeters and is transparent to 98*0Sstevel@tonic-gatein.dhcpd. $SRC/lib/libdhcpsvc/private/{private.c,public.c} implement the 99*0Sstevel@tonic-gatefunctions used by in.dhcpd and DHCP server admin tools to lookup and modify 100*0Sstevel@tonic-gatethe underlying datastore records. 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gateTRANSACTIONS 103*0Sstevel@tonic-gate============ 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gateWhen in.dhcpd receives a packet from a client, the interface thread first 106*0Sstevel@tonic-gatecalls open_dnet() to retrieve the dsvc_dnet_t which describes the network. 107*0Sstevel@tonic-gateThe dsvc_dnet_t is either in the ntable hash, in which case it is returned, 108*0Sstevel@tonic-gateor a new dsvc_dnet_t is allocated and inserted to ntable. Then, using the 109*0Sstevel@tonic-gatedsvc_dnet_t, the interface thread calls open_clnt(), which searches the 110*0Sstevel@tonic-gatedsvc_dnet_t's ctable hash and returns the client structure (dsvc_clnt_t) if 111*0Sstevel@tonic-gatefound. Otherwise, a new dsvc_clnt_t is allocated and inserted into the 112*0Sstevel@tonic-gatectable. Finally, the packet is put to the client's packet list so that the 113*0Sstevel@tonic-gateclient thread can process it. 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gateThe client thread then processes the packet according to whether it's a 116*0Sstevel@tonic-gateDISCOVER, REQUEST, RELEASE, or DECLINE. 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gateFor a DISCOVER: 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate 1. If there is a pre-assigned IP for this client and the cached offer 121*0Sstevel@tonic-gate is not timed out, then use the IP and the record in the 122*0Sstevel@tonic-gate dsvc_clnt_t and make an OFFER. 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate 2. If there is a pre-assigned IP but the cached offer is expired, 125*0Sstevel@tonic-gate remove the cached OFFER from the itable, and try to find a new 126*0Sstevel@tonic-gate record for the client (see below). 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate 3. If there is no pre-assigned IP for this client, just try to find 129*0Sstevel@tonic-gate a new record for the client (see following text). 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate To find a new record, the client thread first searches the datastore 132*0Sstevel@tonic-gate for a record matching the client identifier provided in the packet. 133*0Sstevel@tonic-gate If none is found, then the free record list (freerec) and least 134*0Sstevel@tonic-gate recently used record list (lrurec) are searched, in that order. If 135*0Sstevel@tonic-gate either freerec or lrurec is empty, or the head record on either list 136*0Sstevel@tonic-gate is expired, in.dhcpd removes any existing records and attempts to 137*0Sstevel@tonic-gate repopulate them by performing datastore lookups. Finally, any 138*0Sstevel@tonic-gate unused records are cached for later use. 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate If a usable record is found, the server generates and sends an OFFER 141*0Sstevel@tonic-gate to the client. Once sent, the client's dsvc_clnt_t is inserted to 142*0Sstevel@tonic-gate the dsvc_dnet_t's itable if it is a new IP, or the itable is refreshed 143*0Sstevel@tonic-gate if it is a pre-assigned IP. 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gateFor a REQUEST: 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate 1. If the REQUEST is a reply to a previous OFFER, it checks if the 148*0Sstevel@tonic-gate OFFER has expired. If not, the itable timer is reset, the client 149*0Sstevel@tonic-gate record is updated, and the ACK is sent. If it is expired and the 150*0Sstevel@tonic-gate address cannot be confirmed to still be free, the REQUEST is 151*0Sstevel@tonic-gate silently ignored (and the client should eventually drop back 152*0Sstevel@tonic-gate to DISCOVER). 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate 2. If the REQUEST is associated with a client INIT-REBOOT or a client 155*0Sstevel@tonic-gate extending a lease, then the client thread does a datastore lookup 156*0Sstevel@tonic-gate by client identifier. If a match is found, the record is updated 157*0Sstevel@tonic-gate and an ACK is sent. 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gateIf the packet is a RELEASE, the client thread modifies the record in the 160*0Sstevel@tonic-gatedatastore so that it is marked free, and, if successful, puts the record onto 161*0Sstevel@tonic-gatethe free record list (freerec). 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gateFinally, if the packet is a DECLINE, the client thread modifies the record in 164*0Sstevel@tonic-gatethe datastore so that it is marked unusable. 165