Lines Matching refs:the
3 The contents of this file are subject to the terms of the
4 Common Development and Distribution License (the "License").
5 You may not use this file except in compliance with the License.
7 You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 See the License for the specific language governing permissions
10 and limitations under the License.
13 file and include the License file at usr/src/OPENSOLARIS.LICENSE.
14 If applicable, add the following below this CDDL HEADER, with the
23 Architectural Overview for the DHCP agent
41 interface on a machine, the problem is expressed well as a simple
43 responsible for managing more than one interface at a time, the
48 machine, the event-driven model is the closest match.
51 Indeed, much of the agent's code is there to manage the complexity of
58 companion header file. While the largest source file is around 1700
64 the system. Examples include "packet.c", which along with
65 "packet.h" provide a Packet object for use by the rest of
66 the agent; and "async.c", which along with "async.h" defines
68 the agent.
70 * Source files that implement a given state of the agent; for
72 the procedural "work" which must be done while in the
73 REQUESTING state of the agent. By encapsulating states in
74 files, it becomes easier to debug errors in the
75 client/server protocol and adapt the agent to new
76 constraints, since all the relevant code is in one place.
80 difference between this and the first group is that the
89 Here we discuss the essential objects and subtle aspects of the
92 to fend for yourself in the source code.
94 For details on the DHCPv6 aspects of the design, and how this relates
95 to the implementation present in previous releases of Solaris, see the
101 The most important object in the agent is the event handler, whose
104 wrapper around poll(2): other components of the agent can register to
106 instance, to wait for requests to arrive on its IPC socket, the agent
108 back whenever a new connection arrives on the file descriptor
109 associated with the IPC socket. When the agent initially begins in
110 main(), it registers a number of events with the event handler, and
112 happen -- this function does not return until the agent is shutdown
115 When the registered events occur, the callback functions are called
117 registered -- this is the classic event-driven model. (As an aside,
119 cannot block, or else the agent will become unresponsive.)
130 The event handler and timer queue objects work hand-in-hand: the event
132 from there, it can use the iu_earliest_timer() routine to find the
134 its call to poll(2). If poll(2) returns due to a timeout, the event
137 timers were set to expire at the same time).
141 are really "singletons". Accordingly, the agent has two global
142 variables, `eh' and `tq', which store pointers to the global event
148 For each network interface managed by the agent, there is a set of
150 the maximum MTU) and its connections to DHCP-related state (the
152 structures called `dhcp_pif_t' (the IP physical interface layer or
153 PIF) and `dhcp_lif_t' (the IP logical interface layer or LIF). Each
156 structures representing the logical interfaces (such as "hme0:1") in
157 use by the agent.
162 interface, which must be specified by the user. For IPv6, however,
168 needed and removes them when the addresses expire.
171 This state machine then points to the main LIF used for I/O, and to a
173 each of those points to a list of LIFs corresponding to the individual
176 One point that was brushed over in the preceding discussion of event
177 handlers and timer queues was context. Recall that the event-driven
178 nature of the agent requires that functions cannot block, lest they
179 starve out others and impact the observed responsiveness of the agent.
180 As an example, consider the process of extending a lease: the agent
182 response. This is done by sending a REQUEST and then returning to the
183 event handler that waits for an ACK or NAK packet to arrive on the
184 file descriptor associated with the interface. Note however, that
185 when the ACK or NAK does arrive, and the callback function called
189 the event handler's register function (iu_register_event()) take in an
190 opaque context pointer, which will then be passed back to the
191 callback. In the agent, the context pointer used depends on the
192 nature of the event: events on LIFs use the dhcp_lif_t pointer, events
193 on the state machine use dhcp_smach_t, and so on.
195 Note that there is nothing that guarantees the pointer passed into
197 the callback is called back (for instance, the memory may have been
198 freed in the meantime). To solve this problem, all of the data
200 on how the reference count scheme is implemented, see the closing
210 that due to the event-driven model the agent operates in, these
211 operations are not inherently "grouped" -- instead, the agent sends a
212 DISCOVER, goes back into the main event loop, waits for events
213 (perhaps even requests on the IPC channel to begin acquiring a lease
215 OFFER has come in, and so forth. To some degree, the notion of the
217 control the potential chaos of the event-driven model (for instance,
218 if while the agent is waiting for an OFFER on a given state machine,
219 an IPC event comes in requesting that the leases be RELEASED, the
220 agent knows to send back an error since the state machine must be in
221 at least the BOUND state before a RELEASE can be performed.)
223 However, states are not enough -- for instance, suppose that the agent
226 while waiting for the ACK or NAK, the user sends a request to renew
227 the lease as well, then if the agent were to send another REQUEST,
228 things could get quite complicated (and this is only the beginning of
231 independent of one another; the more essential object is the
236 one. The `async_action' structure is embedded in the `dhcp_smach_t'
242 operation is synchronous (not asynchronous) since after the RELEASE is
243 sent no reply is expected from the DHCP server, but DHCPv6 Release is
246 the system state, and thus do not require sequencing.
248 When the agent realizes it must perform an asynchronous transaction,
249 it calls async_async() to open the transaction. If one is already
250 pending, then the new transaction must fail (the details of failure
251 depend on how the transaction was initiated, which is described in
252 more detail later when the `ipc_action' object is discussed). If
253 there is no pending asynchronous transaction, the operation succeeds.
255 When the transaction is complete, either async_finish() or
256 async_cancel() must be called to complete or cancel the asynchronous
257 action on that state machine. If the transaction is unable to
259 should be used to cancel the operation.
261 The notion of asynchronous transactions is complicated by the fact
262 that they may originate from both inside and outside of the agent.
264 he performs an `ifconfig hme0 dhcp start', but the agent will
266 the lease before it expires. Note that user-initiated actions always
267 have priority over internal actions: the former will cancel the
270 This leads us into the `ipc_action' object. An `ipc_action'
271 represents the IPC-related pieces of an asynchronous transaction that
272 was started as a result of a user request, as well as the `BUSY' state
273 of the administrative interface. Only IPC-generated asynchronous
277 also conveniently be embedded inside the `dhcp_smach_t' structure).
279 One of the main purposes of the `ipc_action' object is to timeout user
280 events. When the user specifies a timeout value as an argument to
282 how long he is willing to wait for the command to complete. When this
283 time expires, the ipc_action is terminated, as well as the
286 The API provided for the `ipc_action' object is quite similar to the
287 one for the `async_action' object: when an IPC request comes in for an
289 called. When the request completes, ipc_action_finish() is called.
290 If the user times out before the request completes, then
298 behind a dozen or so interfaces (see packet.h) that abstract the
299 unimportant details away from the rest of the agent code. In order to
303 the `dhcp_smach_t', but this may change in the future.. After calling
304 init_pkt(), the add_pkt_opt*() functions are used to add options to
305 the DHCP packet. Finally, send_pkt() and send_pkt_v6() can be used to
306 transmit the packet to a given IP address.
308 The send_pkt() function handles the details of packet timeout and
310 "stop function." If this argument is passed as NULL, then the packet
312 each retransmission, the stop function will be called back prior to
314 to place a cap on the next timeout; this is done for DHCPv6 in
315 stop_init_reboot() in order to implement the CNF_MAX_RD constraint.
318 retransmission or not, which allows the send_pkt() caller to control
319 the retransmission policy without making it have to deal with the
323 The recv_pkt() function is simpler but still complicated by the fact
325 once. The caller registers an event handler on the file descriptor,
326 and then calls recv_pkt() to read in the packet along with meta
327 information about the message (the sender and interface identifier).
330 IPV6_PKTINFO to determine the actual destination address and receiving
331 interface. Packets are then matched against the state machines on the
332 given interface through the transaction ID.
334 For IPv4, due to oddities in the DHCP specification (discussed in
337 lease acquisition. Since the IP_DHCPINIT_IF socket option can only
344 five ways that time is represented in the source: as lease_t's,
348 The `lease_t' type is the simplest to understand; it is the unit of
349 time in the CD_{LEASE,T1,T2}_TIME options in a DHCP packet, as defined
351 to some fixed point in time) or the value `-1' (DHCP_PERM) which
353 used either when dealing with actual DHCP packets that are sent on the
354 wire or for variables which follow the exact definition given in the
358 seconds. However, here the value `-1' is not special and of course
363 The `time_t' type is the natural Unix type for representing time since
364 the epoch. Unfortunately, it is affected by stime(2) or adjtime(2)
365 and since the DHCP client is used during system installation (and thus
366 when time is typically being configured), the time_t cannot be used in
367 general to represent an absolute time since the epoch. For instance,
369 minute later stime(2) was called to adjust the system clock forward a
370 year, then the lease would appeared to have expired a year ago even
377 The `hrtime_t' type returned from gethrtime() works around the
378 limitations of the time_t in that it is not affected by stime(2) or
379 adjtime(2), with the disadvantage that it represents time from some
380 arbitrary time in the past and in nanoseconds. The timer queue code
382 meant to be fairly independent of the rest of the DHCP client.
384 However, dealing with nanoseconds is error-prone when all the other
385 time types are in seconds. As a result, yet another time type, the
389 been used. The function monosec() in util.c returns the current
391 time, using the system's current notion of time.
393 One additional limitation of the `hrtime_t' and `monosec_t' types is
394 that they are unaware of the passage of time across checkpoint/resume
396 gethrtime() returns time T, and then the machine is suspended for 2
397 hours, and then gethrtime() is called again, the time returned is not
401 when a system is resumed, the DHCP client makes the pessimistic
402 assumption that all finite leases have expired while the machine was
404 the leases, and is handled by refresh_smachs().
407 record the time(2) when the system is suspended, compare that against
408 the time(2) when the system is resumed, and use the delta between them
416 For the most part, the DHCP client only *retrieves* configuration data
417 from the DHCP server, leaving the configuration to scripts (such as
418 boot scripts), which themselves use dhcpinfo(1) to retrieve the data
419 from the DHCP client. This is desirable because it keeps the mechanism
420 of retrieving the configuration data decoupled from the policy of using
421 the data.
423 However, unless used in "inform" mode, the DHCP client *does*
425 other hosts. Specifically, the DHCP client configures the interface's
426 IP address, netmask, and broadcast address using the information
427 provided by the server. Further, for IPv4 logical interface 0
430 For IPv6, only the IP addresses are set. The netmask (prefix) is then
431 set automatically by in.ndpd, and routes are discovered in the usual
436 the kernel forwarding table, and in most cases, logical interfaces
437 share a default route with their associated physical interface, the
447 INFORM6 for DHCPv6. The user program runs asynchronous to the DHCP
448 client so that the main event loop stays active to process other
449 events, including events triggered by the user program (for example,
452 The user program execution is part of the transaction of a DHCP command.
453 For example, if the user program is not enabled, the transaction of the
454 DHCP command START is considered over when an ACK is received and the
455 interface is configured successfully. If the user program is enabled,
456 it is invoked after the interface is configured successfully, and the
457 transaction is considered over only when the user program exits. The
458 event scripting implementation makes use of the asynchronous operations
459 discussed in the "Transactions" section.
461 An upper bound of 58 seconds is imposed on how long the user program
462 can run. If the user program does not exit after 55 seconds, the signal
464 seconds, the signal SIGKILL is sent to it. Since the event handler is
465 a wrapper around poll(), the DHCP client cannot directly observe the
466 completion of the user program. Instead, the DHCP client creates a
467 child "helper" process to synchronously monitor the user program (this
468 process is also used to send the aformentioned signals to the process,
469 if necessary). The DHCP client and the helper process share a pipe
470 which is included in the set of poll descriptors monitored by the DHCP
471 client's event handler. When the user program exits, the helper process
472 passes the user program exit status to the DHCP client through the pipe,
473 informing the DHCP client that the user program has finished. When the
475 of the user program to complete.