xref: /onnv-gate/usr/src/cmd/cmd-inet/sbin/dhcpagent/README (revision 5381:6bff17151099)
10Sstevel@tonic-gateCDDL HEADER START
20Sstevel@tonic-gate
30Sstevel@tonic-gateThe contents of this file are subject to the terms of the
43431ScarlsonjCommon Development and Distribution License (the "License").
53431ScarlsonjYou may not use this file except in compliance with the License.
60Sstevel@tonic-gate
70Sstevel@tonic-gateYou can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
80Sstevel@tonic-gateor http://www.opensolaris.org/os/licensing.
90Sstevel@tonic-gateSee the License for the specific language governing permissions
100Sstevel@tonic-gateand limitations under the License.
110Sstevel@tonic-gate
120Sstevel@tonic-gateWhen distributing Covered Code, include this CDDL HEADER in each
130Sstevel@tonic-gatefile and include the License file at usr/src/OPENSOLARIS.LICENSE.
140Sstevel@tonic-gateIf applicable, add the following below this CDDL HEADER, with the
150Sstevel@tonic-gatefields enclosed by brackets "[]" replaced with your own identifying
160Sstevel@tonic-gateinformation: Portions Copyright [yyyy] [name of copyright owner]
170Sstevel@tonic-gate
180Sstevel@tonic-gateCDDL HEADER END
190Sstevel@tonic-gate
203431ScarlsonjCopyright 2007 Sun Microsystems, Inc.  All rights reserved.
210Sstevel@tonic-gateUse is subject to license terms.
220Sstevel@tonic-gate
230Sstevel@tonic-gateArchitectural Overview for the DHCP agent
240Sstevel@tonic-gatePeter Memishian
250Sstevel@tonic-gateident	"%Z%%M%	%I%	%E% SMI"
260Sstevel@tonic-gate
270Sstevel@tonic-gateINTRODUCTION
280Sstevel@tonic-gate============
290Sstevel@tonic-gate
303431ScarlsonjThe Solaris DHCP agent (dhcpagent) is a DHCP client implementation
313431Scarlsonjcompliant with RFCs 2131, 3315, and others.  The major forces shaping
323431Scarlsonjits design were:
330Sstevel@tonic-gate
340Sstevel@tonic-gate	* Must be capable of managing multiple network interfaces.
350Sstevel@tonic-gate	* Must consume little CPU, since it will always be running.
360Sstevel@tonic-gate	* Must have a small memory footprint, since it will always be
370Sstevel@tonic-gate	  running.
383431Scarlsonj	* Must not rely on any shared libraries outside of /lib, since
393431Scarlsonj	  it must run before all filesystems have been mounted.
400Sstevel@tonic-gate
410Sstevel@tonic-gateWhen a DHCP agent implementation is only required to control a single
420Sstevel@tonic-gateinterface on a machine, the problem is expressed well as a simple
430Sstevel@tonic-gatestate-machine, as shown in RFC2131.  However, when a DHCP agent is
440Sstevel@tonic-gateresponsible for managing more than one interface at a time, the
453431Scarlsonjproblem becomes much more complicated.
463431Scarlsonj
473431ScarlsonjThis can be resolved using threads or with an event-driven model.
483431ScarlsonjGiven that DHCP's behavior can be expressed concisely as a state
493431Scarlsonjmachine, the event-driven model is the closest match.
503431Scarlsonj
513431ScarlsonjWhile tried-and-true, that model is subtle and easy to get wrong.
523431ScarlsonjIndeed, much of the agent's code is there to manage the complexity of
533431Scarlsonjprogramming in an asynchronous event-driven paradigm.
540Sstevel@tonic-gate
550Sstevel@tonic-gateTHE BASICS
560Sstevel@tonic-gate==========
570Sstevel@tonic-gate
583431ScarlsonjThe DHCP agent consists of roughly 30 source files, most with a
593431Scarlsonjcompanion header file.  While the largest source file is around 1700
600Sstevel@tonic-gatelines, most are much shorter.  The source files can largely be broken
610Sstevel@tonic-gateup into three groups:
620Sstevel@tonic-gate
633431Scarlsonj	* Source files that, along with their companion header files,
640Sstevel@tonic-gate	  define an abstract "object" that is used by other parts of
653431Scarlsonj	  the system.  Examples include "packet.c", which along with
663431Scarlsonj	  "packet.h" provide a Packet object for use by the rest of
673431Scarlsonj	  the agent; and "async.c", which along with "async.h" defines
683431Scarlsonj	  an interface for managing asynchronous transactions within
693431Scarlsonj	  the agent.
700Sstevel@tonic-gate
713431Scarlsonj	* Source files that implement a given state of the agent; for
720Sstevel@tonic-gate	  instance, there is a "request.c" which comprises all of
730Sstevel@tonic-gate	  the procedural "work" which must be done while in the
740Sstevel@tonic-gate	  REQUESTING state of the agent.  By encapsulating states in
750Sstevel@tonic-gate	  files, it becomes easier to debug errors in the
760Sstevel@tonic-gate	  client/server protocol and adapt the agent to new
770Sstevel@tonic-gate	  constraints, since all the relevant code is in one place.
780Sstevel@tonic-gate
790Sstevel@tonic-gate	* Source files, which along with their companion header files,
800Sstevel@tonic-gate  	  encapsulate a given task or related set of tasks.  The
810Sstevel@tonic-gate	  difference between this and the first group is that the
820Sstevel@tonic-gate	  interfaces exported from these files do not operate on
830Sstevel@tonic-gate	  an "object", but rather perform a specific task.  Examples
84*5381Smeem	  include "defaults.c", which provides a useful interface
85*5381Smeem	  to /etc/default/dhcpagent file operations.
860Sstevel@tonic-gate
870Sstevel@tonic-gateOVERVIEW
880Sstevel@tonic-gate========
890Sstevel@tonic-gate
900Sstevel@tonic-gateHere we discuss the essential objects and subtle aspects of the
910Sstevel@tonic-gateDHCP agent implementation.  Note that there is of course much more
920Sstevel@tonic-gatethat is not discussed here, but after this overview you should be able
930Sstevel@tonic-gateto fend for yourself in the source code.
940Sstevel@tonic-gate
953431ScarlsonjFor details on the DHCPv6 aspects of the design, and how this relates
963431Scarlsonjto the implementation present in previous releases of Solaris, see the
973431ScarlsonjREADME.v6 file.
983431Scarlsonj
990Sstevel@tonic-gateEvent Handlers and Timer Queues
1000Sstevel@tonic-gate-------------------------------
1010Sstevel@tonic-gate
1020Sstevel@tonic-gateThe most important object in the agent is the event handler, whose
1030Sstevel@tonic-gateinterface is in libinetutil.h and whose implementation is in
1040Sstevel@tonic-gatelibinetutil.  The event handler is essentially an object-oriented
1050Sstevel@tonic-gatewrapper around poll(2): other components of the agent can register to
1060Sstevel@tonic-gatebe called back when specific events on file descriptors happen -- for
1070Sstevel@tonic-gateinstance, to wait for requests to arrive on its IPC socket, the agent
1080Sstevel@tonic-gateregisters a callback function (accept_event()) that will be called
1090Sstevel@tonic-gateback whenever a new connection arrives on the file descriptor
1100Sstevel@tonic-gateassociated with the IPC socket.  When the agent initially begins in
1110Sstevel@tonic-gatemain(), it registers a number of events with the event handler, and
1120Sstevel@tonic-gatethen calls iu_handle_events(), which proceeds to wait for events to
1130Sstevel@tonic-gatehappen -- this function does not return until the agent is shutdown
1140Sstevel@tonic-gatevia signal.
1150Sstevel@tonic-gate
1160Sstevel@tonic-gateWhen the registered events occur, the callback functions are called
1170Sstevel@tonic-gateback, which in turn might lead to additional callbacks being
1180Sstevel@tonic-gateregistered -- this is the classic event-driven model.  (As an aside,
1190Sstevel@tonic-gatenote that programming in an event-driven model means that callbacks
1200Sstevel@tonic-gatecannot block, or else the agent will become unresponsive.)
1210Sstevel@tonic-gate
1220Sstevel@tonic-gateA special kind of "event" is a timeout.  Since there are many timers
1230Sstevel@tonic-gatewhich must be maintained for each DHCP-controlled interface (such as a
1240Sstevel@tonic-gatelease expiration timer, time-to-first-renewal (t1) timer, and so
1250Sstevel@tonic-gateforth), an object-oriented abstraction to timers called a "timer
1260Sstevel@tonic-gatequeue" is provided, whose interface is in libinetutil.h with a
1270Sstevel@tonic-gatecorresponding implementation in libinetutil.  The timer queue allows
1280Sstevel@tonic-gatecallback functions to be "scheduled" for callback after a certain
1290Sstevel@tonic-gateamount of time has passed.
1300Sstevel@tonic-gate
1310Sstevel@tonic-gateThe event handler and timer queue objects work hand-in-hand: the event
1320Sstevel@tonic-gatehandler is passed a pointer to a timer queue in iu_handle_events() --
1330Sstevel@tonic-gatefrom there, it can use the iu_earliest_timer() routine to find the
1340Sstevel@tonic-gatetimer which will next fire, and use this to set its timeout value in
1350Sstevel@tonic-gateits call to poll(2).  If poll(2) returns due to a timeout, the event
1360Sstevel@tonic-gatehandler calls iu_expire_timers() to expire all timers that expired
1370Sstevel@tonic-gate(note that more than one may have expired if, for example, multiple
1380Sstevel@tonic-gatetimers were set to expire at the same time).
1390Sstevel@tonic-gate
1400Sstevel@tonic-gateAlthough it is possible to instantiate more than one timer queue or
1410Sstevel@tonic-gateevent handler object, it doesn't make a lot of sense -- these objects
1420Sstevel@tonic-gateare really "singletons".  Accordingly, the agent has two global
1430Sstevel@tonic-gatevariables, `eh' and `tq', which store pointers to the global event
1440Sstevel@tonic-gatehandler and timer queue.
1450Sstevel@tonic-gate
1460Sstevel@tonic-gateNetwork Interfaces
1470Sstevel@tonic-gate------------------
1480Sstevel@tonic-gate
1490Sstevel@tonic-gateFor each network interface managed by the agent, there is a set of
1500Sstevel@tonic-gateassociated state that describes both its general properties (such as
1513431Scarlsonjthe maximum MTU) and its connections to DHCP-related state (the
1523431Scarlsonjprotocol state machines).  This state is stored in a pair of
1533431Scarlsonjstructures called `dhcp_pif_t' (the IP physical interface layer or
1543431ScarlsonjPIF) and `dhcp_lif_t' (the IP logical interface layer or LIF).  Each
1553431Scarlsonjdhcp_pif_t represents a single physical interface, such as "hme0," for
1563431Scarlsonja given IP protocol version (4 or 6), and has a list of dhcp_lif_t
1573431Scarlsonjstructures representing the logical interfaces (such as "hme0:1") in
1583431Scarlsonjuse by the agent.
1593431Scarlsonj
1603431ScarlsonjThis split is important because of differences between IPv4 and IPv6.
1613431ScarlsonjFor IPv4, each DHCP state machine manages a single IP address and
1623431Scarlsonjassociated configuration data.  This corresponds to a single logical
1633431Scarlsonjinterface, which must be specified by the user.  For IPv6, however,
1643431Scarlsonjeach DHCP state machine manages a group of addresses, and is
1653431Scarlsonjassociated with DUID value rather than with just an interface.
1663431Scarlsonj
1673431ScarlsonjThus, DHCPv6 behaves more like in.ndpd in its creation of "ADDRCONF"
1683431Scarlsonjinterfaces.  The agent automatically plumbs logical interfaces when
1693431Scarlsonjneeded and removes them when the addresses expire.
1703431Scarlsonj
1713431ScarlsonjThe state for a given session is stored separately in `dhcp_smach_t'.
1723431ScarlsonjThis state machine then points to the main LIF used for I/O, and to a
1733431Scarlsonjlist of `dhcp_lease_t' structures representing individual leases, and
1743431Scarlsonjeach of those points to a list of LIFs corresponding to the individual
1753431Scarlsonjaddresses being managed.
1760Sstevel@tonic-gate
1770Sstevel@tonic-gateOne point that was brushed over in the preceding discussion of event
1780Sstevel@tonic-gatehandlers and timer queues was context.  Recall that the event-driven
1790Sstevel@tonic-gatenature of the agent requires that functions cannot block, lest they
1800Sstevel@tonic-gatestarve out others and impact the observed responsiveness of the agent.
1810Sstevel@tonic-gateAs an example, consider the process of extending a lease: the agent
1820Sstevel@tonic-gatemust send a REQUEST packet and wait for an ACK or NAK packet in
1833431Scarlsonjresponse.  This is done by sending a REQUEST and then returning to the
1843431Scarlsonjevent handler that waits for an ACK or NAK packet to arrive on the
1853431Scarlsonjfile descriptor associated with the interface.  Note however, that
1863431Scarlsonjwhen the ACK or NAK does arrive, and the callback function called
1873431Scarlsonjback, it must know which state machine this packet is for (it must get
1883431Scarlsonjback its context).  This could be handled through an ad-hoc mapping of
1893431Scarlsonjfile descriptors to state machines, but a cleaner approach is to have
1903431Scarlsonjthe event handler's register function (iu_register_event()) take in an
1913431Scarlsonjopaque context pointer, which will then be passed back to the
1923431Scarlsonjcallback.  In the agent, the context pointer used depends on the
1933431Scarlsonjnature of the event: events on LIFs use the dhcp_lif_t pointer, events
1943431Scarlsonjon the state machine use dhcp_smach_t, and so on.
1950Sstevel@tonic-gate
1960Sstevel@tonic-gateNote that there is nothing that guarantees the pointer passed into
1970Sstevel@tonic-gateiu_register_event() or iu_schedule_timer() will still be valid when
1980Sstevel@tonic-gatethe callback is called back (for instance, the memory may have been
1993431Scarlsonjfreed in the meantime).  To solve this problem, all of the data
2003431Scarlsonjstructures used in this way are reference counted.  For more details
2013431Scarlsonjon how the reference count scheme is implemented, see the closing
2023431Scarlsonjcomments in interface.h regarding memory management.
2030Sstevel@tonic-gate
2040Sstevel@tonic-gateTransactions
2050Sstevel@tonic-gate------------
2060Sstevel@tonic-gate
2070Sstevel@tonic-gateMany operations performed via DHCP must be performed in groups -- for
2080Sstevel@tonic-gateinstance, acquiring a lease requires several steps: sending a
2090Sstevel@tonic-gateDISCOVER, collecting OFFERs, selecting an OFFER, sending a REQUEST,
2100Sstevel@tonic-gateand receiving an ACK, assuming everything goes well.  Note however
2110Sstevel@tonic-gatethat due to the event-driven model the agent operates in, these
2120Sstevel@tonic-gateoperations are not inherently "grouped" -- instead, the agent sends a
2130Sstevel@tonic-gateDISCOVER, goes back into the main event loop, waits for events
2140Sstevel@tonic-gate(perhaps even requests on the IPC channel to begin acquiring a lease
2153431Scarlsonjon another state machine), eventually checks to see if an acceptable
2163431ScarlsonjOFFER has come in, and so forth.  To some degree, the notion of the
2173431Scarlsonjstate machine's current state (SELECTING, REQUESTING, etc) helps
2183431Scarlsonjcontrol the potential chaos of the event-driven model (for instance,
2193431Scarlsonjif while the agent is waiting for an OFFER on a given state machine,
2203431Scarlsonjan IPC event comes in requesting that the leases be RELEASED, the
2213431Scarlsonjagent knows to send back an error since the state machine must be in
2223431Scarlsonjat least the BOUND state before a RELEASE can be performed.)
2230Sstevel@tonic-gate
2240Sstevel@tonic-gateHowever, states are not enough -- for instance, suppose that the agent
2253431Scarlsonjbegins trying to renew a lease.  This is done by sending a REQUEST
2260Sstevel@tonic-gatepacket and waiting for an ACK or NAK, which might never come.  If,
2270Sstevel@tonic-gatewhile waiting for the ACK or NAK, the user sends a request to renew
2280Sstevel@tonic-gatethe lease as well, then if the agent were to send another REQUEST,
2290Sstevel@tonic-gatethings could get quite complicated (and this is only the beginning of
2300Sstevel@tonic-gatethis rathole).  To protect against this, two objects exist:
2310Sstevel@tonic-gate`async_action' and `ipc_action'.  These objects are related, but
2320Sstevel@tonic-gateindependent of one another; the more essential object is the
2330Sstevel@tonic-gate`async_action', which we will discuss first.
2340Sstevel@tonic-gate
2350Sstevel@tonic-gateIn short, an `async_action' represents a pending transaction (aka
2363431Scarlsonjasynchronous action), of which each state machine can have at most
2373431Scarlsonjone.  The `async_action' structure is embedded in the `dhcp_smach_t'
2383431Scarlsonjstructure, which is fine since there can be at most one pending
2393431Scarlsonjtransaction per state machine.  Typical "asynchronous transactions"
2403431Scarlsonjare START, EXTEND, and INFORM, since each consists of a sequence of
2413431Scarlsonjpackets that must be done without interruption.  Note that not all
2423431ScarlsonjDHCP operations are "asynchronous" -- for instance, a DHCPv4 RELEASE
2433431Scarlsonjoperation is synchronous (not asynchronous) since after the RELEASE is
2443431Scarlsonjsent no reply is expected from the DHCP server, but DHCPv6 Release is
2453431Scarlsonjasynchronous, as all DHCPv6 messages are transactional.  Some
2463431Scarlsonjoperations, such as status query, are synchronous and do not affect
2473431Scarlsonjthe system state, and thus do not require sequencing.
2480Sstevel@tonic-gate
2490Sstevel@tonic-gateWhen the agent realizes it must perform an asynchronous transaction,
2503431Scarlsonjit calls async_async() to open the transaction.  If one is already
2513431Scarlsonjpending, then the new transaction must fail (the details of failure
2523431Scarlsonjdepend on how the transaction was initiated, which is described in
2533431Scarlsonjmore detail later when the `ipc_action' object is discussed).  If
2543431Scarlsonjthere is no pending asynchronous transaction, the operation succeeds.
2550Sstevel@tonic-gate
2563431ScarlsonjWhen the transaction is complete, either async_finish() or
2573431Scarlsonjasync_cancel() must be called to complete or cancel the asynchronous
2583431Scarlsonjaction on that state machine.  If the transaction is unable to
2593431Scarlsonjcomplete within a certain amount of time (more on this later), a timer
2603431Scarlsonjshould be used to cancel the operation.
2610Sstevel@tonic-gate
2620Sstevel@tonic-gateThe notion of asynchronous transactions is complicated by the fact
2630Sstevel@tonic-gatethat they may originate from both inside and outside of the agent.
2640Sstevel@tonic-gateFor instance, a user initiates an asynchronous START transaction when
2650Sstevel@tonic-gatehe performs an `ifconfig hme0 dhcp start', but the agent will
2660Sstevel@tonic-gateinternally need to perform asynchronous EXTEND transactions to extend
2673431Scarlsonjthe lease before it expires.  Note that user-initiated actions always
2683431Scarlsonjhave priority over internal actions: the former will cancel the
2693431Scarlsonjlatter, if necessary.
2700Sstevel@tonic-gate
2713431ScarlsonjThis leads us into the `ipc_action' object.  An `ipc_action'
2723431Scarlsonjrepresents the IPC-related pieces of an asynchronous transaction that
2733431Scarlsonjwas started as a result of a user request, as well as the `BUSY' state
2743431Scarlsonjof the administrative interface.  Only IPC-generated asynchronous
2753431Scarlsonjtransactions have a valid `ipc_action' object.  Note that since there
2763431Scarlsonjcan be at most one asynchronous action per state machine, there can
2773431Scarlsonjalso be at most one `ipc_action' per state machine (this means it can
2783431Scarlsonjalso conveniently be embedded inside the `dhcp_smach_t' structure).
2793431Scarlsonj
2803431ScarlsonjOne of the main purposes of the `ipc_action' object is to timeout user
2813431Scarlsonjevents.  When the user specifies a timeout value as an argument to
2823431Scarlsonjifconfig, he is specifying an `ipc_action' timeout; in other words,
2833431Scarlsonjhow long he is willing to wait for the command to complete.  When this
2843431Scarlsonjtime expires, the ipc_action is terminated, as well as the
2853431Scarlsonjasynchronous operation.
2860Sstevel@tonic-gate
2870Sstevel@tonic-gateThe API provided for the `ipc_action' object is quite similar to the
2880Sstevel@tonic-gateone for the `async_action' object: when an IPC request comes in for an
2890Sstevel@tonic-gateoperation requiring asynchronous operation, ipc_action_start() is
2900Sstevel@tonic-gatecalled.  When the request completes, ipc_action_finish() is called.
2910Sstevel@tonic-gateIf the user times out before the request completes, then
2920Sstevel@tonic-gateipc_action_timeout() is called.
2930Sstevel@tonic-gate
2940Sstevel@tonic-gatePacket Management
2950Sstevel@tonic-gate-----------------
2960Sstevel@tonic-gate
2970Sstevel@tonic-gateAnother complicated area is packet management: building, manipulating,
2980Sstevel@tonic-gatesending and receiving packets.  These operations are all encapsulated
2990Sstevel@tonic-gatebehind a dozen or so interfaces (see packet.h) that abstract the
3000Sstevel@tonic-gateunimportant details away from the rest of the agent code.  In order to
3010Sstevel@tonic-gatesend a DHCP packet, code first calls init_pkt(), which returns a
3020Sstevel@tonic-gatedhcp_pkt_t initialized suitably for transmission.  Note that currently
3030Sstevel@tonic-gateinit_pkt() returns a dhcp_pkt_t that is actually allocated as part of
3043431Scarlsonjthe `dhcp_smach_t', but this may change in the future..  After calling
3050Sstevel@tonic-gateinit_pkt(), the add_pkt_opt*() functions are used to add options to
3063431Scarlsonjthe DHCP packet.  Finally, send_pkt() and send_pkt_v6() can be used to
3073431Scarlsonjtransmit the packet to a given IP address.
3080Sstevel@tonic-gate
309*5381SmeemThe send_pkt() function handles the details of packet timeout and
3100Sstevel@tonic-gateretransmission.  The last argument to send_pkt() is a pointer to a
3113431Scarlsonj"stop function."  If this argument is passed as NULL, then the packet
3120Sstevel@tonic-gatewill only be sent once (it won't be retransmitted).  Otherwise, before
3130Sstevel@tonic-gateeach retransmission, the stop function will be called back prior to
3143431Scarlsonjretransmission.  The callback may alter dsm_send_timeout if necessary
3153431Scarlsonjto place a cap on the next timeout; this is done for DHCPv6 in
3163431Scarlsonjstop_init_reboot() in order to implement the CNF_MAX_RD constraint.
3173431Scarlsonj
3183431ScarlsonjThe return value from this function indicates whether to continue
3193431Scarlsonjretransmission or not, which allows the send_pkt() caller to control
3203431Scarlsonjthe retransmission policy without making it have to deal with the
3213431Scarlsonjretransmission mechanism.  See request.c for an example of this in
3223431Scarlsonjaction.
3230Sstevel@tonic-gate
3240Sstevel@tonic-gateThe recv_pkt() function is simpler but still complicated by the fact
3250Sstevel@tonic-gatethat one may want to receive several different types of packets at
326*5381Smeemonce.  The caller registers an event handler on the file descriptor,
327*5381Smeemand then calls recv_pkt() to read in the packet along with meta
328*5381Smeeminformation about the message (the sender and interface identifier).
329*5381Smeem
3303431ScarlsonjFor IPv6, packet reception is done with a single socket, using
3313431ScarlsonjIPV6_PKTINFO to determine the actual destination address and receiving
3323431Scarlsonjinterface.  Packets are then matched against the state machines on the
3333431Scarlsonjgiven interface through the transaction ID.
3343431Scarlsonj
335*5381SmeemFor IPv4, due to oddities in the DHCP specification (discussed in
336*5381SmeemPSARC/2007/571), a special IP_DHCPINIT_IF socket option must be used
337*5381Smeemto allow unicast DHCP traffic to be received on an interface during
338*5381Smeemlease acquisition.  Since the IP_DHCPINIT_IF socket option can only
339*5381Smeemenable one interface at a time, one socket must be used per interface.
3400Sstevel@tonic-gate
3410Sstevel@tonic-gateTime
3420Sstevel@tonic-gate----
3430Sstevel@tonic-gate
3440Sstevel@tonic-gateThe notion of time is an exceptionally subtle area.  You will notice
3450Sstevel@tonic-gatefive ways that time is represented in the source: as lease_t's,
3460Sstevel@tonic-gateuint32_t's, time_t's, hrtime_t's, and monosec_t's.  Each of these
3470Sstevel@tonic-gatetypes serves a slightly different function.
3480Sstevel@tonic-gate
3490Sstevel@tonic-gateThe `lease_t' type is the simplest to understand; it is the unit of
3500Sstevel@tonic-gatetime in the CD_{LEASE,T1,T2}_TIME options in a DHCP packet, as defined
3510Sstevel@tonic-gateby RFC2131. This is defined as a positive number of seconds (relative
3520Sstevel@tonic-gateto some fixed point in time) or the value `-1' (DHCP_PERM) which
3530Sstevel@tonic-gaterepresents infinity (i.e., a permanent lease).  The lease_t should be
3540Sstevel@tonic-gateused either when dealing with actual DHCP packets that are sent on the
3550Sstevel@tonic-gatewire or for variables which follow the exact definition given in the
3560Sstevel@tonic-gateRFC.
3570Sstevel@tonic-gate
3580Sstevel@tonic-gateThe `uint32_t' type is also used to represent a relative time in
3590Sstevel@tonic-gateseconds.  However, here the value `-1' is not special and of course
3600Sstevel@tonic-gatethis type is not tied to any definition given in RFC2131.  Use this
3610Sstevel@tonic-gatefor representing "offsets" from another point in time that are not
3620Sstevel@tonic-gateDHCP lease times.
3630Sstevel@tonic-gate
3640Sstevel@tonic-gateThe `time_t' type is the natural Unix type for representing time since
3650Sstevel@tonic-gatethe epoch.  Unfortunately, it is affected by stime(2) or adjtime(2)
3660Sstevel@tonic-gateand since the DHCP client is used during system installation (and thus
3670Sstevel@tonic-gatewhen time is typically being configured), the time_t cannot be used in
3680Sstevel@tonic-gategeneral to represent an absolute time since the epoch.  For instance,
3690Sstevel@tonic-gateif a time_t were used to keep track of when a lease began, and then a
3700Sstevel@tonic-gateminute later stime(2) was called to adjust the system clock forward a
3710Sstevel@tonic-gateyear, then the lease would appeared to have expired a year ago even
3720Sstevel@tonic-gatethough it has only been a minute.  For this reason, time_t's should
3730Sstevel@tonic-gateonly be used either when wall time must be displayed (such as in
3740Sstevel@tonic-gateDHCP_STATUS ipc transaction) or when a time meaningful across reboots
3750Sstevel@tonic-gatemust be obtained (such as when caching an ACK packet at system
3760Sstevel@tonic-gateshutdown).
3770Sstevel@tonic-gate
3780Sstevel@tonic-gateThe `hrtime_t' type returned from gethrtime() works around the
3790Sstevel@tonic-gatelimitations of the time_t in that it is not affected by stime(2) or
3800Sstevel@tonic-gateadjtime(2), with the disadvantage that it represents time from some
3810Sstevel@tonic-gatearbitrary time in the past and in nanoseconds.  The timer queue code
3820Sstevel@tonic-gatedeals with hrtime_t's directly since that particular piece of code is
3830Sstevel@tonic-gatemeant to be fairly independent of the rest of the DHCP client.
3840Sstevel@tonic-gate
3850Sstevel@tonic-gateHowever, dealing with nanoseconds is error-prone when all the other
3860Sstevel@tonic-gatetime types are in seconds.  As a result, yet another time type, the
3870Sstevel@tonic-gate`monosec_t' was created to represent a monotonically increasing time
3880Sstevel@tonic-gatein seconds, and is really no more than (hrtime_t / NANOSEC).  Note
3890Sstevel@tonic-gatethat this unit is typically used where time_t's would've traditionally
3900Sstevel@tonic-gatebeen used.  The function monosec() in util.c returns the current
3910Sstevel@tonic-gatemonosec, and monosec_to_time() can convert a given monosec to wall
3920Sstevel@tonic-gatetime, using the system's current notion of time.
3930Sstevel@tonic-gate
3940Sstevel@tonic-gateOne additional limitation of the `hrtime_t' and `monosec_t' types is
3950Sstevel@tonic-gatethat they are unaware of the passage of time across checkpoint/resume
3960Sstevel@tonic-gateevents (e.g., those generated by sys-suspend(1M)).  For example, if
3970Sstevel@tonic-gategethrtime() returns time T, and then the machine is suspended for 2
3980Sstevel@tonic-gatehours, and then gethrtime() is called again, the time returned is not
3990Sstevel@tonic-gateT + (2 * 60 * 60 * NANOSEC), but rather approximately still T.
4000Sstevel@tonic-gate
4010Sstevel@tonic-gateTo work around this (and other checkpoint/resume related problems),
4020Sstevel@tonic-gatewhen a system is resumed, the DHCP client makes the pessimistic
4030Sstevel@tonic-gateassumption that all finite leases have expired while the machine was
4040Sstevel@tonic-gatesuspended and must be obtained again.  This is known as "refreshing"
4053431Scarlsonjthe leases, and is handled by refresh_smachs().
4060Sstevel@tonic-gate
4070Sstevel@tonic-gateNote that it appears like a more intelligent approach would be to
4080Sstevel@tonic-gaterecord the time(2) when the system is suspended, compare that against
4090Sstevel@tonic-gatethe time(2) when the system is resumed, and use the delta between them
4100Sstevel@tonic-gateto decide which leases have expired.  Sadly, this cannot be done since
4113431Scarlsonjthrough at least Solaris 10, it is not possible for userland programs
4120Sstevel@tonic-gateto be notified of system suspend events.
4130Sstevel@tonic-gate
4140Sstevel@tonic-gateConfiguration
4150Sstevel@tonic-gate-------------
4160Sstevel@tonic-gate
4170Sstevel@tonic-gateFor the most part, the DHCP client only *retrieves* configuration data
4180Sstevel@tonic-gatefrom the DHCP server, leaving the configuration to scripts (such as
4190Sstevel@tonic-gateboot scripts), which themselves use dhcpinfo(1) to retrieve the data
4200Sstevel@tonic-gatefrom the DHCP client.  This is desirable because it keeps the mechanism
4210Sstevel@tonic-gateof retrieving the configuration data decoupled from the policy of using
4220Sstevel@tonic-gatethe data.
4230Sstevel@tonic-gate
4243431ScarlsonjHowever, unless used in "inform" mode, the DHCP client *does*
4253431Scarlsonjconfigure each IP interface enough to allow it to communicate with
4263431Scarlsonjother hosts.  Specifically, the DHCP client configures the interface's
4273431ScarlsonjIP address, netmask, and broadcast address using the information
4283431Scarlsonjprovided by the server.  Further, for IPv4 logical interface 0
4293431Scarlsonj("hme0"), any provided default routes are also configured.
4303431Scarlsonj
4313431ScarlsonjFor IPv6, only the IP addresses are set.  The netmask (prefix) is then
4323431Scarlsonjset automatically by in.ndpd, and routes are discovered in the usual
4333431Scarlsonjway by router discovery or routing protocols.  DHCPv6 doesn't set
4343431Scarlsonjroutes.
4353431Scarlsonj
4363431ScarlsonjSince logical interfaces cannot be specified as output interfaces in
4373431Scarlsonjthe kernel forwarding table, and in most cases, logical interfaces
4383431Scarlsonjshare a default route with their associated physical interface, the
4393431ScarlsonjDHCP client does not automatically add or remove default routes when
4403431ScarlsonjIPv4 leases are acquired or expired on logical interfaces.
4410Sstevel@tonic-gate
4420Sstevel@tonic-gateEvent Scripting
4430Sstevel@tonic-gate---------------
4440Sstevel@tonic-gate
4450Sstevel@tonic-gateThe DHCP client supports user program invocations on DHCP events.  The
4463431Scarlsonjsupported events are BOUND, EXTEND, EXPIRE, DROP, RELEASE, and INFORM
4473431Scarlsonjfor DHCPv4, and BUILD6, EXTEND6, EXPIRE6, DROP6, LOSS6, RELEASE6, and
4483431ScarlsonjINFORM6 for DHCPv6.  The user program runs asynchronous to the DHCP
4493431Scarlsonjclient so that the main event loop stays active to process other
4503431Scarlsonjevents, including events triggered by the user program (for example,
4513431Scarlsonjwhen it invokes dhcpinfo).
4520Sstevel@tonic-gate
4530Sstevel@tonic-gateThe user program execution is part of the transaction of a DHCP command.
4540Sstevel@tonic-gateFor example, if the user program is not enabled, the transaction of the
4550Sstevel@tonic-gateDHCP command START is considered over when an ACK is received and the
4560Sstevel@tonic-gateinterface is configured successfully.  If the user program is enabled,
4570Sstevel@tonic-gateit is invoked after the interface is configured successfully, and the
4580Sstevel@tonic-gatetransaction is considered over only when the user program exits.  The
4590Sstevel@tonic-gateevent scripting implementation makes use of the asynchronous operations
4600Sstevel@tonic-gatediscussed in the "Transactions" section.
4610Sstevel@tonic-gate
4623431ScarlsonjAn upper bound of 58 seconds is imposed on how long the user program
4630Sstevel@tonic-gatecan run. If the user program does not exit after 55 seconds, the signal
4640Sstevel@tonic-gateSIGTERM is sent to it. If it still does not exit after additional 3
4650Sstevel@tonic-gateseconds, the signal SIGKILL is sent to it.  Since the event handler is
4660Sstevel@tonic-gatea wrapper around poll(), the DHCP client cannot directly observe the
4670Sstevel@tonic-gatecompletion of the user program.  Instead, the DHCP client creates a
4680Sstevel@tonic-gatechild "helper" process to synchronously monitor the user program (this
4690Sstevel@tonic-gateprocess is also used to send the aformentioned signals to the process,
4703431Scarlsonjif necessary).  The DHCP client and the helper process share a pipe
4710Sstevel@tonic-gatewhich is included in the set of poll descriptors monitored by the DHCP
4720Sstevel@tonic-gateclient's event handler.  When the user program exits, the helper process
4730Sstevel@tonic-gatepasses the user program exit status to the DHCP client through the pipe,
4740Sstevel@tonic-gateinforming the DHCP client that the user program has finished.  When the
4750Sstevel@tonic-gateDHCP client is asked to shut down, it will wait for any running instances
4760Sstevel@tonic-gateof the user program to complete.
477