1CDDL HEADER START 2 3The contents of this file are subject to the terms of the 4Common Development and Distribution License (the "License"). 5You may not use this file except in compliance with the License. 6 7You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 8or http://www.opensolaris.org/os/licensing. 9See the License for the specific language governing permissions 10and limitations under the License. 11 12When distributing Covered Code, include this CDDL HEADER in each 13file and include the License file at usr/src/OPENSOLARIS.LICENSE. 14If applicable, add the following below this CDDL HEADER, with the 15fields enclosed by brackets "[]" replaced with your own identifying 16information: Portions Copyright [yyyy] [name of copyright owner] 17 18CDDL HEADER END 19 20Copyright 2007 Sun Microsystems, Inc. All rights reserved. 21Use is subject to license terms. 22 23ident "%Z%%M% %I% %E% SMI" 24 25 26** PLEASE NOTE: 27** 28** This document discusses aspects of the DHCPv4 client design that have 29** since changed (e.g., DLPI is no longer used). However, since those 30** aspects affected the DHCPv6 design, the discussion has been left for 31** historical record. 32 33 34DHCPv6 Client Low-Level Design 35 36Introduction 37 38 This project adds DHCPv6 client-side (not server) support to 39 Solaris. Future projects may add server-side support as well as 40 enhance the basic capabilities added here. These future projects 41 are not discussed in detail in this document. 42 43 This document assumes that the reader is familiar with the following 44 other documents: 45 46 - RFC 3315: the primary description of DHCPv6 47 - RFCs 2131 and 2132: IPv4 DHCP 48 - RFCs 2461 and 2462: IPv6 NDP and stateless autoconfiguration 49 - RFC 3484: IPv6 default address selection 50 - ifconfig(1M): Solaris IP interface configuration 51 - in.ndpd(1M): Solaris IPv6 Neighbor and Router Discovery daemon 52 - dhcpagent(1M): Solaris DHCP client 53 - dhcpinfo(1): Solaris DHCP parameter utility 54 - ndpd.conf(4): in.ndpd configuration file 55 - netstat(1M): Solaris network status utility 56 - snoop(1M): Solaris network packet capture and inspection 57 - "DHCPv6 Client High-Level Design" 58 59 Several terms from those documents (such as the DHCPv6 IA_NA and 60 IAADDR options) are used without further explanation in this 61 document; see the reference documents above for details. 62 63 The overall plan is to enhance the existing Solaris dhcpagent so 64 that it is able to process DHCPv6. It would also have been possible 65 to create a new, separate daemon process for this, or to integrate 66 the feature into in.ndpd. These alternatives, and the reason for 67 the chosen design, are discussed in Appendix A. 68 69 This document discusses the internal design issues involved in the 70 protocol implementation, and with the associated components (such as 71 in.ndpd, snoop, and the kernel's source address selection 72 algorithm). It does not discuss the details of the protocol itself, 73 which are more than adequately described in the RFC, nor the 74 individual lines of code, which will be in the code review. 75 76 As a cross-reference, Appendix B has a summary of the components 77 involved and the changes to each. 78 79 80Background 81 82 In order to discuss the design changes for DHCPv6, it's necessary 83 first to talk about the current IPv4-only design, and the 84 assumptions built into that design. 85 86 The main data structure used in dhcpagent is the 'struct ifslist'. 87 Each instance of this structure represents a Solaris logical IP 88 interface under DHCP's control. It also represents the shared state 89 with the DHCP server that granted the address, the address itself, 90 and copies of the negotiated options. 91 92 There is one list in dhcpagent containing all of the IP interfaces 93 that are under DHCP control. IP interfaces not under DHCP control 94 (for example, those that are statically addressed) are not included 95 in this list, even when plumbed on the system. These ifslist 96 entries are chained like this: 97 98 ifsheadp -> ifslist -> ifslist -> ifslist -> NULL 99 net0 net0:1 net1 100 101 Each ifslist entry contains the address, mask, lease information, 102 interface name, hardware information, packets, protocol state, and 103 timers. The name of the logical IP interface under DHCP's control 104 is also the name used in the administrative interfaces (dhcpinfo, 105 ifconfig) and when logging events. 106 107 Each entry holds open a DLPI stream and two sockets. The DLPI 108 stream is nulled-out with a filter when not in use, but still 109 consumes system resources. (Most significantly, it causes data 110 copies in the driver layer that end up sapping performance.) 111 112 The entry storage is managed by a insert/hold/release/remove model 113 and reference counts. In this model, insert_ifs() allocates a new 114 ifslist entry and inserts it into the global list, with the global 115 list holding a reference. remove_ifs() removes it from the global 116 list and drops that reference. hold_ifs() and release_ifs() are 117 used by data structures that refer to ifslist entries, such as timer 118 entries, to make sure that the ifslist entry isn't freed until the 119 timer has been dispatched or deleted. 120 121 The design is single-threaded, so code that walks the global list 122 needn't bother taking holds on the ifslist structure. Only 123 references that may be used at a different time (i.e., pointers 124 stored in other data structures) need to be recorded. 125 126 Packets are handled using PKT (struct dhcp; <netinet/dhcp.h>), 127 PKT_LIST (struct dhcp_list; <dhcp_impl.h>), and dhcp_pkt_t (struct 128 dhcp_pkt; "packet.h"). PKT is just the RFC 2131 DHCP packet 129 structure, and has no additional information, such as packet length. 130 PKT_LIST contains a PKT pointer, length, decoded option arrays, and 131 linkage for putting the packet in a list. Finally, dhcp_pkt_t has a 132 PKT pointer and length values suitable for modifying the packet. 133 134 Essentially, PKT_LIST is a wrapper for received packets, and 135 dhcp_pkt_t is a wrapper for packets to be sent. 136 137 The basic PKT structure is used in dhcpagent, inetboot, in.dhcpd, 138 libdhcpagent, libwanboot, libdhcputil, and others. PKT_LIST is used 139 in a similar set of places, including the kernel NFS modules. 140 dhcp_pkt_t is (as the header file implies) limited to dhcpagent. 141 142 In addition to these structures, dhcpagent maintains a set of 143 internal supporting abstractions. Two key ones involved in this 144 project are the "async operation" and the "IPC action." An async 145 operation encapsulates the actions needed for a given operation, so 146 that if cancellation is needed, there's a single point where the 147 associated resources can be freed. An IPC action represents the 148 user state related to the private interface used by ifconfig. 149 150 151DHCPv6 Inherent Differences 152 153 DHCPv6 naturally has some commonality with IPv4 DHCP, but also has 154 some significant differences. 155 156 Unlike IPv4 DHCP, DHCPv6 relies on link-local IP addresses to do its 157 work. This means that, on Solaris, the client doesn't need DLPI to 158 perform any of the I/O; regular IP sockets will do the job. It also 159 means that, unlike IPv4 DHCP, DHCPv6 does not need to obtain a lease 160 for the address used in its messages to the server. The system 161 provides the address automatically. 162 163 IPv4 DHCP expects some messages from the server to be broadcast. 164 DHCPv6 has no such mechanism; all messages from the server to the 165 client are unicast. In the case where the client and server aren't 166 on the same subnet, a relay agent is used to get the unicast replies 167 back to the client's link-local address. 168 169 With IPv4 DHCP, a single address plus configuration options is 170 leased with a given client ID and a single state machine instance, 171 and the implementation binds that to a single IP logical interface 172 specified by the user. The lease has a "Lease Time," a required 173 option, as well as two timers, called T1 (renew) and T2 (rebind), 174 which are controlled by regular options. 175 176 DHCPv6 uses a single client/server session to control the 177 acquisition of configuration options and "identity associations" 178 (IAs). The identity associations, in turn, contain lists of 179 addresses for the client to use and the T1/T2 timer values. Each 180 individual address has its own preferred and valid lifetime, with 181 the address being marked "deprecated" at the end of the preferred 182 interval, and removed at the end of the valid interval. 183 184 IPv4 DHCP leaves many of the retransmit decisions up to the client, 185 and some things (such as RELEASE and DECLINE) are sent just once. 186 Others (such as the REQUEST message used for renew and rebind) are 187 dealt with by heuristics. DHCPv6 treats each message to the server 188 as a separate transaction, and resends each message using a common 189 retransmission mechanism. DHCPv6 also has separate messages for 190 Renew, Rebind, and Confirm rather than reusing the Request 191 mechanism. 192 193 The set of options (which are used to convey configuration 194 information) for each protocol are distinct. Notably, two of the 195 mistakes from IPv4 DHCP have been fixed: DHCPv6 doesn't carry a 196 client name, and doesn't attempt to impersonate a routing protocol 197 by setting a "default route." 198 199 Another welcome change is the lack of a netmask/prefix length with 200 DHCPv6. Instead, the client uses the Router Advertisement prefixes 201 to set the correct interface netmask. This reduces the number of 202 databases that need to be kept in sync. (The equivalent mechanism 203 in IPv4 would have been the use of ICMP Address Mask Request / 204 Reply, but the BOOTP designers chose to embed it in the address 205 assignment protocol itself.) 206 207 Otherwise, DHCPv6 is similar to IPv4 DHCP. The same overall 208 renew/rebind and lease expiry strategy is used, although the state 209 machine events must now take into account multiple IAs and the fact 210 that each can cause RENEWING or REBINDING state independently. 211 212 213DHCPv6 And Solaris 214 215 The protocol distinctions above have several important implications. 216 For the logical interfaces: 217 218 - Because Solaris uses IP logical interfaces to configure 219 addresses, we must have multiple IP logical interfaces per IA 220 with IPv6. 221 222 - Because we need to support multiple addresses (and thus multiple 223 IP logical interfaces) per IA and multiple IAs per client/server 224 session, the IP logical interface name isn't a unique name for 225 the lease. 226 227 As a result, IP logical interfaces will come and go with DHCPv6, 228 just as happens with the existing stateless address 229 autoconfiguration support in in.ndpd. The logical interface names 230 (visible in ifconfig) have no administrative significance. 231 232 Fortunately, DHCPv6 does end up with one fixed name that can be used 233 to identify a session. Because DHCPv6 uses link local addresses for 234 communication with the server, the name of the IP logical interface 235 that has this link local address (normally the same as the IP 236 physical interface) can be used as an identifier for dhcpinfo and 237 logging purposes. 238 239 240Dhcpagent Redesign Overview 241 242 The redesign starts by refactoring the IP interface representation. 243 Because we need to have multiple IP logical interfaces (LIFs) for a 244 single identity association (IA), we should not store all of the 245 DHCP state information along with the LIF information. 246 247 For DHCPv6, we will need to keep LIFs on a single IP physical 248 interface (PIF) together, so this is probably also a good time to 249 reconsider the way dhcpagent represents physical interfaces. The 250 current design simply replicates the state (notably the DLPI stream, 251 but also the hardware address and other bits) among all of the 252 ifslist entries on the same physical interface. 253 254 The new design creates two lists of dhcp_pif_t entries, one list for 255 IPv4 and the other for IPv6. Each dhcp_pif_t represents a PIF, with 256 a list of dhcp_lif_t entries attached, each of which represents a 257 LIF used by dhcpagent. This structure mirrors the kernel's ill_t 258 and ipif_t interface representations. 259 260 Next, the lease-tracking needs to be refactored. DHCPv6 is the 261 functional superset in this case, as it has two lifetimes per 262 address (LIF) and IA groupings with shared T1/T2 timers. To 263 represent these groupings, we will use a new dhcp_lease_t structure. 264 IPv4 DHCP will have one such structure per state machine, while 265 DHCPv6 will have a list. (Note: the initial implementation will 266 have only one lease per DHCPv6 state machine, because each state 267 machine uses a single link-local address, a single DUID+IAID pair, 268 and supports only Non-temporary Addresses [IA_NA option]. Future 269 enhancements may use multiple leases per DHCPv6 state machine or 270 support other IA types.) 271 272 For all of these new structures, we will use the same insert/hold/ 273 release/remove model as with the original ifslist. 274 275 Finally, the remaining items (and the bulk of the original ifslist 276 members) are kept on a per-state-machine basis. As this is no 277 longer just an "interface," a new dhcp_smach_t structure will hold 278 these, and the ifslist structure is gone. 279 280 281Lease Representation 282 283 For DHCPv6, we need to track multiple LIFs per lease (IA), but we 284 also need multiple LIFs per PIF. Rather than having two sets of 285 list linkage for each LIF, we can observe that a LIF is on exactly 286 one PIF and is a member of at most one lease, and then simplify: the 287 lease structure will use a base pointer for the first LIF in the 288 lease, and a count for the number of consecutive LIFs in the PIF's 289 list of LIFs that belong to the lease. 290 291 When removing a LIF from the system, we need to decrement the count 292 of LIFs in the lease, and advance the base pointer if the LIF being 293 removed is the first one. Inserting a LIF means just moving it into 294 this list and bumping the counter. 295 296 When removing a lease from a state machine, we need to dispose of 297 the LIFs referenced. If the LIF being disposed is the main LIF for 298 a state machine, then all that we can do is canonize the LIF 299 (returning it to a default state); this represents the normal IPv4 300 DHCP operation on lease expiry. Otherwise, the lease is the owner 301 of that LIF (it was created because of a DHCPv6 IA), and disposal 302 means unplumbing the LIF from the actual system and removing the LIF 303 entry from the PIF. 304 305 306Main Structure Linkage 307 308 For IPv4 DHCP, the new linkage is straightforward. Using the same 309 system configuration example as in the initial design discussion: 310 311 +- lease +- lease +- lease 312 | ^ | ^ | ^ 313 | | | | | | 314 \ smach \ smach \ smach 315 \ ^| \ ^| \ ^| 316 v|v v|v v|v 317 lif ----> lif -> NULL lif -> NULL 318 net0 net0:1 net1 319 ^ ^ 320 | | 321 v4root -> pif --------------------> pif -> NULL 322 net0 net1 323 324 This diagram shows three separate state machines running (with 325 backpointers omitted for clarity). Each state machine has a single 326 "main" LIF with which it's associated (and named). Each also has a 327 single lease structure that points back to the same LIF (count of 328 1), because IPv4 DHCP controls a single address allocation per state 329 machine. 330 331 DHCPv6 is a bit more complex. This shows DHCPv6 running on two 332 interfaces (more or fewer interfaces are of course possible) and 333 with multiple leases on the first interface, and each lease with 334 multiple addresses (one with two addresses, the second with one). 335 336 lease ----------------> lease -> NULL lease -> NULL 337 ^ \(2) |(1) ^ \ (1) 338 | \ | | \ 339 smach \ | smach \ 340 ^ | \ | ^ | \ 341 | v v v | v v 342 lif --> lif --> lif --> lif --> NULL lif --> lif -> NULL 343 net0 net0:1 net0:4 net0:2 net1 net1:5 344 ^ ^ 345 | | 346 v6root -> pif ----------------------------------> pif -> NULL 347 net0 net1 348 349 Note that there's intentionally no ordering based on name in the 350 list of LIFs. Instead, the contiguous LIF structures in that list 351 represent the addresses in each lease. The logical interfaces 352 themselves are allocated and numbered by the system kernel, so they 353 may not be sequential, and there may be gaps in the list if other 354 entities (such as in.ndpd) are also configuring interfaces. 355 356 Note also that with IPv4 DHCP, the lease points to the LIF that's 357 also the main LIF for the state machine, because that's the IP 358 interface that dhcpagent controls. With DHCPv6, the lease (one per 359 IA structure) points to a separate set of LIFs that are created just 360 for the leased addresses (one per IA address in an IAADDR option). 361 The state machine alone points to the main LIF. 362 363 364Packet Structure Extensions 365 366 Obviously, we need some DHCPv6 packet data structures and 367 definitions. A new <netinet/dhcp6.h> file will be introduced with 368 the necessary #defines and structures. The key structure there will 369 be: 370 371 struct dhcpv6_message { 372 uint8_t d6m_msg_type; 373 uint8_t d6m_transid_ho; 374 uint16_t d6m_transid_lo; 375 }; 376 typedef struct dhcpv6_message dhcpv6_message_t; 377 378 This defines the usual (non-relay) DHCPv6 packet header, and is 379 roughly equivalent to PKT for IPv4. 380 381 Extending dhcp_pkt_t for DHCPv6 is straightforward, as it's used 382 only within dhcpagent. This structure will be amended to use a 383 union for v4/v6 and include a boolean to flag which version is in 384 use. 385 386 For the PKT_LIST structure, things are more complex. This defines 387 both a queuing mechanism for received packets (typically OFFERs) and 388 a set of packet decoding structures. The decoding structures are 389 highly specific to IPv4 DHCP -- they have no means to handle nested 390 or repeated options (as used heavily in DHCPv6) and make use of the 391 DHCP_OPT structure which is specific to IPv4 DHCP -- and are 392 somewhat expensive in storage, due to the use of arrays indexed by 393 option code number. 394 395 Worse, this structure is used throughout the system, so changes to 396 it need to be made carefully. (For example, the existing 'pkt' 397 member can't just be turned into a union.) 398 399 For an initial prototype, since discarded, I created a new 400 dhcp_plist_t structure to represent packet lists as used inside 401 dhcpagent and made dhcp_pkt_t valid for use on input and output. 402 The result is unsatisfying, though, as it results in code that 403 manipulates far too many data structures in common cases; it's a sea 404 of pointers to pointers. 405 406 The better answer is to use PKT_LIST for both IPv4 and IPv6, adding 407 the few new bits of metadata required to the end (receiving ifIndex, 408 packet source/destination addresses), and staying within the overall 409 existing design. 410 411 For option parsing, dhcpv6_find_option() and dhcpv6_pkt_option() 412 functions will be added to libdhcputil. The former function will 413 walk a DHCPv6 option list, and provide safe (bounds-checked) access 414 to the options inside. The function can be called recursively, so 415 that option nesting can be handled fairly simply by nested loops, 416 and can be called repeatedly to return each instance of a given 417 option code number. The latter function is just a convenience 418 wrapper on dhcpv6_find_option() that starts with a PKT_LIST pointer 419 and iterates over the top-level options with a given code number. 420 421 There are two special considerations for the use of these library 422 interfaces: there's no "pad" option for DHCPv6 or alignment 423 requirements on option headers or contents, and nested options 424 always follow a structure that has type-dependent length. This 425 means that code that handles options must all be written to deal 426 with unaligned data, and suboption code must index the pointer past 427 the type-dependent part. 428 429 430Packet Construction 431 432 Unlike DHCPv4, DHCPv6 places the transaction timer value in an 433 option. The existing code sets the current time value in 434 send_pkt_internal(), which allows it to be updated in a 435 straightforward way when doing retransmits. 436 437 To make this work in a simple manner for DHCPv6, I added a 438 remove_pkt_opt() function. The update logic just does a remove and 439 re-adds the option. We could also just assume the presence of the 440 option, find it, and modify in place, but the remove feature seems 441 more general. 442 443 DHCPv6 uses nesting options. To make this work, two new utility 444 functions are needed. First, an add_pkt_subopt() function will take 445 a pointer to an existing option and add an embedded option within 446 it. The packet length and existing option length are updated. If 447 that existing option isn't a top-level option, though, this means 448 that the caller must update the lengths of all of the enclosing 449 options up to the top level. To do this, update_v6opt_len() will be 450 added. This is used in the special case of adding a Status Code 451 option to an IAADDR option within an IA_NA top-level option. 452 453 454Sockets and I/O Handling 455 456 DHCPv6 doesn't need or use either a DLPI or a broadcast IP socket. 457 Instead, a single unicast-bound IP socket on a link-local address 458 would be the most that is needed. This is roughly equivalent to 459 if_sock_ip_fd in the existing design, but that existing socket is 460 bound only after DHCP reaches BOUND state -- that is, when it 461 switches away from DLPI. We need something different. 462 463 This, along with the excess of open file descriptors in an otherwise 464 idle daemon and the potentially serious performance problems in 465 leaving DLPI open at all times, argues for a larger redesign of the 466 I/O logic in dhcpagent. 467 468 The first thing that we can do is eliminate the need for the 469 per-ifslist if_sock_fd. This is used primarily for issuing ioctls 470 to configure interfaces -- a task that would work as well with any 471 open socket -- and is also registered to receive any ACK/NAK packets 472 that may arrive via broadcast. Both of these can be eliminated by 473 creating a pair of global sockets (IPv4 and IPv6), bound and 474 configured for ACK/NAK reception. The only functional difference is 475 that the list of running state machines must be scanned on reception 476 to find the correct transaction ID, but the existing design 477 effectively already goes to this effort because the kernel 478 replicates received datagrams among all matching sockets, and each 479 ifslist entry has a socket open. 480 481 (The existing code for if_sock_fd makes oblique reference to unknown 482 problems in the system that may prevent binding from working in some 483 cases. The reference dates back some seven years to the original 484 DHCP implementation. I've observed no such problems in extensive 485 testing and if any do show up, they will be dealt with by fixing the 486 underlying bugs.) 487 488 This leads to an important simplification: it's no longer necessary 489 to register, unregister, and re-register for packet reception while 490 changing state -- register_acknak() and unregister_acknak() are 491 gone. Instead, we always receive, and we dispatch the packets as 492 they arrive. As a result, when receiving a DHCPv4 ACK or DHCPv6 493 Reply when in BOUND state, we know it's a duplicate, and we can 494 discard. 495 496 The next part is in minimizing DLPI usage. A DLPI stream is needed 497 at most for each IPv4 PIF, and it's not needed when all of the 498 DHCP instances on that PIF are bound. In fact, the current 499 implementation deals with this in configure_bound() by setting a 500 "blackhole" packet filter. The stream is left open. 501 502 To simplify this, we will open at most one DLPI stream on a PIF, and 503 use reference counts from the state machines to determine when the 504 stream must be open and when it can be closed. This mechanism will 505 be centralized in a set_smach_state() function that changes the 506 state and opens/closes the DLPI stream when needed. 507 508 This leads to another simplification. The I/O logic in the existing 509 dhcpagent makes use of the protocol state to select between DLPI and 510 sockets. Now that we keep track of this in a simpler manner, we no 511 longer need to switch out on state in when sending a packet; just 512 test the dsm_using_dlpi flag instead. 513 514 Still another simplification is in the handling of DHCPv4 INFORM. 515 The current code has separate logic in it for getting the interface 516 state and address information. This is no longer necessary, as the 517 LIF mechanism keeps track of the interface state. And since we have 518 separate lease structures, and INFORM doesn't acquire a lease, we no 519 longer have to be careful about canonizing the interface on 520 shutdown. 521 522 Although the default is to send all client messages to a well-known 523 multicast address for servers and relays, DHCPv6 also has a 524 mechanism that allows the client to send unicast messages to the 525 server. The operation of this mechanism is slightly complex. 526 First, the server sends the client a unicast address via an option. 527 We may use this address as the destination (rather than the 528 well-known multicast address for local DHCPv6 servers and relays) 529 only if we have a viable local source address. This means using 530 SIOCGDSTINFO each time we try to send unicast. Next, the server may 531 send back a special status code: UseMulticast. If this is received, 532 and if we were actually using unicast in our messages to the server, 533 then we need to forget the unicast address, switch back to 534 multicast, and resend our last message. 535 536 Note that it's important to avoid the temptation to resend the last 537 message every time UseMulticast is seen, and do it only once on 538 switching back to multicast: otherwise, a potential feedback loop is 539 created. 540 541 Because IP_PKTINFO (PSARC 2006/466) has integrated, we could go a 542 step further by removing the need for any per-LIF sockets and just 543 use the global sockets for all but DLPI. However, in order to 544 facilitate a Solaris 10 backport, this will be done separately as CR 545 6509317. 546 547 In the case of DHCPv6, we already have IPV6_PKTINFO, so we will pave 548 the way for IPv4 by beginning to using this now, and thus have just 549 a single socket (bound to "::") for all of DHCPv6. Doing this 550 requires switching from the old BSD4.2 -lsocket -lnsl to the 551 standards-compliant -lxnet in order to use ancillary data. 552 553 It may also be possible to remove the need for DLPI for IPv4, and 554 incidentally simplify the code a fair amount, by adding a kernel 555 option to allow transmission and reception of UDP packets over 556 interfaces that are plumbed but not marked IFF_UP. This is left for 557 future work. 558 559 560The State Machine 561 562 Several parts of the existing state machine need additions to handle 563 DHCPv6, which is a superset of DHCPv4. 564 565 First, there are the RENEWING and REBINDING states. For IPv4 DHCP, 566 these states map one-to-one with a single address and single lease 567 that's undergoing renewal. It's a simple progression (on timeout) 568 from BOUND, to RENEWING, to REBINDING and finally back to SELECTING 569 to start over. Each retransmit is done by simply rescheduling the 570 T1 or T2 timer. 571 572 For DHCPv6, things are somewhat more complex. At any one time, 573 there may be multiple IAs (leases) that are effectively in renewing 574 or rebinding state, based on the T1/T2 timers for each IA, and many 575 addresses that have expired. 576 577 However, because all of the leases are related to a single server, 578 and that server either responds to our requests or doesn't, we can 579 simplify the states to be nearly identical to IPv4 DHCP. 580 581 The revised definition for use with DHCPv6 is: 582 583 - Transition from BOUND to RENEWING state when the first T1 timer 584 (of any lease on the state machine) expires. At this point, as 585 an optimization, we should begin attempting to renew any IAs 586 that are within REN_TIMEOUT (10 seconds) of reaching T1 as well. 587 We may as well avoid sending an excess of packets. 588 589 - When a T1 lease timer expires and we're in RENEWING or REBINDING 590 state, just ignore it, because the transaction is already in 591 progress. 592 593 - At each retransmit timeout, we should check to see if there are 594 more IAs that need to join in because they've passed point T1 as 595 well, and, if so, add them. This check isn't necessary at this 596 time, because only a single IA_NA is possible with the initial 597 design. 598 599 - When we reach T2 on any IA and we're in BOUND or RENEWING state, 600 enter REBINDING state. At this point, we have a choice. For 601 those other IAs that are past T1 but not yet at T2, we could 602 ignore them (sending only those that have passed point T2), 603 continue to send separate Renew messages for them, or just 604 include them in the Rebind message. This isn't an issue that 605 must be dealt with for this project, but the plan is to include 606 them in the Rebind message. 607 608 - When a T2 lease timer expires and we're in REBINDING state, just 609 ignore it, as with the corresponding T1 timer. 610 611 - As addresses reach the end of their preferred lifetimes, set the 612 IFF_DEPRECATED flag. As they reach the end of the valid 613 lifetime, remove them from the system. When an IA (lease) 614 becomes empty, just remove it. When there are no more leases 615 left, return to SELECTING state to start over. 616 617 Note that the RFC treats the IAs as separate entities when 618 discussing the renew/rebind T1/T2 timers, but treats them as a unit 619 when doing the initial negotiation. This is, to say the least, 620 confusing, especially so given that there's no reason to expect that 621 after having failed to elicit any responses at all from the server 622 on one IA, the server will suddenly start responding when we attempt 623 to renew some other IA. We rationalize this behavior by using a 624 single renew/rebind state for the entire state machine (and thus 625 client/server pair). 626 627 There's a subtle timing difference here between DHCPv4 and DHCPv6. 628 For DHCPv4, the client just sends packets more and more frequently 629 (shorter timeouts) as the next state gets nearer. DHCPv6 treats 630 each as a transaction, using the same retransmit logic as for other 631 messages. The DHCPv6 method is a cleaner design, so we will change 632 the DHCPv4 implementation to do the same, and compute the new timer 633 values as part of stop_extending(). 634 635 Note that it would be possible to start the SELECTING state earlier 636 than waiting for the last lease to expire, and thus avoid a loss of 637 connectivity. However, it this point, there are other servers on 638 the network that have seen us attempting to Rebind for quite some 639 time, and they have not responded. The likelihood that there's a 640 server that will ignore Rebind but then suddenly spring into action 641 on a Solicit message seems low enough that the optimization won't be 642 done now. (Starting SELECTING state earlier may be done in the 643 future, if it's found to be useful.) 644 645 646Persistent State 647 648 IPv4 DHCP has only minimal need for persistent state, beyond the 649 configuration parameters. The state is stored when "ifconfig dhcp 650 drop" is run or the daemon receives SIGTERM, which is typically done 651 only well after the system is booted and running. 652 653 The daemon stores this state in /etc/dhcp, because it needs to be 654 available when only the root file system has been mounted. 655 656 Moreover, dhcpagent starts very early in the boot process. It runs 657 as part of svc:/network/physical:default, which runs well before 658 root is mounted read/write: 659 660 svc:/system/filesystem/root:default -> 661 svc:/system/metainit:default -> 662 svc:/system/identity:node -> 663 svc:/network/physical:default 664 svc:/network/iscsi_initiator:default -> 665 svc:/network/physical:default 666 667 and, of course, well before either /var or /usr is mounted. This 668 means that any persistent state must be kept in the root file 669 system, and that if we write before shutdown, we have to cope 670 gracefully with the root file system returning EROFS on write 671 attempts. 672 673 For DHCPv6, we need to try to keep our stable DUID and IAID values 674 stable across reboots to fulfill the demands of RFC 3315. 675 676 The DUID is either configured or automatically generated. When 677 configured, it comes from the /etc/default/dhcpagent file, and thus 678 does not need to be saved by the daemon. If automatically 679 generated, there's exactly one of these created, and it will 680 eventually be needed before /usr is mounted, if /usr is mounted over 681 IPv6. This means a new file in the root file system, 682 /etc/dhcp/duid, will be used to hold the automatically generated 683 DUID. 684 685 The determination of whether to use a configured DUID or one saved 686 in a file is made in get_smach_cid(). This function will 687 encapsulate all of the DUID parsing and generation machinery for the 688 rest of dhcpagent. 689 690 If root is not writable at the point when dhcpagent starts, and our 691 attempt fails with EROFS, we will set a timer for 60 second 692 intervals to retry the operation periodically. In the unlikely case 693 that it just never succeeds or that we're rebooted before root 694 becomes writable, then the impact will be that the daemon will wake 695 up once a minute and, ultimately, we'll choose a different DUID on 696 next start-up, and we'll thus lose our leases across a reboot. 697 698 The IAID similarly must be kept stable if at all possible, but 699 cannot be configured by the user. To do make these values stable, 700 we will use two strategies. First the IAID value for a given 701 interface (if not known) will just default to the IP ifIndex value, 702 provided that there's no known saved IAID using that value. Second, 703 we will save off the IAID we choose in a single /etc/dhcp/iaid file, 704 containing an array of entries indexed by logical interface name. 705 Keeping it in a single file allows us to scan for used and unused 706 IAID values when necessary. 707 708 This mechanism depends on the interface name, and thus will need to 709 be revisited when Clearview vanity naming and NWAM are available. 710 711 Currently, the boot system (GRUB, OBP, the miniroot) does not 712 support installing over IPv6. This could change in the future, so 713 one of the goals of the above stability plan is to support that 714 event. 715 716 When running in the miniroot on an x86 system, /etc/dhcp (and the 717 rest of the root) is mounted on a read-only ramdisk. In this case, 718 writing to /etc/dhcp will just never work. A possible solution 719 would be to add a new privileged command in ifconfig that forces 720 dhcpagent to write to an alternate location. The initial install 721 process could then do "ifconfig <x> dhcp write /a" to get the needed 722 state written out to the newly-constructed system root. 723 724 This part (the new write option) won't be implemented as part of 725 this project, because it's not needed yet. 726 727 728Router Advertisements 729 730 IPv6 Router Advertisements perform two functions related to DHCPv6: 731 732 - they specify whether and how to run DHCPv6 on a given interface. 733 - they provide a list of the valid prefixes on an interface. 734 735 For the first function, in.ndpd needs to use the same DHCP control 736 interfaces that ifconfig uses, so that it can launch dhcpagent and 737 trigger DHCPv6 when necessary. Note that it never needs to shut 738 down DHCPv6, as router advertisements can't do that. 739 740 However, launching dhcpagent presents new problems. As a part of 741 the "Quagga SMF Modifications" project (PSARC 2006/552), in.ndpd in 742 Nevada is now privilege-aware and runs with limited privileges, 743 courtesy of SMF. Dhcpagent, on the other hand, must run with all 744 privileges. 745 746 A simple work-around for this issue is to rip out the "privileges=" 747 clause from the method_credential for in.ndpd. I've taken this 748 direction initially, but the right longer-term answer seems to be 749 converting dhcpagent into an SMF service. This is quite a bit more 750 complex, as it means turning the /sbin/dhcpagent command line 751 interface into a utility that manipulates the service and passes the 752 command line options via IPC extensions. 753 754 Such a design also begs the question of whether dhcpagent itself 755 ought to run with reduced privileges. It could, but it still needs 756 the ability to grant "all" (traditional UNIX root) privileges to the 757 eventhook script, if present. There seem to be few ways to do this, 758 though it's a good area for research. 759 760 The second function, prefix handling, is also subtle. Unlike IPv4 761 DHCP, DHCPv6 does not give the netmask or prefix length along with 762 the leased address. The client is on its own to determine the right 763 netmask to use. This is where the advertised prefixes come in: 764 these must be used to finish the interface configuration. 765 766 We will have the DHCPv6 client configure each interface with an 767 all-ones (/128) netmask by default. In.ndpd will be modified so 768 that when it detects a new IFF_DHCPRUNNING IP logical interface, it 769 checks for a known matching prefix, and sets the netmask as 770 necessary. If no matching prefix is known, it will send a new 771 Router Solicitation message to try to find one. 772 773 When in.ndpd learns of a new prefix from a Router Advertisement, it 774 will scan all of the IFF_DHCPRUNNING IP logical interfaces on the 775 same physical interface and set the netmasks when necessary. 776 Dhcpagent, for its part, will ignore the netmask on IPv6 interfaces 777 when checking for changes that would require it to "abandon" the 778 interface. 779 780 Given the way that DHCPv6 and in.ndpd control both the horizontal 781 and the vertical in plumbing and removing logical interfaces, and 782 users do not, it might be worthwhile to consider roping off any 783 direct user changes to IPv6 logical interfaces under control of 784 in.ndpd or dhcpagent, and instead force users through a higher-level 785 interface. This won't be done as part of this project, however. 786 787 788ARP Hardware Types 789 790 There are multiple places within the DHCPv6 client where the mapping 791 of DLPI MAC type to ARP Hardware Type is required: 792 793 - When we are constructing an automatic, stable DUID for our own 794 identity, we prefer to use a DUID-LLT if possible. This is done 795 by finding a link-layer interface, opening it, reading the MAC 796 address and type, and translating in the make_stable_duid() 797 function in libdhcpagent. 798 799 - When we translate a user-configured DUID from 800 /etc/default/dhcpagent into a binary representation, we may have 801 to deal with a physical interface name. In this case, we must 802 open that interface and read the MAC address and type. 803 804 - As part of the PIF data structure initialization, we need to read 805 out the MAC type so that it can be used in the BOOTP/DHCPv4 806 'htype' field. 807 808 Ideally, these would all be provided by a single libdlpi 809 implementation. However, that project is on-going at this time and 810 has not yet integrated. For the time being, a dlpi_to_arp() 811 translation function (taking dl_mac_type and returning an ARP 812 Hardware Type number) will be placed in libdhcputil. 813 814 This temporary function should be removed and this section of the 815 code updated when the new libdlpi from Clearview integrates. 816 817 818Field Mappings 819 820 Old (all in ifslist) New 821 next dhcp_smach_t.dsm_next 822 prev dhcp_smach_t.dsm_prev 823 if_hold_count dhcp_smach_t.dsm_hold_count 824 if_ia dhcp_smach_t.dsm_ia 825 if_async dhcp_smach_t.dsm_async 826 if_state dhcp_smach_t.dsm_state 827 if_dflags dhcp_smach_t.dsm_dflags 828 if_name dhcp_smach_t.dsm_name (see text) 829 if_index dhcp_pif_t.pif_index 830 if_max dhcp_lif_t.lif_max and dhcp_pif_t.pif_max 831 if_min (was unused; removed) 832 if_opt (was unused; removed) 833 if_hwaddr dhcp_pif_t.pif_hwaddr 834 if_hwlen dhcp_pif_t.pif_hwlen 835 if_hwtype dhcp_pif_t.pif_hwtype 836 if_cid dhcp_smach_t.dsm_cid 837 if_cidlen dhcp_smach_t.dsm_cidlen 838 if_prl dhcp_smach_t.dsm_prl 839 if_prllen dhcp_smach_t.dsm_prllen 840 if_daddr dhcp_pif_t.pif_daddr 841 if_dlen dhcp_pif_t.pif_dlen 842 if_saplen dhcp_pif_t.pif_saplen 843 if_sap_before dhcp_pif_t.pif_sap_before 844 if_dlpi_fd dhcp_pif_t.pif_dlpi_fd 845 if_sock_fd v4_sock_fd and v6_sock_fd (globals) 846 if_sock_ip_fd dhcp_lif_t.lif_sock_ip_fd 847 if_timer (see text) 848 if_t1 dhcp_lease_t.dl_t1 849 if_t2 dhcp_lease_t.dl_t2 850 if_lease dhcp_lif_t.lif_expire 851 if_nrouters dhcp_smach_t.dsm_nrouters 852 if_routers dhcp_smach_t.dsm_routers 853 if_server dhcp_smach_t.dsm_server 854 if_addr dhcp_lif_t.lif_v6addr 855 if_netmask dhcp_lif_t.lif_v6mask 856 if_broadcast dhcp_lif_t.lif_v6peer 857 if_ack dhcp_smach_t.dsm_ack 858 if_orig_ack dhcp_smach_t.dsm_orig_ack 859 if_offer_wait dhcp_smach_t.dsm_offer_wait 860 if_offer_timer dhcp_smach_t.dsm_offer_timer 861 if_offer_id dhcp_pif_t.pif_dlpi_id 862 if_acknak_id dhcp_lif_t.lif_acknak_id 863 if_acknak_bcast_id v4_acknak_bcast_id (global) 864 if_neg_monosec dhcp_smach_t.dsm_neg_monosec 865 if_newstart_monosec dhcp_smach_t.dsm_newstart_monosec 866 if_curstart_monosec dhcp_smach_t.dsm_curstart_monosec 867 if_disc_secs dhcp_smach_t.dsm_disc_secs 868 if_reqhost dhcp_smach_t.dsm_reqhost 869 if_recv_pkt_list dhcp_smach_t.dsm_recv_pkt_list 870 if_sent dhcp_smach_t.dsm_sent 871 if_received dhcp_smach_t.dsm_received 872 if_bad_offers dhcp_smach_t.dsm_bad_offers 873 if_send_pkt dhcp_smach_t.dsm_send_pkt 874 if_send_timeout dhcp_smach_t.dsm_send_timeout 875 if_send_dest dhcp_smach_t.dsm_send_dest 876 if_send_stop_func dhcp_smach_t.dsm_send_stop_func 877 if_packet_sent dhcp_smach_t.dsm_packet_sent 878 if_retrans_timer dhcp_smach_t.dsm_retrans_timer 879 if_script_fd dhcp_smach_t.dsm_script_fd 880 if_script_pid dhcp_smach_t.dsm_script_pid 881 if_script_helper_pid dhcp_smach_t.dsm_script_helper_pid 882 if_script_event dhcp_smach_t.dsm_script_event 883 if_script_event_id dhcp_smach_t.dsm_script_event_id 884 if_callback_msg dhcp_smach_t.dsm_callback_msg 885 if_script_callback dhcp_smach_t.dsm_script_callback 886 887 Notes: 888 889 - The dsm_name field currently just points to the lif_name on the 890 controlling LIF. This may need to be named differently in the 891 future; perhaps when Zones are supported. 892 893 - The timer mechanism will be refactored. Rather than using the 894 separate if_timer[] array to hold the timer IDs and 895 if_{t1,t2,lease} to hold the relative timer values, we will 896 gather this information into a dhcp_timer_t structure: 897 898 dt_id timer ID value 899 dt_start relative start time 900 901 New fields not accounted for above: 902 903 dhcp_pif_t.pif_next linkage in global list of PIFs 904 dhcp_pif_t.pif_prev linkage in global list of PIFs 905 dhcp_pif_t.pif_lifs pointer to list of LIFs on this PIF 906 dhcp_pif_t.pif_isv6 IPv6 flag 907 dhcp_pif_t.pif_dlpi_count number of state machines using DLPI 908 dhcp_pif_t.pif_hold_count reference count 909 dhcp_pif_t.pif_name name of physical interface 910 dhcp_lif_t.lif_next linkage in per-PIF list of LIFs 911 dhcp_lif_t.lif_prev linkage in per-PIF list of LIFs 912 dhcp_lif_t.lif_pif backpointer to parent PIF 913 dhcp_lif_t.lif_smachs pointer to list of state machines 914 dhcp_lif_t.lif_lease backpointer to lease holding LIF 915 dhcp_lif_t.lif_flags interface flags (IFF_*) 916 dhcp_lif_t.lif_hold_count reference count 917 dhcp_lif_t.lif_dad_wait waiting for DAD resolution flag 918 dhcp_lif_t.lif_removed removed from list flag 919 dhcp_lif_t.lif_plumbed plumbed by dhcpagent flag 920 dhcp_lif_t.lif_expired lease has expired flag 921 dhcp_lif_t.lif_declined reason to refuse this address (string) 922 dhcp_lif_t.lif_iaid unique and stable 32-bit identifier 923 dhcp_lif_t.lif_iaid_id timer for delayed /etc writes 924 dhcp_lif_t.lif_preferred preferred timer for v6; deprecate after 925 dhcp_lif_t.lif_name name of logical interface 926 dhcp_smach_t.dsm_lif controlling (main) LIF 927 dhcp_smach_t.dsm_leases pointer to list of leases 928 dhcp_smach_t.dsm_lif_wait number of LIFs waiting on DAD 929 dhcp_smach_t.dsm_lif_down number of LIFs that have failed 930 dhcp_smach_t.dsm_using_dlpi currently using DLPI flag 931 dhcp_smach_t.dsm_send_tcenter v4 central timer value; v6 MRT 932 dhcp_lease_t.dl_next linkage in per-state-machine list of leases 933 dhcp_lease_t.dl_prev linkage in per-state-machine list of leases 934 dhcp_lease_t.dl_smach back pointer to state machine 935 dhcp_lease_t.dl_lifs pointer to first LIF configured by lease 936 dhcp_lease_t.dl_nlifs number of configured consecutive LIFs 937 dhcp_lease_t.dl_hold_count reference counter 938 dhcp_lease_t.dl_removed removed from list flag 939 dhcp_lease_t.dl_stale lease was not updated by Renew/Rebind 940 941 942Snoop 943 944 The snoop changes are fairly straightforward. As snoop just decodes 945 the messages, and the message format is quite different between 946 DHCPv4 and DHCPv6, a new module will be created to handle DHCPv6 947 decoding, and will export a interpret_dhcpv6() function. 948 949 The one bit of commonality between the two protocols is the use of 950 ARP Hardware Type numbers, which are found in the underlying BOOTP 951 message format for DHCPv4 and in the DUID-LL and DUID-LLT 952 construction for DHCPv6. To simplify this, the existing static 953 show_htype() function in snoop_dhcp.c will be renamed to arp_htype() 954 (to better reflect its functionality), updated with more modern 955 hardware types, moved to snoop_arp.c (where it belongs), and made a 956 public symbol within snoop. 957 958 While I'm there, I'll update snoop_arp.c so that when it prints an 959 ARP message in verbose mode, it uses arp_htype() to translate the 960 ar_hrd value. 961 962 The snoop updates also involve the addition of a new "dhcp6" keyword 963 for filtering. As a part of this, CR 6487534 will be fixed. 964 965 966IPv6 Source Address Selection 967 968 One of the customer requests for DHCPv6 is to be able to predict the 969 address selection behavior in the presence of both stateful and 970 stateless addresses on the same network. 971 972 Solaris implements RFC 3484 address selection behavior. In this 973 scheme, the first seven rules implement some basic preferences for 974 addresses, with Rule 8 being a deterministic tie breaker. 975 976 Rule 8 relies on a special function, CommonPrefixLen, defined in the 977 RFC, that compares leading bits of the address without regard to 978 configured prefix length. As Rule 1 eliminates equal addresses, 979 this always picks a single address. 980 981 This rule, though, allows for additional checks: 982 983 Rule 8 may be superseded if the implementation has other means of 984 choosing among source addresses. For example, if the implementation 985 somehow knows which source address will result in the "best" 986 communications performance. 987 988 We will thus split Rule 8 into three separate rules: 989 990 - First, compare on configured prefix. The interface with the 991 longest configured prefix length that also matches the candidate 992 address will be preferred. 993 994 - Next, check the type of address. Prefer statically configured 995 addresses above all others. Next, those from DHCPv6. Next, 996 stateless autoconfigured addresses. Finally, temporary addresses. 997 (Note that Rule 7 will take care of temporary address preferences, 998 so that this rule doesn't actually need to look at them.) 999 1000 - Finally, run the check-all-bits (CommonPrefixLen) tie breaker. 1001 1002 The result of this is that if there's a local address in the same 1003 configured prefix, then we'll prefer that over other addresses. If 1004 there are multiple to choose from, then will pick static first, then 1005 DHCPv6, then dynamic. Finally, if there are still multiples, we'll 1006 use the "closest" address, bitwise. 1007 1008 Also, this basic implementation scheme also addresses CR 6485164, so 1009 a fix for that will be included with this project. 1010 1011 1012Minor Improvements 1013 1014 Various small problems with the system encountered during 1015 development will be fixed along with this project. Some of these 1016 are: 1017 1018 - List of ARPHRD_* types is a bit short; add some new ones. 1019 1020 - List of IPPORT_* values is similarly sparse; add others in use by 1021 snoop. 1022 1023 - dhcpmsg.h lacks PRINTFLIKE for dhcpmsg(); add it. 1024 1025 - CR 6482163 causes excessive lint errors with libxnet; will fix. 1026 1027 - libdhcpagent uses gettimeofday() for I/O timing, and this can 1028 drift on systems with NTP. It should use a stable time source 1029 (gethrtime()) instead, and should return better error values. 1030 1031 - Controlling debug mode in the daemon shouldn't require changing 1032 the command line arguments or jumping through special hoops. I've 1033 added undocumented ".DEBUG_LEVEL=[0-3]" and ".VERBOSE=[01]" 1034 features to /etc/default/dhcpagent. 1035 1036 - The various attributes of the IPC commands (requires privileges, 1037 creates a new session, valid with BOOTP, immediate reply) should 1038 be gathered together into one look-up table rather than scattered 1039 as hard-coded tests. 1040 1041 - Remove the event unregistration from the command dispatch loop and 1042 get rid of the ipc_action_pending() botch. We'll get a 1043 zero-length read any time the client goes away, and that will be 1044 enough to trigger termination. This fix removes async_pending() 1045 and async_timeout() as well, and fixes CR 6487958 as a 1046 side-effect. 1047 1048 - Throughout the dhcpagent code, there are private implementations 1049 of doubly-linked and singly-linked lists for each data type. 1050 These will all be removed and replaced with insque(3C) and 1051 remque(3C). 1052 1053 1054Testing 1055 1056 The implementation was tested using the TAHI test suite for DHCPv6 1057 (www.tahi.org). There are some peculiar aspects to this test suite, 1058 and these issues directed some of the design. In particular: 1059 1060 - If Renew/Rebind doesn't mention one of our leases, then we need to 1061 allow the message to be retransmitted. Real servers are unlikely 1062 to do this. 1063 1064 - We must look for a status code within IAADDR and within IA_NA, and 1065 handle the paradoxical case of "NoAddrAvail." That doesn't make 1066 sense, as a server with no addresses wouldn't use those options. 1067 That option makes more sense at the top level of the message. 1068 1069 - If we get "UseMulticast" when we were already using multicast, 1070 then ignore the error code. Sending another request would cause a 1071 loop. 1072 1073 - TAHI uses "NoBinding" at the top level of the message. This 1074 status code only makes sense within an IA, as it refers to the 1075 GUID:IAID binding, which doesn't exist outside an IA. We must 1076 ignore such errors -- treat them as success. 1077 1078 1079Interactions With Other Projects 1080 1081 Clearview UV (vanity naming) will cause link names, and thus IP 1082 interface names, to become changeable over time. This will break 1083 the IAID stability mechanism if UV is used for arbitrary renaming, 1084 rather than as just a DR enhancement. 1085 1086 When this portion of Clearview integrates, this part of the DHCPv6 1087 design may need to be revisited. (The solution will likely be 1088 handled at some higher layer, such as within Network Automagic.) 1089 1090 Clearview is also contributing a new libdlpi that will work for 1091 dhcpagent, and is thus removing the private dlpi_io.[ch] functions 1092 from this daemon. When that Clearview project integrates, the 1093 DHCPv6 project will need to adjust to the new interfaces, and remove 1094 or relocate the dlpi_to_arp() function. 1095 1096 1097Futures 1098 1099 Zones currently cannot address any IP interfaces by way of DHCP. 1100 This project will not fix that problem, but the DUID/IAID could be 1101 used to help fix it in the future. 1102 1103 In particular, the DUID allows the client to obtain separate sets of 1104 addresses and configuration parameters on a single interface, just 1105 like an IPv4 Client ID, but it includes a clean mechanism for vendor 1106 extensions. If we associate the DUID with the zone identifier or 1107 name through an extension, then we have a really simple way of 1108 allocating per-zone addresses. 1109 1110 Moreover, RFC 4361 describes a handy way of using DHCPv6 DUID/IAID 1111 values with IPv4 DHCP, which would quickly solve the problem of 1112 using DHCP for IPv4 address assignment in non-global zones as well. 1113 1114 (One potential risk with this plan is that there may be server 1115 implementations that either do not implement the RFC correctly or 1116 otherwise mishandle the DUID. This has apparently bitten some early 1117 adopters.) 1118 1119 Implementing the FQDN option for DHCPv6 would, given the current 1120 libdhcputil design, require a new 'type' of entry for the inittab6 1121 file. This is because the design does not allow for any simple 1122 means to ``compose'' a sequence of basic types together. Thus, 1123 every type of option must either be a basic type, or an array of 1124 multiple instances of the same basic type. 1125 1126 If we implement FQDN in the future, it may be useful to explore some 1127 means of allowing a given option instance to be a sequence of basic 1128 types. 1129 1130 This project does not make the DNS resolver or any other subsystem 1131 use the data gathered by DHCPv6. It just makes the data available 1132 through dhcpinfo(1). Future projects should modify those services 1133 to use configuration data learned via DHCPv6. (One of the reasons 1134 this is not being done now is that Network Automagic [NWAM] will 1135 likely be changing this area substantially in the very near future, 1136 and thus the effort would be largely wasted.) 1137 1138 1139Appendix A - Choice of Venue 1140 1141 There are three logical places to implement DHCPv6: 1142 1143 - in dhcpagent 1144 - in in.ndpd 1145 - in a new daemon (say, 'dhcp6agent') 1146 1147 We need to access parameters via dhcpinfo, and should provide the 1148 same set of status and control features via ifconfig as are present 1149 for IPv4. (For the latter, if we fail to do that, it will likely 1150 confuse users. The expense for doing it is comparatively small, and 1151 it will be useful for testing, even though it should not be needed 1152 in normal operation.) 1153 1154 If we implement somewhere other than dhcpagent, then we need to give 1155 that new daemon (in.ndpd or dhcp6agent) the same basic IPC features 1156 as dhcpagent already has. This means either extracting those bits 1157 (async.c and ipc_action.c) into a shared library or just copying 1158 them. Obviously, the former would be preferred, but as those bits 1159 depend on the rest of the dhcpagent infrastructure for timers and 1160 state handling, this means that the new process would have to look a 1161 lot like dhcpagent. 1162 1163 Implementing DHCPv6 as part of in.ndpd is attractive, as it 1164 eliminates the confusion that the router discovery process for 1165 determining interface netmasks can cause, along with the need to do 1166 any signaling at all to bring DHCPv6 up. However, the need to make 1167 in.ndpd more like dhcpagent is unattractive. 1168 1169 Having a new dhcp6agent daemon seems to have little to recommend it, 1170 other than leaving the existing dhcpagent code untouched. If we do 1171 that, then we end up with two implementations that do many similar 1172 things, and must be maintained in parallel. 1173 1174 Thus, although it leads to some complexity in reworking the data 1175 structures to fit both protocols, on balance the simplest solution 1176 is to extend dhcpagent. 1177 1178 1179Appendix B - Cross-Reference 1180 1181 in.ndpd 1182 1183 - Start dhcpagent and issue "dhcp start" command via libdhcpagent 1184 - Parse StatefulAddrConf interface option from ndpd.conf 1185 - Watch for M and O bits to trigger DHCPv6 1186 - Handle "no routers found" case and start DHCPv6 1187 - Track prefixes and set prefix length on IFF_DHCPRUNNING aliases 1188 - Send new Router Solicitation when prefix unknown 1189 - Change privileges so that dhcpagent can be launched successfully 1190 1191 libdhcputil 1192 1193 - Parse new /etc/dhcp/inittab6 file 1194 - Handle new UNUMBER24, SNUMBER64, IPV6, DUID and DOMAIN types 1195 - Add DHCPv6 option iterators (dhcpv6_find_option and 1196 dhcpv6_pkt_option) 1197 - Add dlpi_to_arp function (temporary) 1198 1199 libdhcpagent 1200 1201 - Add stable DUID and IAID creation and storage support 1202 functions and add new dhcp_stable.h include file 1203 - Support new DECLINING and RELEASING states introduced by DHCPv6. 1204 - Update implementation so that it doesn't rely on gettimeofday() 1205 for I/O timeouts 1206 - Extend the hostconf functions to support DHCPv6, using a new 1207 ".dh6" file 1208 1209 snoop 1210 1211 - Add support for DHCPv6 packet decoding (all types) 1212 - Add "dhcp6" filter keyword 1213 - Fix known bugs in DHCP filtering 1214 1215 ifconfig 1216 1217 - Remove inet-only restriction on "dhcp" keyword 1218 1219 netstat 1220 1221 - Remove strange "-I list" feature. 1222 - Add support for DHCPv6 and iterating over IPv6 interfaces. 1223 1224 ip 1225 1226 - Add extensions to IPv6 source address selection to prefer DHCPv6 1227 addresses when all else is equal 1228 - Fix known bugs in source address selection (remaining from TX 1229 integration) 1230 1231 other 1232 1233 - Add ifindex and source/destination address into PKT_LIST. 1234 - Add more ARPHDR_* and IPPORT_* values. 1235