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