README revision 7c478bd95313f5f23a4c958a745db2134aa03244
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwCDDL HEADER START
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwThe contents of this file are subject to the terms of the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwCommon Development and Distribution License, Version 1.0 only
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw(the "License"). You may not use this file except in compliance
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwwith the License.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwYou can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwSee the License for the specific language governing permissions
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwand limitations under the License.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwWhen distributing Covered Code, include this CDDL HEADER in each
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwfile and include the License file at usr/src/OPENSOLARIS.LICENSE.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwIf applicable, add the following below this CDDL HEADER, with the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwfields enclosed by brackets "[]" replaced with your own identifying
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwinformation: Portions Copyright [yyyy] [name of copyright owner]
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwCDDL HEADER END
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwCopyright 2004 Sun Microsystems, Inc. All rights reserved.
cb174861876aea6950a7ab4ce944aff84b1914cdjoyce mcintoshUse is subject to license terms.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwArchitectural Overview for the DHCP agent
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwPeter Memishian
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownident "%Z%%M% %I% %E% SMI"
dc20a3024900c47dd2ee44b9707e6df38f7d62a5asINTRODUCTION
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw============
b1352070d318187b41b088da3533692976f3f225Alan WrightThe Solaris DHCP agent (dhcpagent) is an RFC2131-compliant DHCP client
b1352070d318187b41b088da3533692976f3f225Alan Wrightimplementation. The major forces shaping its design were:
b1352070d318187b41b088da3533692976f3f225Alan Wright * Must be capable of managing multiple network interfaces.
b1352070d318187b41b088da3533692976f3f225Alan Wright * Must consume little CPU, since it will always be running.
b1352070d318187b41b088da3533692976f3f225Alan Wright * Must have a small memory footprint, since it will always be
b1352070d318187b41b088da3533692976f3f225Alan Wright * Must not rely on any shared libraries, since it must run
b1352070d318187b41b088da3533692976f3f225Alan Wright before all filesystems have been mounted.
b1352070d318187b41b088da3533692976f3f225Alan WrightWhen a DHCP agent implementation is only required to control a single
b1352070d318187b41b088da3533692976f3f225Alan Wrightinterface on a machine, the problem is expressed well as a simple
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownstate-machine, as shown in RFC2131. However, when a DHCP agent is
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownresponsible for managing more than one interface at a time, the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownproblem becomes much more complicated, especially when threads cannot
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownbe used to attack the problem (since the filesystems containing the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthread libraries may not be available when the agent starts).
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownInstead, the problem must be solved using an event-driven model, which
b1352070d318187b41b088da3533692976f3f225Alan Wrightwhile tried-and-true, is subtle and easy to get wrong. Indeed, much
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownof the agent's code is there to manage the complexity of programming
037cac007b685e7ea79f6ef7e8e62bfd342a4d56joyce mcintoshin an asynchronous event-driven paradigm.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownThe DHCP agent consists of roughly 20 source files, most with a
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwcompanion header file. While the largest source file is around 700
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwlines, most are much shorter. The source files can largely be broken
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwup into three groups:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Source files, which along with their companion header files,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw define an abstract "object" that is used by other parts of
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw the system. Examples include "timer_queue.c", which along
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw with "timer_queue.h" provide a Timer Queue object for use
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw by the rest of the agent, and "async.c", which along with
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw "async.h" defines an interface for managing asynchronous
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw transactions within the agent.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Source files which implement a given state of the agent; for
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw instance, there is a "request.c" which comprises all of
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw the procedural "work" which must be done while in the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brown REQUESTING state of the agent. By encapsulating states in
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw files, it becomes easier to debug errors in the
7b59d02d2a384be9a08087b14defadd214b3c1ddjb client/server protocol and adapt the agent to new
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb constraints, since all the relevant code is in one place.
b89a8333f5e1f75ec0c269b22524bd2eccb972banatalie li - Sun Microsystems - Irvine United States * Source files, which along with their companion header files,
b89a8333f5e1f75ec0c269b22524bd2eccb972banatalie li - Sun Microsystems - Irvine United States encapsulate a given task or related set of tasks. The
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb difference between this and the first group is that the
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb interfaces exported from these files do not operate on
eb1d736b1c19f6abeee90c921a9320b67fedd016afshin salek ardakani - Sun Microsystems - Irvine United States an "object", but rather perform a specific task. Examples
eb1d736b1c19f6abeee90c921a9320b67fedd016afshin salek ardakani - Sun Microsystems - Irvine United States include "dlpi_io.c", which provides a useful interface
eb1d736b1c19f6abeee90c921a9320b67fedd016afshin salek ardakani - Sun Microsystems - Irvine United States to DLPI-related i/o operations.
eb1d736b1c19f6abeee90c921a9320b67fedd016afshin salek ardakani - Sun Microsystems - Irvine United StatesOVERVIEW
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbHere we discuss the essential objects and subtle aspects of the
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbDHCP agent implementation. Note that there is of course much more
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbthat is not discussed here, but after this overview you should be able
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbto fend for yourself in the source code.
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbEvent Handlers and Timer Queues
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb-------------------------------
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbThe most important object in the agent is the event handler, whose
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbinterface is in libinetutil.h and whose implementation is in
faa1795a28a5c712eed6d0a3f84d98c368a316c6jblibinetutil. The event handler is essentially an object-oriented
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbwrapper around poll(2): other components of the agent can register to
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbbe called back when specific events on file descriptors happen -- for
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbinstance, to wait for requests to arrive on its IPC socket, the agent
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwregisters a callback function (accept_event()) that will be called
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesback whenever a new connection arrives on the file descriptor
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesassociated with the IPC socket. When the agent initially begins in
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesmain(), it registers a number of events with the event handler, and
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesthen calls iu_handle_events(), which proceeds to wait for events to
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Stateshappen -- this function does not return until the agent is shutdown
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwvia signal.
dc20a3024900c47dd2ee44b9707e6df38f7d62a5asWhen the registered events occur, the callback functions are called
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwback, which in turn might lead to additional callbacks being
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbregistered -- this is the classic event-driven model. (As an aside,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwnote that programming in an event-driven model means that callbacks
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwcannot block, or else the agent will become unresponsive.)
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United States
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United StatesA special kind of "event" is a timeout. Since there are many timers
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Stateswhich must be maintained for each DHCP-controlled interface (such as a
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Stateslease expiration timer, time-to-first-renewal (t1) timer, and so
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesforth), an object-oriented abstraction to timers called a "timer
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesqueue" is provided, whose interface is in libinetutil.h with a
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statescorresponding implementation in libinetutil. The timer queue allows
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browncallback functions to be "scheduled" for callback after a certain
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwamount of time has passed.
b1352070d318187b41b088da3533692976f3f225Alan WrightThe event handler and timer queue objects work hand-in-hand: the event
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbhandler is passed a pointer to a timer queue in iu_handle_events() --
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwfrom there, it can use the iu_earliest_timer() routine to find the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwtimer which will next fire, and use this to set its timeout value in
7b59d02d2a384be9a08087b14defadd214b3c1ddjbits call to poll(2). If poll(2) returns due to a timeout, the event
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbhandler calls iu_expire_timers() to expire all timers that expired
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw(note that more than one may have expired if, for example, multiple
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwtimers were set to expire at the same time).
b1352070d318187b41b088da3533692976f3f225Alan WrightAlthough it is possible to instantiate more than one timer queue or
b1352070d318187b41b088da3533692976f3f225Alan Wrightevent handler object, it doesn't make a lot of sense -- these objects
b1352070d318187b41b088da3533692976f3f225Alan Wrightare really "singletons". Accordingly, the agent has two global
b1352070d318187b41b088da3533692976f3f225Alan Wrightvariables, `eh' and `tq', which store pointers to the global event
b1352070d318187b41b088da3533692976f3f225Alan Wrighthandler and timer queue.
b1352070d318187b41b088da3533692976f3f225Alan WrightNetwork Interfaces
b1352070d318187b41b088da3533692976f3f225Alan Wright------------------
b1352070d318187b41b088da3533692976f3f225Alan WrightFor each network interface managed by the agent, there is a set of
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownassociated state that describes both its general properties (such as
b1352070d318187b41b088da3533692976f3f225Alan Wrightthe maximum MTU) and its DHCP-related state (such as when it acquired
b1352070d318187b41b088da3533692976f3f225Alan Wrighta lease). This state is stored in a a structure called an `ifslist',
b1352070d318187b41b088da3533692976f3f225Alan Wrightwhich is a poor name (since it suggests implementation artifacts but
b1352070d318187b41b088da3533692976f3f225Alan Wrightnot purpose) but has historical precedent. Another way to think about
b1352070d318187b41b088da3533692976f3f225Alan Wrightan `ifslist' is that it provides all of the context necessary to
b1352070d318187b41b088da3533692976f3f225Alan Wrightperform DHCP on a given interface: the state the interface is in, the
b1352070d318187b41b088da3533692976f3f225Alan Wrightlast packet DHCP packet received on that interface, and so forth. As
b1352070d318187b41b088da3533692976f3f225Alan Wrightone can imagine, the `ifslist' structure is quite complicated and rules
b1352070d318187b41b088da3533692976f3f225Alan Wrightgoverning accessing its fields are equally convoluted -- see the
b1352070d318187b41b088da3533692976f3f225Alan Wrightcomments in interface.h for more information.
b1352070d318187b41b088da3533692976f3f225Alan WrightOne point that was brushed over in the preceding discussion of event
b1352070d318187b41b088da3533692976f3f225Alan Wrighthandlers and timer queues was context. Recall that the event-driven
b1352070d318187b41b088da3533692976f3f225Alan Wrightnature of the agent requires that functions cannot block, lest they
b1352070d318187b41b088da3533692976f3f225Alan Wrightstarve out others and impact the observed responsiveness of the agent.
b1352070d318187b41b088da3533692976f3f225Alan WrightAs an example, consider the process of extending a lease: the agent
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwmust send a REQUEST packet and wait for an ACK or NAK packet in
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwresponse. This is done by sending a REQUEST and then registering a
b1352070d318187b41b088da3533692976f3f225Alan Wrightcallback with the event handler that waits for an ACK or NAK packet to
b1352070d318187b41b088da3533692976f3f225Alan Wrightarrive on the file descriptor associated with the interface. Note
dc20a3024900c47dd2ee44b9707e6df38f7d62a5ashowever, that when the ACK or NAK does arrive, and the callback
b1352070d318187b41b088da3533692976f3f225Alan Wrightfunction called back, it must know which interface this packet is for
b1352070d318187b41b088da3533692976f3f225Alan Wright(it must get back its context). This could be handled through an
dc20a3024900c47dd2ee44b9707e6df38f7d62a5asad-hoc mapping of file descriptors to interfaces, but a cleaner
b1352070d318187b41b088da3533692976f3f225Alan Wrightapproach is to have the event handler's register function
b1352070d318187b41b088da3533692976f3f225Alan Wright(iu_register_event()) take in an opaque context pointer, which will
b1352070d318187b41b088da3533692976f3f225Alan Wrightthen be passed back to the callback. In the agent, this context
b1352070d318187b41b088da3533692976f3f225Alan Wrightpointer is always the `ifslist', but for reasons of decoupling and
b1352070d318187b41b088da3533692976f3f225Alan Wrightgenerality, the timer queue and event handler objects allow a generic
b1352070d318187b41b088da3533692976f3f225Alan Wright(void *) context argument.
b1352070d318187b41b088da3533692976f3f225Alan WrightNote that there is nothing that guarantees the pointer passed into
b1352070d318187b41b088da3533692976f3f225Alan Wrightiu_register_event() or iu_schedule_timer() will still be valid when
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesthe callback is called back (for instance, the memory may have been
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesfreed in the meantime). To solve this problem, ifslists are reference
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statescounted. For more details on how the reference count scheme is
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesimplemented, see the closing comments in interface.h regarding memory
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesmanagement.
b1352070d318187b41b088da3533692976f3f225Alan WrightMany operations performed via DHCP must be performed in groups -- for
b1352070d318187b41b088da3533692976f3f225Alan Wrightinstance, acquiring a lease requires several steps: sending a
b1352070d318187b41b088da3533692976f3f225Alan WrightDISCOVER, collecting OFFERs, selecting an OFFER, sending a REQUEST,
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesand receiving an ACK, assuming everything goes well. Note however
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesthat due to the event-driven model the agent operates in, these
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesoperations are not inherently "grouped" -- instead, the agent sends a
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United StatesDISCOVER, goes back into the main event loop, waits for events
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United States(perhaps even requests on the IPC channel to begin acquiring a lease
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Stateson another interface), eventually checks to see if an acceptable OFFER
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Stateshas come in, and so forth. To some degree, the notion of the current
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesstate of an interface (SELECTING, REQUESTING, etc) helps control the
b1352070d318187b41b088da3533692976f3f225Alan Wrightpotential chaos of the event-driven model (for instance, if while the
b1352070d318187b41b088da3533692976f3f225Alan Wrightagent is waiting for an OFFER on a given interface, an IPC event comes
b1352070d318187b41b088da3533692976f3f225Alan Wrightin requesting that the interface be RELEASED, the agent knows to send
b1352070d318187b41b088da3533692976f3f225Alan Wrightback an error since the interface must be in at least the BOUND state
b1352070d318187b41b088da3533692976f3f225Alan Wrightbefore a RELEASE can be performed.)
b1352070d318187b41b088da3533692976f3f225Alan WrightHowever, states are not enough -- for instance, suppose that the agent
b1352070d318187b41b088da3533692976f3f225Alan Wrightbegins trying to renew a lease -- this is done by sending a REQUEST
b1352070d318187b41b088da3533692976f3f225Alan Wrightpacket and waiting for an ACK or NAK, which might never come. If,
b1352070d318187b41b088da3533692976f3f225Alan Wrightwhile waiting for the ACK or NAK, the user sends a request to renew
b1352070d318187b41b088da3533692976f3f225Alan Wrightthe lease as well, then if the agent were to send another REQUEST,
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthings could get quite complicated (and this is only the beginning of
b1352070d318187b41b088da3533692976f3f225Alan Wrightthis rathole). To protect against this, two objects exist:
b1352070d318187b41b088da3533692976f3f225Alan Wright`async_action' and `ipc_action'. These objects are related, but
b1352070d318187b41b088da3533692976f3f225Alan Wrightindependent of one another; the more essential object is the
b1352070d318187b41b088da3533692976f3f225Alan Wright`async_action', which we will discuss first.
b1352070d318187b41b088da3533692976f3f225Alan WrightIn short, an `async_action' represents a pending transaction (aka
b1352070d318187b41b088da3533692976f3f225Alan Wrightasynchronous action), of which each interface can have at most one.
b1352070d318187b41b088da3533692976f3f225Alan WrightThe `async_action' structure is embedded in the `ifslist' structure,
b1352070d318187b41b088da3533692976f3f225Alan Wrightwhich is fine since there can be at most one pending transaction per
b1352070d318187b41b088da3533692976f3f225Alan Wrightinterface. Typical "asynchronous transactions" are START, EXTEND, and
b1352070d318187b41b088da3533692976f3f225Alan WrightINFORM, since each consists of a sequence of packets that must be done
b1352070d318187b41b088da3533692976f3f225Alan Wrightwithout interruption. Note that not all DHCP operations are
b1352070d318187b41b088da3533692976f3f225Alan Wright"asynchronous" -- for instance, a RELEASE operation is synchronous
b1352070d318187b41b088da3533692976f3f225Alan Wright(not asynchronous) since after the RELEASE is sent no reply is
b1352070d318187b41b088da3533692976f3f225Alan Wrightexpected from the DHCP server. Also, note that there can be
b1352070d318187b41b088da3533692976f3f225Alan Wrightsynchronous operations intermixed with asynchronous operations
b1352070d318187b41b088da3533692976f3f225Alan Wrightalthough it's not recommended.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownWhen the agent realizes it must perform an asynchronous transaction,
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownit first calls async_pending() to see if there is already one pending;
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownif so, the new transaction must fail (the details of failure depend on
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownhow the transaction was initiated, which is described in more detail
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownlater when the `ipc_action' object is discussed). If there is no
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownpending asynchronous transaction, async_start() is called to begin
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownWhen the transaction is complete, async_finish() must be called to
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browncomplete the asynchronous action on that interface. If the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browntransaction is unable to complete within a certain amount of time
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brown(more on this later), async_timeout() is invoked which attempts to
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browncancel the asynchronous action with async_cancel(). If the event is
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownnot cancellable it is left pending, although this means that no future
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownasynchronous actions can be performed on the interface until the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browntransaction voluntarily calls async_finish(). While this may seem
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownsuboptimal, cancellation here is quite analogous to thread
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browncancellation, which is generally considered a difficult problem.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownThe notion of asynchronous transactions is complicated by the fact
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthat they may originate from both inside and outside of the agent.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownFor instance, a user initiates an asynchronous START transaction when
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownhe performs an `ifconfig hme0 dhcp start', but the agent will
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browninternally need to perform asynchronous EXTEND transactions to extend
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthe lease before it expires. This leads us into the `ipc_action'
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownAn `ipc_action' represents the IPC-related pieces of an asynchronous
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browntransaction that was started as a result of a user request. Only
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownIPC-generated asynchronous transactions have a valid `ipc_action'
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownobject. Note that since there can be at most one asynchronous action
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownper interface, there can also be at most one `ipc_action' per
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browninterface (this means it can also conveniently be embedded inside the
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United States`ifslist' structure).
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United States
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United StatesOne of the main purposes of the `ipc_action' object is to timeout user
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesevents. This is not the same as timing out the transaction; for
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesinstance, when the user specifies a timeout value as an argument to
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesifconfig, he is specifying an `ipc_action' timeout; in other words,
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownhow long he is willing to wait for the command to complete. However,
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browneven after the command times out for the user, the asynchronous
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browntransaction continues until async_timeout() occurs.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownIt is worth understanding these timeouts since the relationship is
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownsubtle but powerful. The `async_action' timer specifies how long the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownagent will try to perform the transaction; the `ipc_action' timer
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownspecifies how long the user is willing to wait for the action to
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statescomplete. If when the `async_action' timer fires and async_timeout()
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesis called, there is no associated `ipc_action' (either because the
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statestransaction was not initiated by a user or because the user already
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statestimed out), then async_cancel() proceeds as described previously. If,
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Stateson the other hand, the user is still waiting for the transaction to
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statescomplete, then async_timeout() is rescheduled and the transaction is
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesleft pending. While this behavior might seem odd, it adheres to the
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesprinciples of least surprise: when a user is willing to wait for a
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statestransaction to complete, the agent should try for as long as they're
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Stateswilling to wait. On the other hand, if the agent were to take that
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesstance with its internal transactions, it would block out
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesuser-requested operations if the internal transaction never completed
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United States(perhaps because the server never sent an ACK in response to our lease
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesextension REQUEST).
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United States
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United StatesThe API provided for the `ipc_action' object is quite similar to the
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesone for the `async_action' object: when an IPC request comes in for an
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statesoperation requiring asynchronous operation, ipc_action_start() is
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United Statescalled. When the request completes, ipc_action_finish() is called.
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United StatesIf the user times out before the request completes, then
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownipc_action_timeout() is called.
9fb67ea305c66b6a297583b9b0db6796b0dfe497afshin salek ardakani - Sun Microsystems - Irvine United States
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownPacket Management
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brown-----------------
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownAnother complicated area is packet management: building, manipulating,
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownsending and receiving packets. These operations are all encapsulated
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownbehind a dozen or so interfaces (see packet.h) that abstract the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownunimportant details away from the rest of the agent code. In order to
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownsend a DHCP packet, code first calls init_pkt(), which returns a
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browndhcp_pkt_t initialized suitably for transmission. Note that currently
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browninit_pkt() returns a dhcp_pkt_t that is actually allocated as part of
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthe `ifslist', but this may change in the future.. After calling
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browninit_pkt(), the add_pkt_opt*() functions are used to add options to
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthe DHCP packet. Finally, send_pkt() can be used to transmit the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownpacket to a given IP address.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownThe send_pkt() function is actually quite complicated; for one, it
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownmust internally use either DLPI or sockets depending on the state of
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthe interface; for two, it handles the details of packet timeout and
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownretransmission. The last argument to send_pkt() is a pointer to a
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brown"stop function". If this argument is passed as NULL, then the packet
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownwill only be sent once (it won't be retransmitted). Otherwise, before
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browneach retransmission, the stop function will be called back prior to
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownretransmission. The return value from this function indicates whether
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownto continue retransmission or not, which allows the send_pkt() caller
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownto control the retransmission policy without making it have to deal
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownwith the retransmission mechanism. See init_reboot.c for an example
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownof this in action.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownThe recv_pkt() function is simpler but still complicated by the fact
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthat one may want to receive several different types of packets at
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownonce; for instance, after sending a REQUEST, either an ACK or a NAK is
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownacceptable. Also, before calling recv_pkt(), the caller must know
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthat there is data to be read from the socket (this can be
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownaccomplished by using the event handler), otherwise recv_pkt() will
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownblock, which is clearly not acceptable.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownThe notion of time is an exceptionally subtle area. You will notice
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownfive ways that time is represented in the source: as lease_t's,
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownuint32_t's, time_t's, hrtime_t's, and monosec_t's. Each of these
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browntypes serves a slightly different function.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownThe `lease_t' type is the simplest to understand; it is the unit of
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browntime in the CD_{LEASE,T1,T2}_TIME options in a DHCP packet, as defined
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownby RFC2131. This is defined as a positive number of seconds (relative
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownto some fixed point in time) or the value `-1' (DHCP_PERM) which
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownrepresents infinity (i.e., a permanent lease). The lease_t should be
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownused either when dealing with actual DHCP packets that are sent on the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownwire or for variables which follow the exact definition given in the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownThe `uint32_t' type is also used to represent a relative time in
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownseconds. However, here the value `-1' is not special and of course
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthis type is not tied to any definition given in RFC2131. Use this
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownfor representing "offsets" from another point in time that are not
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownDHCP lease times.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownThe `time_t' type is the natural Unix type for representing time since
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthe epoch. Unfortunately, it is affected by stime(2) or adjtime(2)
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownand since the DHCP client is used during system installation (and thus
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownwhen time is typically being configured), the time_t cannot be used in
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browngeneral to represent an absolute time since the epoch. For instance,
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownif a time_t were used to keep track of when a lease began, and then a
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownminute later stime(2) was called to adjust the system clock forward a
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownyear, then the lease would appeared to have expired a year ago even
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthough it has only been a minute. For this reason, time_t's should
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownonly be used either when wall time must be displayed (such as in
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownDHCP_STATUS ipc transaction) or when a time meaningful across reboots
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownmust be obtained (such as when caching an ACK packet at system
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownThe `hrtime_t' type returned from gethrtime() works around the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownlimitations of the time_t in that it is not affected by stime(2) or
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownadjtime(2), with the disadvantage that it represents time from some
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownarbitrary time in the past and in nanoseconds. The timer queue code
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browndeals with hrtime_t's directly since that particular piece of code is
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownmeant to be fairly independent of the rest of the DHCP client.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownHowever, dealing with nanoseconds is error-prone when all the other
fe1c642d06e14b412cd83ae2179303186ab08972Bill Kriertime types are in seconds. As a result, yet another time type, the
fe1c642d06e14b412cd83ae2179303186ab08972Bill Krier`monosec_t' was created to represent a monotonically increasing time
fe1c642d06e14b412cd83ae2179303186ab08972Bill Krierin seconds, and is really no more than (hrtime_t / NANOSEC). Note
fe1c642d06e14b412cd83ae2179303186ab08972Bill Krierthat this unit is typically used where time_t's would've traditionally
fe1c642d06e14b412cd83ae2179303186ab08972Bill Krierbeen used. The function monosec() in util.c returns the current
fe1c642d06e14b412cd83ae2179303186ab08972Bill Kriermonosec, and monosec_to_time() can convert a given monosec to wall
fe1c642d06e14b412cd83ae2179303186ab08972Bill Kriertime, using the system's current notion of time.
fe1c642d06e14b412cd83ae2179303186ab08972Bill KrierOne additional limitation of the `hrtime_t' and `monosec_t' types is
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthat they are unaware of the passage of time across checkpoint/resume
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownevents (e.g., those generated by sys-suspend(1M)). For example, if
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browngethrtime() returns time T, and then the machine is suspended for 2
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownhours, and then gethrtime() is called again, the time returned is not
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownT + (2 * 60 * 60 * NANOSEC), but rather approximately still T.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownTo work around this (and other checkpoint/resume related problems),
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownwhen a system is resumed, the DHCP client makes the pessimistic
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownassumption that all finite leases have expired while the machine was
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownsuspended and must be obtained again. This is known as "refreshing"
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthe leases, and is handled by refresh_ifslist().
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownNote that it appears like a more intelligent approach would be to
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownrecord the time(2) when the system is suspended, compare that against
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthe time(2) when the system is resumed, and use the delta between them
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownto decide which leases have expired. Sadly, this cannot be done since
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownthrough at least Solaris 8, it is not possible for userland programs
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownto be notified of system suspend events.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownConfiguration
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brown-------------
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownFor the most part, the DHCP client only *retrieves* configuration data
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownfrom the DHCP server, leaving the configuration to scripts (such as
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownboot scripts), which themselves use dhcpinfo(1) to retrieve the data
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownfrom the DHCP client. This is desirable because it keeps the mechanism
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownof retrieving the configuration data decoupled from the policy of using
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownHowever, unless used in "inform" mode, the DHCP client *does* configure
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browneach interface enough to allow it to communicate with other hosts.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownSpecifically, the DHCP client configures the interface's IP address,
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownnetmask, and broadcast address using the information provided by the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownserver. Further, for physical interfaces, any provided default routes
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownare also configured. Since logical interfaces cannot be stored in the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownkernel routing table, and in most cases, logical interfaces share a
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browndefault route with their associated physical interface, the DHCP client
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browndoes not automatically add or remove default routes when leases are
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownacquired or expired on logical interfaces.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownEvent Scripting
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brown---------------
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownThe DHCP client supports user program invocations on DHCP events. The
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownsupported events are BOUND, EXTEND, EXPIRE, DROP and RELEASE. The user
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownprogram runs asynchronous to the DHCP client so that the main event
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownloop stays active to process other events, including events triggered
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownby the user program (for example, when it invokes dhcpinfo).
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownThe user program execution is part of the transaction of a DHCP command.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownFor example, if the user program is not enabled, the transaction of the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownDHCP command START is considered over when an ACK is received and the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browninterface is configured successfully. If the user program is enabled,
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownit is invoked after the interface is configured successfully, and the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browntransaction is considered over only when the user program exits. The
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownevent scripting implementation makes use of the asynchronous operations
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browndiscussed in the "Transactions" section.
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownThe upper bound of 58 seconds is imposed on how long the user program
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browncan run. If the user program does not exit after 55 seconds, the signal
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownSIGTERM is sent to it. If it still does not exit after additional 3
cb174861876aea6950a7ab4ce944aff84b1914cdjoyce mcintoshseconds, the signal SIGKILL is sent to it. Since the event handler is
cb174861876aea6950a7ab4ce944aff84b1914cdjoyce mcintosha wrapper around poll(), the DHCP client cannot directly observe the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browncompletion of the user program. Instead, the DHCP client creates a
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownchild "helper" process to synchronously monitor the user program (this
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownprocess is also used to send the aformentioned signals to the process,
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownif necessary). The DHCP client and the helper process share a pipe
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownwhich is included in the set of poll descriptors monitored by the DHCP
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownclient's event handler. When the user program exits, the helper process
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownpasses the user program exit status to the DHCP client through the pipe,
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Browninforming the DHCP client that the user program has finished. When the
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan BrownDHCP client is asked to shut down, it will wait for any running instances
bbf6f00c25b6a2bed23c35eac6d62998ecdb338cJordan Brownof the user program to complete.