13431ScarlsonjCDDL HEADER START 23431Scarlsonj 33431ScarlsonjThe contents of this file are subject to the terms of the 43431ScarlsonjCommon Development and Distribution License (the "License"). 53431ScarlsonjYou may not use this file except in compliance with the License. 63431Scarlsonj 73431ScarlsonjYou can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 83431Scarlsonjor http://www.opensolaris.org/os/licensing. 93431ScarlsonjSee the License for the specific language governing permissions 103431Scarlsonjand limitations under the License. 113431Scarlsonj 123431ScarlsonjWhen distributing Covered Code, include this CDDL HEADER in each 133431Scarlsonjfile and include the License file at usr/src/OPENSOLARIS.LICENSE. 143431ScarlsonjIf applicable, add the following below this CDDL HEADER, with the 153431Scarlsonjfields enclosed by brackets "[]" replaced with your own identifying 163431Scarlsonjinformation: Portions Copyright [yyyy] [name of copyright owner] 173431Scarlsonj 183431ScarlsonjCDDL HEADER END 193431Scarlsonj 203431ScarlsonjCopyright 2007 Sun Microsystems, Inc. All rights reserved. 213431ScarlsonjUse is subject to license terms. 223431Scarlsonj 233431Scarlsonjident "%Z%%M% %I% %E% SMI" 243431Scarlsonj 25*5381Smeem 26*5381Smeem** PLEASE NOTE: 27*5381Smeem** 28*5381Smeem** This document discusses aspects of the DHCPv4 client design that have 29*5381Smeem** since changed (e.g., DLPI is no longer used). However, since those 30*5381Smeem** aspects affected the DHCPv6 design, the discussion has been left for 31*5381Smeem** historical record. 32*5381Smeem 33*5381Smeem 343431ScarlsonjDHCPv6 Client Low-Level Design 353431Scarlsonj 363431ScarlsonjIntroduction 373431Scarlsonj 383431Scarlsonj This project adds DHCPv6 client-side (not server) support to 393431Scarlsonj Solaris. Future projects may add server-side support as well as 403431Scarlsonj enhance the basic capabilities added here. These future projects 413431Scarlsonj are not discussed in detail in this document. 423431Scarlsonj 433431Scarlsonj This document assumes that the reader is familiar with the following 443431Scarlsonj other documents: 453431Scarlsonj 463431Scarlsonj - RFC 3315: the primary description of DHCPv6 473431Scarlsonj - RFCs 2131 and 2132: IPv4 DHCP 483431Scarlsonj - RFCs 2461 and 2462: IPv6 NDP and stateless autoconfiguration 493431Scarlsonj - RFC 3484: IPv6 default address selection 503431Scarlsonj - ifconfig(1M): Solaris IP interface configuration 513431Scarlsonj - in.ndpd(1M): Solaris IPv6 Neighbor and Router Discovery daemon 523431Scarlsonj - dhcpagent(1M): Solaris DHCP client 533431Scarlsonj - dhcpinfo(1): Solaris DHCP parameter utility 543431Scarlsonj - ndpd.conf(4): in.ndpd configuration file 553431Scarlsonj - netstat(1M): Solaris network status utility 563431Scarlsonj - snoop(1M): Solaris network packet capture and inspection 573431Scarlsonj - "DHCPv6 Client High-Level Design" 583431Scarlsonj 593431Scarlsonj Several terms from those documents (such as the DHCPv6 IA_NA and 603431Scarlsonj IAADDR options) are used without further explanation in this 613431Scarlsonj document; see the reference documents above for details. 623431Scarlsonj 633431Scarlsonj The overall plan is to enhance the existing Solaris dhcpagent so 643431Scarlsonj that it is able to process DHCPv6. It would also have been possible 653431Scarlsonj to create a new, separate daemon process for this, or to integrate 663431Scarlsonj the feature into in.ndpd. These alternatives, and the reason for 673431Scarlsonj the chosen design, are discussed in Appendix A. 683431Scarlsonj 693431Scarlsonj This document discusses the internal design issues involved in the 703431Scarlsonj protocol implementation, and with the associated components (such as 713431Scarlsonj in.ndpd, snoop, and the kernel's source address selection 723431Scarlsonj algorithm). It does not discuss the details of the protocol itself, 733431Scarlsonj which are more than adequately described in the RFC, nor the 743431Scarlsonj individual lines of code, which will be in the code review. 753431Scarlsonj 763431Scarlsonj As a cross-reference, Appendix B has a summary of the components 773431Scarlsonj involved and the changes to each. 783431Scarlsonj 793431Scarlsonj 803431ScarlsonjBackground 813431Scarlsonj 823431Scarlsonj In order to discuss the design changes for DHCPv6, it's necessary 833431Scarlsonj first to talk about the current IPv4-only design, and the 843431Scarlsonj assumptions built into that design. 853431Scarlsonj 863431Scarlsonj The main data structure used in dhcpagent is the 'struct ifslist'. 873431Scarlsonj Each instance of this structure represents a Solaris logical IP 883431Scarlsonj interface under DHCP's control. It also represents the shared state 893431Scarlsonj with the DHCP server that granted the address, the address itself, 903431Scarlsonj and copies of the negotiated options. 913431Scarlsonj 923431Scarlsonj There is one list in dhcpagent containing all of the IP interfaces 933431Scarlsonj that are under DHCP control. IP interfaces not under DHCP control 943431Scarlsonj (for example, those that are statically addressed) are not included 953431Scarlsonj in this list, even when plumbed on the system. These ifslist 963431Scarlsonj entries are chained like this: 973431Scarlsonj 983431Scarlsonj ifsheadp -> ifslist -> ifslist -> ifslist -> NULL 993431Scarlsonj net0 net0:1 net1 1003431Scarlsonj 1013431Scarlsonj Each ifslist entry contains the address, mask, lease information, 1023431Scarlsonj interface name, hardware information, packets, protocol state, and 1033431Scarlsonj timers. The name of the logical IP interface under DHCP's control 1043431Scarlsonj is also the name used in the administrative interfaces (dhcpinfo, 1053431Scarlsonj ifconfig) and when logging events. 1063431Scarlsonj 1073431Scarlsonj Each entry holds open a DLPI stream and two sockets. The DLPI 1083431Scarlsonj stream is nulled-out with a filter when not in use, but still 1093431Scarlsonj consumes system resources. (Most significantly, it causes data 1103431Scarlsonj copies in the driver layer that end up sapping performance.) 1113431Scarlsonj 1123431Scarlsonj The entry storage is managed by a insert/hold/release/remove model 1133431Scarlsonj and reference counts. In this model, insert_ifs() allocates a new 1143431Scarlsonj ifslist entry and inserts it into the global list, with the global 1153431Scarlsonj list holding a reference. remove_ifs() removes it from the global 1163431Scarlsonj list and drops that reference. hold_ifs() and release_ifs() are 1173431Scarlsonj used by data structures that refer to ifslist entries, such as timer 1183431Scarlsonj entries, to make sure that the ifslist entry isn't freed until the 1193431Scarlsonj timer has been dispatched or deleted. 1203431Scarlsonj 1213431Scarlsonj The design is single-threaded, so code that walks the global list 1223431Scarlsonj needn't bother taking holds on the ifslist structure. Only 1233431Scarlsonj references that may be used at a different time (i.e., pointers 1243431Scarlsonj stored in other data structures) need to be recorded. 1253431Scarlsonj 1263431Scarlsonj Packets are handled using PKT (struct dhcp; <netinet/dhcp.h>), 1273431Scarlsonj PKT_LIST (struct dhcp_list; <dhcp_impl.h>), and dhcp_pkt_t (struct 1283431Scarlsonj dhcp_pkt; "packet.h"). PKT is just the RFC 2131 DHCP packet 1293431Scarlsonj structure, and has no additional information, such as packet length. 1303431Scarlsonj PKT_LIST contains a PKT pointer, length, decoded option arrays, and 1313431Scarlsonj linkage for putting the packet in a list. Finally, dhcp_pkt_t has a 1323431Scarlsonj PKT pointer and length values suitable for modifying the packet. 1333431Scarlsonj 1343431Scarlsonj Essentially, PKT_LIST is a wrapper for received packets, and 1353431Scarlsonj dhcp_pkt_t is a wrapper for packets to be sent. 1363431Scarlsonj 1373431Scarlsonj The basic PKT structure is used in dhcpagent, inetboot, in.dhcpd, 1383431Scarlsonj libdhcpagent, libwanboot, libdhcputil, and others. PKT_LIST is used 1393431Scarlsonj in a similar set of places, including the kernel NFS modules. 1403431Scarlsonj dhcp_pkt_t is (as the header file implies) limited to dhcpagent. 1413431Scarlsonj 1423431Scarlsonj In addition to these structures, dhcpagent maintains a set of 1433431Scarlsonj internal supporting abstractions. Two key ones involved in this 1443431Scarlsonj project are the "async operation" and the "IPC action." An async 1453431Scarlsonj operation encapsulates the actions needed for a given operation, so 1463431Scarlsonj that if cancellation is needed, there's a single point where the 1473431Scarlsonj associated resources can be freed. An IPC action represents the 1483431Scarlsonj user state related to the private interface used by ifconfig. 1493431Scarlsonj 1503431Scarlsonj 1513431ScarlsonjDHCPv6 Inherent Differences 1523431Scarlsonj 1533431Scarlsonj DHCPv6 naturally has some commonality with IPv4 DHCP, but also has 1543431Scarlsonj some significant differences. 1553431Scarlsonj 1563431Scarlsonj Unlike IPv4 DHCP, DHCPv6 relies on link-local IP addresses to do its 1573431Scarlsonj work. This means that, on Solaris, the client doesn't need DLPI to 1583431Scarlsonj perform any of the I/O; regular IP sockets will do the job. It also 1593431Scarlsonj means that, unlike IPv4 DHCP, DHCPv6 does not need to obtain a lease 1603431Scarlsonj for the address used in its messages to the server. The system 1613431Scarlsonj provides the address automatically. 1623431Scarlsonj 1633431Scarlsonj IPv4 DHCP expects some messages from the server to be broadcast. 1643431Scarlsonj DHCPv6 has no such mechanism; all messages from the server to the 1653431Scarlsonj client are unicast. In the case where the client and server aren't 1663431Scarlsonj on the same subnet, a relay agent is used to get the unicast replies 1673431Scarlsonj back to the client's link-local address. 1683431Scarlsonj 1693431Scarlsonj With IPv4 DHCP, a single address plus configuration options is 1703431Scarlsonj leased with a given client ID and a single state machine instance, 1713431Scarlsonj and the implementation binds that to a single IP logical interface 1723431Scarlsonj specified by the user. The lease has a "Lease Time," a required 1733431Scarlsonj option, as well as two timers, called T1 (renew) and T2 (rebind), 1743431Scarlsonj which are controlled by regular options. 1753431Scarlsonj 1763431Scarlsonj DHCPv6 uses a single client/server session to control the 1773431Scarlsonj acquisition of configuration options and "identity associations" 1783431Scarlsonj (IAs). The identity associations, in turn, contain lists of 1793431Scarlsonj addresses for the client to use and the T1/T2 timer values. Each 1803431Scarlsonj individual address has its own preferred and valid lifetime, with 1813431Scarlsonj the address being marked "deprecated" at the end of the preferred 1823431Scarlsonj interval, and removed at the end of the valid interval. 1833431Scarlsonj 1843431Scarlsonj IPv4 DHCP leaves many of the retransmit decisions up to the client, 1853431Scarlsonj and some things (such as RELEASE and DECLINE) are sent just once. 1863431Scarlsonj Others (such as the REQUEST message used for renew and rebind) are 1873431Scarlsonj dealt with by heuristics. DHCPv6 treats each message to the server 1883431Scarlsonj as a separate transaction, and resends each message using a common 1893431Scarlsonj retransmission mechanism. DHCPv6 also has separate messages for 1903431Scarlsonj Renew, Rebind, and Confirm rather than reusing the Request 1913431Scarlsonj mechanism. 1923431Scarlsonj 1933431Scarlsonj The set of options (which are used to convey configuration 1943431Scarlsonj information) for each protocol are distinct. Notably, two of the 1953431Scarlsonj mistakes from IPv4 DHCP have been fixed: DHCPv6 doesn't carry a 1963431Scarlsonj client name, and doesn't attempt to impersonate a routing protocol 1973431Scarlsonj by setting a "default route." 1983431Scarlsonj 1993431Scarlsonj Another welcome change is the lack of a netmask/prefix length with 2003431Scarlsonj DHCPv6. Instead, the client uses the Router Advertisement prefixes 2013431Scarlsonj to set the correct interface netmask. This reduces the number of 2023431Scarlsonj databases that need to be kept in sync. (The equivalent mechanism 2033431Scarlsonj in IPv4 would have been the use of ICMP Address Mask Request / 2043431Scarlsonj Reply, but the BOOTP designers chose to embed it in the address 2053431Scarlsonj assignment protocol itself.) 2063431Scarlsonj 2073431Scarlsonj Otherwise, DHCPv6 is similar to IPv4 DHCP. The same overall 2083431Scarlsonj renew/rebind and lease expiry strategy is used, although the state 2093431Scarlsonj machine events must now take into account multiple IAs and the fact 2103431Scarlsonj that each can cause RENEWING or REBINDING state independently. 2113431Scarlsonj 2123431Scarlsonj 2133431ScarlsonjDHCPv6 And Solaris 2143431Scarlsonj 2153431Scarlsonj The protocol distinctions above have several important implications. 2163431Scarlsonj For the logical interfaces: 2173431Scarlsonj 2183431Scarlsonj - Because Solaris uses IP logical interfaces to configure 2193431Scarlsonj addresses, we must have multiple IP logical interfaces per IA 2203431Scarlsonj with IPv6. 2213431Scarlsonj 2223431Scarlsonj - Because we need to support multiple addresses (and thus multiple 2233431Scarlsonj IP logical interfaces) per IA and multiple IAs per client/server 2243431Scarlsonj session, the IP logical interface name isn't a unique name for 2253431Scarlsonj the lease. 2263431Scarlsonj 2273431Scarlsonj As a result, IP logical interfaces will come and go with DHCPv6, 2283431Scarlsonj just as happens with the existing stateless address 2293431Scarlsonj autoconfiguration support in in.ndpd. The logical interface names 2303431Scarlsonj (visible in ifconfig) have no administrative significance. 2313431Scarlsonj 2323431Scarlsonj Fortunately, DHCPv6 does end up with one fixed name that can be used 2333431Scarlsonj to identify a session. Because DHCPv6 uses link local addresses for 2343431Scarlsonj communication with the server, the name of the IP logical interface 2353431Scarlsonj that has this link local address (normally the same as the IP 2363431Scarlsonj physical interface) can be used as an identifier for dhcpinfo and 2373431Scarlsonj logging purposes. 2383431Scarlsonj 2393431Scarlsonj 2403431ScarlsonjDhcpagent Redesign Overview 2413431Scarlsonj 2423431Scarlsonj The redesign starts by refactoring the IP interface representation. 2433431Scarlsonj Because we need to have multiple IP logical interfaces (LIFs) for a 2443431Scarlsonj single identity association (IA), we should not store all of the 2453431Scarlsonj DHCP state information along with the LIF information. 2463431Scarlsonj 2473431Scarlsonj For DHCPv6, we will need to keep LIFs on a single IP physical 2483431Scarlsonj interface (PIF) together, so this is probably also a good time to 2493431Scarlsonj reconsider the way dhcpagent represents physical interfaces. The 2503431Scarlsonj current design simply replicates the state (notably the DLPI stream, 2513431Scarlsonj but also the hardware address and other bits) among all of the 2523431Scarlsonj ifslist entries on the same physical interface. 2533431Scarlsonj 2543431Scarlsonj The new design creates two lists of dhcp_pif_t entries, one list for 2553431Scarlsonj IPv4 and the other for IPv6. Each dhcp_pif_t represents a PIF, with 2563431Scarlsonj a list of dhcp_lif_t entries attached, each of which represents a 2573431Scarlsonj LIF used by dhcpagent. This structure mirrors the kernel's ill_t 2583431Scarlsonj and ipif_t interface representations. 2593431Scarlsonj 2603431Scarlsonj Next, the lease-tracking needs to be refactored. DHCPv6 is the 2613431Scarlsonj functional superset in this case, as it has two lifetimes per 2623431Scarlsonj address (LIF) and IA groupings with shared T1/T2 timers. To 2633431Scarlsonj represent these groupings, we will use a new dhcp_lease_t structure. 2643431Scarlsonj IPv4 DHCP will have one such structure per state machine, while 2653431Scarlsonj DHCPv6 will have a list. (Note: the initial implementation will 2663431Scarlsonj have only one lease per DHCPv6 state machine, because each state 2673431Scarlsonj machine uses a single link-local address, a single DUID+IAID pair, 2683431Scarlsonj and supports only Non-temporary Addresses [IA_NA option]. Future 2693431Scarlsonj enhancements may use multiple leases per DHCPv6 state machine or 2703431Scarlsonj support other IA types.) 2713431Scarlsonj 2723431Scarlsonj For all of these new structures, we will use the same insert/hold/ 2733431Scarlsonj release/remove model as with the original ifslist. 2743431Scarlsonj 2753431Scarlsonj Finally, the remaining items (and the bulk of the original ifslist 2763431Scarlsonj members) are kept on a per-state-machine basis. As this is no 2773431Scarlsonj longer just an "interface," a new dhcp_smach_t structure will hold 2783431Scarlsonj these, and the ifslist structure is gone. 2793431Scarlsonj 2803431Scarlsonj 2813431ScarlsonjLease Representation 2823431Scarlsonj 2833431Scarlsonj For DHCPv6, we need to track multiple LIFs per lease (IA), but we 2843431Scarlsonj also need multiple LIFs per PIF. Rather than having two sets of 2853431Scarlsonj list linkage for each LIF, we can observe that a LIF is on exactly 2863431Scarlsonj one PIF and is a member of at most one lease, and then simplify: the 2873431Scarlsonj lease structure will use a base pointer for the first LIF in the 2883431Scarlsonj lease, and a count for the number of consecutive LIFs in the PIF's 2893431Scarlsonj list of LIFs that belong to the lease. 2903431Scarlsonj 2913431Scarlsonj When removing a LIF from the system, we need to decrement the count 2923431Scarlsonj of LIFs in the lease, and advance the base pointer if the LIF being 2933431Scarlsonj removed is the first one. Inserting a LIF means just moving it into 2943431Scarlsonj this list and bumping the counter. 2953431Scarlsonj 2963431Scarlsonj When removing a lease from a state machine, we need to dispose of 2973431Scarlsonj the LIFs referenced. If the LIF being disposed is the main LIF for 2983431Scarlsonj a state machine, then all that we can do is canonize the LIF 2993431Scarlsonj (returning it to a default state); this represents the normal IPv4 3003431Scarlsonj DHCP operation on lease expiry. Otherwise, the lease is the owner 3013431Scarlsonj of that LIF (it was created because of a DHCPv6 IA), and disposal 3023431Scarlsonj means unplumbing the LIF from the actual system and removing the LIF 3033431Scarlsonj entry from the PIF. 3043431Scarlsonj 3053431Scarlsonj 3063431ScarlsonjMain Structure Linkage 3073431Scarlsonj 3083431Scarlsonj For IPv4 DHCP, the new linkage is straightforward. Using the same 3093431Scarlsonj system configuration example as in the initial design discussion: 3103431Scarlsonj 3113431Scarlsonj +- lease +- lease +- lease 3123431Scarlsonj | ^ | ^ | ^ 3133431Scarlsonj | | | | | | 3143431Scarlsonj \ smach \ smach \ smach 3153431Scarlsonj \ ^| \ ^| \ ^| 3163431Scarlsonj v|v v|v v|v 3173431Scarlsonj lif ----> lif -> NULL lif -> NULL 3183431Scarlsonj net0 net0:1 net1 3193431Scarlsonj ^ ^ 3203431Scarlsonj | | 3213431Scarlsonj v4root -> pif --------------------> pif -> NULL 3223431Scarlsonj net0 net1 3233431Scarlsonj 3243431Scarlsonj This diagram shows three separate state machines running (with 3253431Scarlsonj backpointers omitted for clarity). Each state machine has a single 3263431Scarlsonj "main" LIF with which it's associated (and named). Each also has a 3273431Scarlsonj single lease structure that points back to the same LIF (count of 3283431Scarlsonj 1), because IPv4 DHCP controls a single address allocation per state 3293431Scarlsonj machine. 3303431Scarlsonj 3313431Scarlsonj DHCPv6 is a bit more complex. This shows DHCPv6 running on two 3323431Scarlsonj interfaces (more or fewer interfaces are of course possible) and 3333431Scarlsonj with multiple leases on the first interface, and each lease with 3343431Scarlsonj multiple addresses (one with two addresses, the second with one). 3353431Scarlsonj 3363431Scarlsonj lease ----------------> lease -> NULL lease -> NULL 3373431Scarlsonj ^ \(2) |(1) ^ \ (1) 3383431Scarlsonj | \ | | \ 3393431Scarlsonj smach \ | smach \ 3403431Scarlsonj ^ | \ | ^ | \ 3413431Scarlsonj | v v v | v v 3423431Scarlsonj lif --> lif --> lif --> lif --> NULL lif --> lif -> NULL 3433431Scarlsonj net0 net0:1 net0:4 net0:2 net1 net1:5 3443431Scarlsonj ^ ^ 3453431Scarlsonj | | 3463431Scarlsonj v6root -> pif ----------------------------------> pif -> NULL 3473431Scarlsonj net0 net1 3483431Scarlsonj 3493431Scarlsonj Note that there's intentionally no ordering based on name in the 3503431Scarlsonj list of LIFs. Instead, the contiguous LIF structures in that list 3513431Scarlsonj represent the addresses in each lease. The logical interfaces 3523431Scarlsonj themselves are allocated and numbered by the system kernel, so they 3533431Scarlsonj may not be sequential, and there may be gaps in the list if other 3543431Scarlsonj entities (such as in.ndpd) are also configuring interfaces. 3553431Scarlsonj 3563431Scarlsonj Note also that with IPv4 DHCP, the lease points to the LIF that's 3573431Scarlsonj also the main LIF for the state machine, because that's the IP 3583431Scarlsonj interface that dhcpagent controls. With DHCPv6, the lease (one per 3593431Scarlsonj IA structure) points to a separate set of LIFs that are created just 3603431Scarlsonj for the leased addresses (one per IA address in an IAADDR option). 3613431Scarlsonj The state machine alone points to the main LIF. 3623431Scarlsonj 3633431Scarlsonj 3643431ScarlsonjPacket Structure Extensions 3653431Scarlsonj 3663431Scarlsonj Obviously, we need some DHCPv6 packet data structures and 3673431Scarlsonj definitions. A new <netinet/dhcp6.h> file will be introduced with 3683431Scarlsonj the necessary #defines and structures. The key structure there will 3693431Scarlsonj be: 3703431Scarlsonj 3713431Scarlsonj struct dhcpv6_message { 3723431Scarlsonj uint8_t d6m_msg_type; 3733431Scarlsonj uint8_t d6m_transid_ho; 3743431Scarlsonj uint16_t d6m_transid_lo; 3753431Scarlsonj }; 3763431Scarlsonj typedef struct dhcpv6_message dhcpv6_message_t; 3773431Scarlsonj 3783431Scarlsonj This defines the usual (non-relay) DHCPv6 packet header, and is 3793431Scarlsonj roughly equivalent to PKT for IPv4. 3803431Scarlsonj 3813431Scarlsonj Extending dhcp_pkt_t for DHCPv6 is straightforward, as it's used 3823431Scarlsonj only within dhcpagent. This structure will be amended to use a 3833431Scarlsonj union for v4/v6 and include a boolean to flag which version is in 3843431Scarlsonj use. 3853431Scarlsonj 3863431Scarlsonj For the PKT_LIST structure, things are more complex. This defines 3873431Scarlsonj both a queuing mechanism for received packets (typically OFFERs) and 3883431Scarlsonj a set of packet decoding structures. The decoding structures are 3893431Scarlsonj highly specific to IPv4 DHCP -- they have no means to handle nested 3903431Scarlsonj or repeated options (as used heavily in DHCPv6) and make use of the 3913431Scarlsonj DHCP_OPT structure which is specific to IPv4 DHCP -- and are 3923431Scarlsonj somewhat expensive in storage, due to the use of arrays indexed by 3933431Scarlsonj option code number. 3943431Scarlsonj 3953431Scarlsonj Worse, this structure is used throughout the system, so changes to 3963431Scarlsonj it need to be made carefully. (For example, the existing 'pkt' 3973431Scarlsonj member can't just be turned into a union.) 3983431Scarlsonj 3993431Scarlsonj For an initial prototype, since discarded, I created a new 4003431Scarlsonj dhcp_plist_t structure to represent packet lists as used inside 4013431Scarlsonj dhcpagent and made dhcp_pkt_t valid for use on input and output. 4023431Scarlsonj The result is unsatisfying, though, as it results in code that 4033431Scarlsonj manipulates far too many data structures in common cases; it's a sea 4043431Scarlsonj of pointers to pointers. 4053431Scarlsonj 4063431Scarlsonj The better answer is to use PKT_LIST for both IPv4 and IPv6, adding 4073431Scarlsonj the few new bits of metadata required to the end (receiving ifIndex, 4083431Scarlsonj packet source/destination addresses), and staying within the overall 4093431Scarlsonj existing design. 4103431Scarlsonj 4113431Scarlsonj For option parsing, dhcpv6_find_option() and dhcpv6_pkt_option() 4123431Scarlsonj functions will be added to libdhcputil. The former function will 4133431Scarlsonj walk a DHCPv6 option list, and provide safe (bounds-checked) access 4143431Scarlsonj to the options inside. The function can be called recursively, so 4153431Scarlsonj that option nesting can be handled fairly simply by nested loops, 4163431Scarlsonj and can be called repeatedly to return each instance of a given 4173431Scarlsonj option code number. The latter function is just a convenience 4183431Scarlsonj wrapper on dhcpv6_find_option() that starts with a PKT_LIST pointer 4193431Scarlsonj and iterates over the top-level options with a given code number. 4203431Scarlsonj 4213431Scarlsonj There are two special considerations for the use of these library 4223431Scarlsonj interfaces: there's no "pad" option for DHCPv6 or alignment 4233431Scarlsonj requirements on option headers or contents, and nested options 4243431Scarlsonj always follow a structure that has type-dependent length. This 4253431Scarlsonj means that code that handles options must all be written to deal 4263431Scarlsonj with unaligned data, and suboption code must index the pointer past 4273431Scarlsonj the type-dependent part. 4283431Scarlsonj 4293431Scarlsonj 4303431ScarlsonjPacket Construction 4313431Scarlsonj 4323431Scarlsonj Unlike DHCPv4, DHCPv6 places the transaction timer value in an 4333431Scarlsonj option. The existing code sets the current time value in 4343431Scarlsonj send_pkt_internal(), which allows it to be updated in a 4353431Scarlsonj straightforward way when doing retransmits. 4363431Scarlsonj 4373431Scarlsonj To make this work in a simple manner for DHCPv6, I added a 4383431Scarlsonj remove_pkt_opt() function. The update logic just does a remove and 4393431Scarlsonj re-adds the option. We could also just assume the presence of the 4403431Scarlsonj option, find it, and modify in place, but the remove feature seems 4413431Scarlsonj more general. 4423431Scarlsonj 4433431Scarlsonj DHCPv6 uses nesting options. To make this work, two new utility 4443431Scarlsonj functions are needed. First, an add_pkt_subopt() function will take 4453431Scarlsonj a pointer to an existing option and add an embedded option within 4463431Scarlsonj it. The packet length and existing option length are updated. If 4473431Scarlsonj that existing option isn't a top-level option, though, this means 4483431Scarlsonj that the caller must update the lengths of all of the enclosing 4493431Scarlsonj options up to the top level. To do this, update_v6opt_len() will be 4503431Scarlsonj added. This is used in the special case of adding a Status Code 4513431Scarlsonj option to an IAADDR option within an IA_NA top-level option. 4523431Scarlsonj 4533431Scarlsonj 4543431ScarlsonjSockets and I/O Handling 4553431Scarlsonj 4563431Scarlsonj DHCPv6 doesn't need or use either a DLPI or a broadcast IP socket. 4573431Scarlsonj Instead, a single unicast-bound IP socket on a link-local address 4583431Scarlsonj would be the most that is needed. This is roughly equivalent to 4593431Scarlsonj if_sock_ip_fd in the existing design, but that existing socket is 4603431Scarlsonj bound only after DHCP reaches BOUND state -- that is, when it 4613431Scarlsonj switches away from DLPI. We need something different. 4623431Scarlsonj 4633431Scarlsonj This, along with the excess of open file descriptors in an otherwise 4643431Scarlsonj idle daemon and the potentially serious performance problems in 4653431Scarlsonj leaving DLPI open at all times, argues for a larger redesign of the 4663431Scarlsonj I/O logic in dhcpagent. 4673431Scarlsonj 4683431Scarlsonj The first thing that we can do is eliminate the need for the 4693431Scarlsonj per-ifslist if_sock_fd. This is used primarily for issuing ioctls 4703431Scarlsonj to configure interfaces -- a task that would work as well with any 4713431Scarlsonj open socket -- and is also registered to receive any ACK/NAK packets 4723431Scarlsonj that may arrive via broadcast. Both of these can be eliminated by 4733431Scarlsonj creating a pair of global sockets (IPv4 and IPv6), bound and 4743431Scarlsonj configured for ACK/NAK reception. The only functional difference is 4753431Scarlsonj that the list of running state machines must be scanned on reception 4763431Scarlsonj to find the correct transaction ID, but the existing design 4773431Scarlsonj effectively already goes to this effort because the kernel 4783431Scarlsonj replicates received datagrams among all matching sockets, and each 4793431Scarlsonj ifslist entry has a socket open. 4803431Scarlsonj 4813431Scarlsonj (The existing code for if_sock_fd makes oblique reference to unknown 4823431Scarlsonj problems in the system that may prevent binding from working in some 4833431Scarlsonj cases. The reference dates back some seven years to the original 4843431Scarlsonj DHCP implementation. I've observed no such problems in extensive 4853431Scarlsonj testing and if any do show up, they will be dealt with by fixing the 4863431Scarlsonj underlying bugs.) 4873431Scarlsonj 4883431Scarlsonj This leads to an important simplification: it's no longer necessary 4893431Scarlsonj to register, unregister, and re-register for packet reception while 4903431Scarlsonj changing state -- register_acknak() and unregister_acknak() are 4913431Scarlsonj gone. Instead, we always receive, and we dispatch the packets as 4923431Scarlsonj they arrive. As a result, when receiving a DHCPv4 ACK or DHCPv6 4933431Scarlsonj Reply when in BOUND state, we know it's a duplicate, and we can 4943431Scarlsonj discard. 4953431Scarlsonj 4963431Scarlsonj The next part is in minimizing DLPI usage. A DLPI stream is needed 4973431Scarlsonj at most for each IPv4 PIF, and it's not needed when all of the 4983431Scarlsonj DHCP instances on that PIF are bound. In fact, the current 4993431Scarlsonj implementation deals with this in configure_bound() by setting a 5003431Scarlsonj "blackhole" packet filter. The stream is left open. 5013431Scarlsonj 5023431Scarlsonj To simplify this, we will open at most one DLPI stream on a PIF, and 5033431Scarlsonj use reference counts from the state machines to determine when the 5043431Scarlsonj stream must be open and when it can be closed. This mechanism will 5053431Scarlsonj be centralized in a set_smach_state() function that changes the 5063431Scarlsonj state and opens/closes the DLPI stream when needed. 5073431Scarlsonj 5083431Scarlsonj This leads to another simplification. The I/O logic in the existing 5093431Scarlsonj dhcpagent makes use of the protocol state to select between DLPI and 5103431Scarlsonj sockets. Now that we keep track of this in a simpler manner, we no 5113431Scarlsonj longer need to switch out on state in when sending a packet; just 5123431Scarlsonj test the dsm_using_dlpi flag instead. 5133431Scarlsonj 5143431Scarlsonj Still another simplification is in the handling of DHCPv4 INFORM. 5153431Scarlsonj The current code has separate logic in it for getting the interface 5163431Scarlsonj state and address information. This is no longer necessary, as the 5173431Scarlsonj LIF mechanism keeps track of the interface state. And since we have 5183431Scarlsonj separate lease structures, and INFORM doesn't acquire a lease, we no 5193431Scarlsonj longer have to be careful about canonizing the interface on 5203431Scarlsonj shutdown. 5213431Scarlsonj 5223431Scarlsonj Although the default is to send all client messages to a well-known 5233431Scarlsonj multicast address for servers and relays, DHCPv6 also has a 5243431Scarlsonj mechanism that allows the client to send unicast messages to the 5253431Scarlsonj server. The operation of this mechanism is slightly complex. 5263431Scarlsonj First, the server sends the client a unicast address via an option. 5273431Scarlsonj We may use this address as the destination (rather than the 5283431Scarlsonj well-known multicast address for local DHCPv6 servers and relays) 5293431Scarlsonj only if we have a viable local source address. This means using 5303431Scarlsonj SIOCGDSTINFO each time we try to send unicast. Next, the server may 5313431Scarlsonj send back a special status code: UseMulticast. If this is received, 5323431Scarlsonj and if we were actually using unicast in our messages to the server, 5333431Scarlsonj then we need to forget the unicast address, switch back to 5343431Scarlsonj multicast, and resend our last message. 5353431Scarlsonj 5363431Scarlsonj Note that it's important to avoid the temptation to resend the last 5373431Scarlsonj message every time UseMulticast is seen, and do it only once on 5383431Scarlsonj switching back to multicast: otherwise, a potential feedback loop is 5393431Scarlsonj created. 5403431Scarlsonj 5413431Scarlsonj Because IP_PKTINFO (PSARC 2006/466) has integrated, we could go a 5423431Scarlsonj step further by removing the need for any per-LIF sockets and just 5433431Scarlsonj use the global sockets for all but DLPI. However, in order to 5443431Scarlsonj facilitate a Solaris 10 backport, this will be done separately as CR 5453431Scarlsonj 6509317. 5463431Scarlsonj 5473431Scarlsonj In the case of DHCPv6, we already have IPV6_PKTINFO, so we will pave 5483431Scarlsonj the way for IPv4 by beginning to using this now, and thus have just 5493431Scarlsonj a single socket (bound to "::") for all of DHCPv6. Doing this 5503431Scarlsonj requires switching from the old BSD4.2 -lsocket -lnsl to the 5513431Scarlsonj standards-compliant -lxnet in order to use ancillary data. 5523431Scarlsonj 5533431Scarlsonj It may also be possible to remove the need for DLPI for IPv4, and 5543431Scarlsonj incidentally simplify the code a fair amount, by adding a kernel 5553431Scarlsonj option to allow transmission and reception of UDP packets over 5563431Scarlsonj interfaces that are plumbed but not marked IFF_UP. This is left for 5573431Scarlsonj future work. 5583431Scarlsonj 5593431Scarlsonj 5603431ScarlsonjThe State Machine 5613431Scarlsonj 5623431Scarlsonj Several parts of the existing state machine need additions to handle 5633431Scarlsonj DHCPv6, which is a superset of DHCPv4. 5643431Scarlsonj 5653431Scarlsonj First, there are the RENEWING and REBINDING states. For IPv4 DHCP, 5663431Scarlsonj these states map one-to-one with a single address and single lease 5673431Scarlsonj that's undergoing renewal. It's a simple progression (on timeout) 5683431Scarlsonj from BOUND, to RENEWING, to REBINDING and finally back to SELECTING 5693431Scarlsonj to start over. Each retransmit is done by simply rescheduling the 5703431Scarlsonj T1 or T2 timer. 5713431Scarlsonj 5723431Scarlsonj For DHCPv6, things are somewhat more complex. At any one time, 5733431Scarlsonj there may be multiple IAs (leases) that are effectively in renewing 5743431Scarlsonj or rebinding state, based on the T1/T2 timers for each IA, and many 5753431Scarlsonj addresses that have expired. 5763431Scarlsonj 5773431Scarlsonj However, because all of the leases are related to a single server, 5783431Scarlsonj and that server either responds to our requests or doesn't, we can 5793431Scarlsonj simplify the states to be nearly identical to IPv4 DHCP. 5803431Scarlsonj 5813431Scarlsonj The revised definition for use with DHCPv6 is: 5823431Scarlsonj 5833431Scarlsonj - Transition from BOUND to RENEWING state when the first T1 timer 5843431Scarlsonj (of any lease on the state machine) expires. At this point, as 5853431Scarlsonj an optimization, we should begin attempting to renew any IAs 5863431Scarlsonj that are within REN_TIMEOUT (10 seconds) of reaching T1 as well. 5873431Scarlsonj We may as well avoid sending an excess of packets. 5883431Scarlsonj 5893431Scarlsonj - When a T1 lease timer expires and we're in RENEWING or REBINDING 5903431Scarlsonj state, just ignore it, because the transaction is already in 5913431Scarlsonj progress. 5923431Scarlsonj 5933431Scarlsonj - At each retransmit timeout, we should check to see if there are 5943431Scarlsonj more IAs that need to join in because they've passed point T1 as 5953431Scarlsonj well, and, if so, add them. This check isn't necessary at this 5963431Scarlsonj time, because only a single IA_NA is possible with the initial 5973431Scarlsonj design. 5983431Scarlsonj 5993431Scarlsonj - When we reach T2 on any IA and we're in BOUND or RENEWING state, 6003431Scarlsonj enter REBINDING state. At this point, we have a choice. For 6013431Scarlsonj those other IAs that are past T1 but not yet at T2, we could 6023431Scarlsonj ignore them (sending only those that have passed point T2), 6033431Scarlsonj continue to send separate Renew messages for them, or just 6043431Scarlsonj include them in the Rebind message. This isn't an issue that 6053431Scarlsonj must be dealt with for this project, but the plan is to include 6063431Scarlsonj them in the Rebind message. 6073431Scarlsonj 6083431Scarlsonj - When a T2 lease timer expires and we're in REBINDING state, just 6093431Scarlsonj ignore it, as with the corresponding T1 timer. 6103431Scarlsonj 6113431Scarlsonj - As addresses reach the end of their preferred lifetimes, set the 6123431Scarlsonj IFF_DEPRECATED flag. As they reach the end of the valid 6133431Scarlsonj lifetime, remove them from the system. When an IA (lease) 6143431Scarlsonj becomes empty, just remove it. When there are no more leases 6153431Scarlsonj left, return to SELECTING state to start over. 6163431Scarlsonj 6173431Scarlsonj Note that the RFC treats the IAs as separate entities when 6183431Scarlsonj discussing the renew/rebind T1/T2 timers, but treats them as a unit 6193431Scarlsonj when doing the initial negotiation. This is, to say the least, 6203431Scarlsonj confusing, especially so given that there's no reason to expect that 6213431Scarlsonj after having failed to elicit any responses at all from the server 6223431Scarlsonj on one IA, the server will suddenly start responding when we attempt 6233431Scarlsonj to renew some other IA. We rationalize this behavior by using a 6243431Scarlsonj single renew/rebind state for the entire state machine (and thus 6253431Scarlsonj client/server pair). 6263431Scarlsonj 6273431Scarlsonj There's a subtle timing difference here between DHCPv4 and DHCPv6. 6283431Scarlsonj For DHCPv4, the client just sends packets more and more frequently 6293431Scarlsonj (shorter timeouts) as the next state gets nearer. DHCPv6 treats 6303431Scarlsonj each as a transaction, using the same retransmit logic as for other 6313431Scarlsonj messages. The DHCPv6 method is a cleaner design, so we will change 6323431Scarlsonj the DHCPv4 implementation to do the same, and compute the new timer 6333431Scarlsonj values as part of stop_extending(). 6343431Scarlsonj 6353431Scarlsonj Note that it would be possible to start the SELECTING state earlier 6363431Scarlsonj than waiting for the last lease to expire, and thus avoid a loss of 6373431Scarlsonj connectivity. However, it this point, there are other servers on 6383431Scarlsonj the network that have seen us attempting to Rebind for quite some 6393431Scarlsonj time, and they have not responded. The likelihood that there's a 6403431Scarlsonj server that will ignore Rebind but then suddenly spring into action 6413431Scarlsonj on a Solicit message seems low enough that the optimization won't be 6423431Scarlsonj done now. (Starting SELECTING state earlier may be done in the 6433431Scarlsonj future, if it's found to be useful.) 6443431Scarlsonj 6453431Scarlsonj 6463431ScarlsonjPersistent State 6473431Scarlsonj 6483431Scarlsonj IPv4 DHCP has only minimal need for persistent state, beyond the 6493431Scarlsonj configuration parameters. The state is stored when "ifconfig dhcp 6503431Scarlsonj drop" is run or the daemon receives SIGTERM, which is typically done 6513431Scarlsonj only well after the system is booted and running. 6523431Scarlsonj 6533431Scarlsonj The daemon stores this state in /etc/dhcp, because it needs to be 6543431Scarlsonj available when only the root file system has been mounted. 6553431Scarlsonj 6563431Scarlsonj Moreover, dhcpagent starts very early in the boot process. It runs 6573431Scarlsonj as part of svc:/network/physical:default, which runs well before 6583431Scarlsonj root is mounted read/write: 6593431Scarlsonj 6603431Scarlsonj svc:/system/filesystem/root:default -> 6613431Scarlsonj svc:/system/metainit:default -> 6623431Scarlsonj svc:/system/identity:node -> 6633431Scarlsonj svc:/network/physical:default 6643431Scarlsonj svc:/network/iscsi_initiator:default -> 6653431Scarlsonj svc:/network/physical:default 6663431Scarlsonj 6673431Scarlsonj and, of course, well before either /var or /usr is mounted. This 6683431Scarlsonj means that any persistent state must be kept in the root file 6693431Scarlsonj system, and that if we write before shutdown, we have to cope 6703431Scarlsonj gracefully with the root file system returning EROFS on write 6713431Scarlsonj attempts. 6723431Scarlsonj 6733431Scarlsonj For DHCPv6, we need to try to keep our stable DUID and IAID values 6743431Scarlsonj stable across reboots to fulfill the demands of RFC 3315. 6753431Scarlsonj 6763431Scarlsonj The DUID is either configured or automatically generated. When 6773431Scarlsonj configured, it comes from the /etc/default/dhcpagent file, and thus 6783431Scarlsonj does not need to be saved by the daemon. If automatically 6793431Scarlsonj generated, there's exactly one of these created, and it will 6803431Scarlsonj eventually be needed before /usr is mounted, if /usr is mounted over 6813431Scarlsonj IPv6. This means a new file in the root file system, 6823431Scarlsonj /etc/dhcp/duid, will be used to hold the automatically generated 6833431Scarlsonj DUID. 6843431Scarlsonj 6853431Scarlsonj The determination of whether to use a configured DUID or one saved 6863431Scarlsonj in a file is made in get_smach_cid(). This function will 6873431Scarlsonj encapsulate all of the DUID parsing and generation machinery for the 6883431Scarlsonj rest of dhcpagent. 6893431Scarlsonj 6903431Scarlsonj If root is not writable at the point when dhcpagent starts, and our 6913431Scarlsonj attempt fails with EROFS, we will set a timer for 60 second 6923431Scarlsonj intervals to retry the operation periodically. In the unlikely case 6933431Scarlsonj that it just never succeeds or that we're rebooted before root 6943431Scarlsonj becomes writable, then the impact will be that the daemon will wake 6953431Scarlsonj up once a minute and, ultimately, we'll choose a different DUID on 6963431Scarlsonj next start-up, and we'll thus lose our leases across a reboot. 6973431Scarlsonj 6983431Scarlsonj The IAID similarly must be kept stable if at all possible, but 6993431Scarlsonj cannot be configured by the user. To do make these values stable, 7003431Scarlsonj we will use two strategies. First the IAID value for a given 7013431Scarlsonj interface (if not known) will just default to the IP ifIndex value, 7023431Scarlsonj provided that there's no known saved IAID using that value. Second, 7033431Scarlsonj we will save off the IAID we choose in a single /etc/dhcp/iaid file, 7043431Scarlsonj containing an array of entries indexed by logical interface name. 7053431Scarlsonj Keeping it in a single file allows us to scan for used and unused 7063431Scarlsonj IAID values when necessary. 7073431Scarlsonj 7083431Scarlsonj This mechanism depends on the interface name, and thus will need to 7093431Scarlsonj be revisited when Clearview vanity naming and NWAM are available. 7103431Scarlsonj 7113431Scarlsonj Currently, the boot system (GRUB, OBP, the miniroot) does not 7123431Scarlsonj support installing over IPv6. This could change in the future, so 7133431Scarlsonj one of the goals of the above stability plan is to support that 7143431Scarlsonj event. 7153431Scarlsonj 7163431Scarlsonj When running in the miniroot on an x86 system, /etc/dhcp (and the 7173431Scarlsonj rest of the root) is mounted on a read-only ramdisk. In this case, 7183431Scarlsonj writing to /etc/dhcp will just never work. A possible solution 7193431Scarlsonj would be to add a new privileged command in ifconfig that forces 7203431Scarlsonj dhcpagent to write to an alternate location. The initial install 7213431Scarlsonj process could then do "ifconfig <x> dhcp write /a" to get the needed 7223431Scarlsonj state written out to the newly-constructed system root. 7233431Scarlsonj 7243431Scarlsonj This part (the new write option) won't be implemented as part of 7253431Scarlsonj this project, because it's not needed yet. 7263431Scarlsonj 7273431Scarlsonj 7283431ScarlsonjRouter Advertisements 7293431Scarlsonj 7303431Scarlsonj IPv6 Router Advertisements perform two functions related to DHCPv6: 7313431Scarlsonj 7323431Scarlsonj - they specify whether and how to run DHCPv6 on a given interface. 7333431Scarlsonj - they provide a list of the valid prefixes on an interface. 7343431Scarlsonj 7353431Scarlsonj For the first function, in.ndpd needs to use the same DHCP control 7363431Scarlsonj interfaces that ifconfig uses, so that it can launch dhcpagent and 7373431Scarlsonj trigger DHCPv6 when necessary. Note that it never needs to shut 7383431Scarlsonj down DHCPv6, as router advertisements can't do that. 7393431Scarlsonj 7403431Scarlsonj However, launching dhcpagent presents new problems. As a part of 7413431Scarlsonj the "Quagga SMF Modifications" project (PSARC 2006/552), in.ndpd in 7423431Scarlsonj Nevada is now privilege-aware and runs with limited privileges, 7433431Scarlsonj courtesy of SMF. Dhcpagent, on the other hand, must run with all 7443431Scarlsonj privileges. 7453431Scarlsonj 7463431Scarlsonj A simple work-around for this issue is to rip out the "privileges=" 7473431Scarlsonj clause from the method_credential for in.ndpd. I've taken this 7483431Scarlsonj direction initially, but the right longer-term answer seems to be 7493431Scarlsonj converting dhcpagent into an SMF service. This is quite a bit more 7503431Scarlsonj complex, as it means turning the /sbin/dhcpagent command line 7513431Scarlsonj interface into a utility that manipulates the service and passes the 7523431Scarlsonj command line options via IPC extensions. 7533431Scarlsonj 7543431Scarlsonj Such a design also begs the question of whether dhcpagent itself 7553431Scarlsonj ought to run with reduced privileges. It could, but it still needs 7563431Scarlsonj the ability to grant "all" (traditional UNIX root) privileges to the 7573431Scarlsonj eventhook script, if present. There seem to be few ways to do this, 7583431Scarlsonj though it's a good area for research. 7593431Scarlsonj 7603431Scarlsonj The second function, prefix handling, is also subtle. Unlike IPv4 7613431Scarlsonj DHCP, DHCPv6 does not give the netmask or prefix length along with 7623431Scarlsonj the leased address. The client is on its own to determine the right 7633431Scarlsonj netmask to use. This is where the advertised prefixes come in: 7643431Scarlsonj these must be used to finish the interface configuration. 7653431Scarlsonj 7663431Scarlsonj We will have the DHCPv6 client configure each interface with an 7673431Scarlsonj all-ones (/128) netmask by default. In.ndpd will be modified so 7683431Scarlsonj that when it detects a new IFF_DHCPRUNNING IP logical interface, it 7693431Scarlsonj checks for a known matching prefix, and sets the netmask as 7703431Scarlsonj necessary. If no matching prefix is known, it will send a new 7713431Scarlsonj Router Solicitation message to try to find one. 7723431Scarlsonj 7733431Scarlsonj When in.ndpd learns of a new prefix from a Router Advertisement, it 7743431Scarlsonj will scan all of the IFF_DHCPRUNNING IP logical interfaces on the 7753431Scarlsonj same physical interface and set the netmasks when necessary. 7763431Scarlsonj Dhcpagent, for its part, will ignore the netmask on IPv6 interfaces 7773431Scarlsonj when checking for changes that would require it to "abandon" the 7783431Scarlsonj interface. 7793431Scarlsonj 7803431Scarlsonj Given the way that DHCPv6 and in.ndpd control both the horizontal 7813431Scarlsonj and the vertical in plumbing and removing logical interfaces, and 7823431Scarlsonj users do not, it might be worthwhile to consider roping off any 7833431Scarlsonj direct user changes to IPv6 logical interfaces under control of 7843431Scarlsonj in.ndpd or dhcpagent, and instead force users through a higher-level 7853431Scarlsonj interface. This won't be done as part of this project, however. 7863431Scarlsonj 7873431Scarlsonj 7883431ScarlsonjARP Hardware Types 7893431Scarlsonj 7903431Scarlsonj There are multiple places within the DHCPv6 client where the mapping 7913431Scarlsonj of DLPI MAC type to ARP Hardware Type is required: 7923431Scarlsonj 7933431Scarlsonj - When we are constructing an automatic, stable DUID for our own 7943431Scarlsonj identity, we prefer to use a DUID-LLT if possible. This is done 7953431Scarlsonj by finding a link-layer interface, opening it, reading the MAC 7963431Scarlsonj address and type, and translating in the make_stable_duid() 7973431Scarlsonj function in libdhcpagent. 7983431Scarlsonj 7993431Scarlsonj - When we translate a user-configured DUID from 8003431Scarlsonj /etc/default/dhcpagent into a binary representation, we may have 8013431Scarlsonj to deal with a physical interface name. In this case, we must 8023431Scarlsonj open that interface and read the MAC address and type. 8033431Scarlsonj 8043431Scarlsonj - As part of the PIF data structure initialization, we need to read 8053431Scarlsonj out the MAC type so that it can be used in the BOOTP/DHCPv4 8063431Scarlsonj 'htype' field. 8073431Scarlsonj 8083431Scarlsonj Ideally, these would all be provided by a single libdlpi 8093431Scarlsonj implementation. However, that project is on-going at this time and 8103431Scarlsonj has not yet integrated. For the time being, a dlpi_to_arp() 8113431Scarlsonj translation function (taking dl_mac_type and returning an ARP 8123431Scarlsonj Hardware Type number) will be placed in libdhcputil. 8133431Scarlsonj 8143431Scarlsonj This temporary function should be removed and this section of the 8153431Scarlsonj code updated when the new libdlpi from Clearview integrates. 8163431Scarlsonj 8173431Scarlsonj 8183431ScarlsonjField Mappings 8193431Scarlsonj 8203431Scarlsonj Old (all in ifslist) New 8213431Scarlsonj next dhcp_smach_t.dsm_next 8223431Scarlsonj prev dhcp_smach_t.dsm_prev 8233431Scarlsonj if_hold_count dhcp_smach_t.dsm_hold_count 8243431Scarlsonj if_ia dhcp_smach_t.dsm_ia 8253431Scarlsonj if_async dhcp_smach_t.dsm_async 8263431Scarlsonj if_state dhcp_smach_t.dsm_state 8273431Scarlsonj if_dflags dhcp_smach_t.dsm_dflags 8283431Scarlsonj if_name dhcp_smach_t.dsm_name (see text) 8293431Scarlsonj if_index dhcp_pif_t.pif_index 8303431Scarlsonj if_max dhcp_lif_t.lif_max and dhcp_pif_t.pif_max 8313431Scarlsonj if_min (was unused; removed) 8323431Scarlsonj if_opt (was unused; removed) 8333431Scarlsonj if_hwaddr dhcp_pif_t.pif_hwaddr 8343431Scarlsonj if_hwlen dhcp_pif_t.pif_hwlen 8353431Scarlsonj if_hwtype dhcp_pif_t.pif_hwtype 8363431Scarlsonj if_cid dhcp_smach_t.dsm_cid 8373431Scarlsonj if_cidlen dhcp_smach_t.dsm_cidlen 8383431Scarlsonj if_prl dhcp_smach_t.dsm_prl 8393431Scarlsonj if_prllen dhcp_smach_t.dsm_prllen 8403431Scarlsonj if_daddr dhcp_pif_t.pif_daddr 8413431Scarlsonj if_dlen dhcp_pif_t.pif_dlen 8423431Scarlsonj if_saplen dhcp_pif_t.pif_saplen 8433431Scarlsonj if_sap_before dhcp_pif_t.pif_sap_before 8443431Scarlsonj if_dlpi_fd dhcp_pif_t.pif_dlpi_fd 8453431Scarlsonj if_sock_fd v4_sock_fd and v6_sock_fd (globals) 8463431Scarlsonj if_sock_ip_fd dhcp_lif_t.lif_sock_ip_fd 8473431Scarlsonj if_timer (see text) 8483431Scarlsonj if_t1 dhcp_lease_t.dl_t1 8493431Scarlsonj if_t2 dhcp_lease_t.dl_t2 8503431Scarlsonj if_lease dhcp_lif_t.lif_expire 8513431Scarlsonj if_nrouters dhcp_smach_t.dsm_nrouters 8523431Scarlsonj if_routers dhcp_smach_t.dsm_routers 8533431Scarlsonj if_server dhcp_smach_t.dsm_server 8543431Scarlsonj if_addr dhcp_lif_t.lif_v6addr 8553431Scarlsonj if_netmask dhcp_lif_t.lif_v6mask 8563431Scarlsonj if_broadcast dhcp_lif_t.lif_v6peer 8573431Scarlsonj if_ack dhcp_smach_t.dsm_ack 8583431Scarlsonj if_orig_ack dhcp_smach_t.dsm_orig_ack 8593431Scarlsonj if_offer_wait dhcp_smach_t.dsm_offer_wait 8603431Scarlsonj if_offer_timer dhcp_smach_t.dsm_offer_timer 8613431Scarlsonj if_offer_id dhcp_pif_t.pif_dlpi_id 8623431Scarlsonj if_acknak_id dhcp_lif_t.lif_acknak_id 8633431Scarlsonj if_acknak_bcast_id v4_acknak_bcast_id (global) 8643431Scarlsonj if_neg_monosec dhcp_smach_t.dsm_neg_monosec 8653431Scarlsonj if_newstart_monosec dhcp_smach_t.dsm_newstart_monosec 8663431Scarlsonj if_curstart_monosec dhcp_smach_t.dsm_curstart_monosec 8673431Scarlsonj if_disc_secs dhcp_smach_t.dsm_disc_secs 8683431Scarlsonj if_reqhost dhcp_smach_t.dsm_reqhost 8693431Scarlsonj if_recv_pkt_list dhcp_smach_t.dsm_recv_pkt_list 8703431Scarlsonj if_sent dhcp_smach_t.dsm_sent 8713431Scarlsonj if_received dhcp_smach_t.dsm_received 8723431Scarlsonj if_bad_offers dhcp_smach_t.dsm_bad_offers 8733431Scarlsonj if_send_pkt dhcp_smach_t.dsm_send_pkt 8743431Scarlsonj if_send_timeout dhcp_smach_t.dsm_send_timeout 8753431Scarlsonj if_send_dest dhcp_smach_t.dsm_send_dest 8763431Scarlsonj if_send_stop_func dhcp_smach_t.dsm_send_stop_func 8773431Scarlsonj if_packet_sent dhcp_smach_t.dsm_packet_sent 8783431Scarlsonj if_retrans_timer dhcp_smach_t.dsm_retrans_timer 8793431Scarlsonj if_script_fd dhcp_smach_t.dsm_script_fd 8803431Scarlsonj if_script_pid dhcp_smach_t.dsm_script_pid 8813431Scarlsonj if_script_helper_pid dhcp_smach_t.dsm_script_helper_pid 8823431Scarlsonj if_script_event dhcp_smach_t.dsm_script_event 8833431Scarlsonj if_script_event_id dhcp_smach_t.dsm_script_event_id 8843431Scarlsonj if_callback_msg dhcp_smach_t.dsm_callback_msg 8853431Scarlsonj if_script_callback dhcp_smach_t.dsm_script_callback 8863431Scarlsonj 8873431Scarlsonj Notes: 8883431Scarlsonj 8893431Scarlsonj - The dsm_name field currently just points to the lif_name on the 8903431Scarlsonj controlling LIF. This may need to be named differently in the 8913431Scarlsonj future; perhaps when Zones are supported. 8923431Scarlsonj 8933431Scarlsonj - The timer mechanism will be refactored. Rather than using the 8943431Scarlsonj separate if_timer[] array to hold the timer IDs and 8953431Scarlsonj if_{t1,t2,lease} to hold the relative timer values, we will 8963431Scarlsonj gather this information into a dhcp_timer_t structure: 8973431Scarlsonj 8983431Scarlsonj dt_id timer ID value 8993431Scarlsonj dt_start relative start time 9003431Scarlsonj 9013431Scarlsonj New fields not accounted for above: 9023431Scarlsonj 9033431Scarlsonj dhcp_pif_t.pif_next linkage in global list of PIFs 9043431Scarlsonj dhcp_pif_t.pif_prev linkage in global list of PIFs 9053431Scarlsonj dhcp_pif_t.pif_lifs pointer to list of LIFs on this PIF 9063431Scarlsonj dhcp_pif_t.pif_isv6 IPv6 flag 9073431Scarlsonj dhcp_pif_t.pif_dlpi_count number of state machines using DLPI 9083431Scarlsonj dhcp_pif_t.pif_hold_count reference count 9093431Scarlsonj dhcp_pif_t.pif_name name of physical interface 9103431Scarlsonj dhcp_lif_t.lif_next linkage in per-PIF list of LIFs 9113431Scarlsonj dhcp_lif_t.lif_prev linkage in per-PIF list of LIFs 9123431Scarlsonj dhcp_lif_t.lif_pif backpointer to parent PIF 9133431Scarlsonj dhcp_lif_t.lif_smachs pointer to list of state machines 9143431Scarlsonj dhcp_lif_t.lif_lease backpointer to lease holding LIF 9153431Scarlsonj dhcp_lif_t.lif_flags interface flags (IFF_*) 9163431Scarlsonj dhcp_lif_t.lif_hold_count reference count 9173431Scarlsonj dhcp_lif_t.lif_dad_wait waiting for DAD resolution flag 9183431Scarlsonj dhcp_lif_t.lif_removed removed from list flag 9193431Scarlsonj dhcp_lif_t.lif_plumbed plumbed by dhcpagent flag 9203431Scarlsonj dhcp_lif_t.lif_expired lease has expired flag 9213431Scarlsonj dhcp_lif_t.lif_declined reason to refuse this address (string) 9223431Scarlsonj dhcp_lif_t.lif_iaid unique and stable 32-bit identifier 9233431Scarlsonj dhcp_lif_t.lif_iaid_id timer for delayed /etc writes 9243431Scarlsonj dhcp_lif_t.lif_preferred preferred timer for v6; deprecate after 9253431Scarlsonj dhcp_lif_t.lif_name name of logical interface 9263431Scarlsonj dhcp_smach_t.dsm_lif controlling (main) LIF 9273431Scarlsonj dhcp_smach_t.dsm_leases pointer to list of leases 9283431Scarlsonj dhcp_smach_t.dsm_lif_wait number of LIFs waiting on DAD 9293431Scarlsonj dhcp_smach_t.dsm_lif_down number of LIFs that have failed 9303431Scarlsonj dhcp_smach_t.dsm_using_dlpi currently using DLPI flag 9313431Scarlsonj dhcp_smach_t.dsm_send_tcenter v4 central timer value; v6 MRT 9323431Scarlsonj dhcp_lease_t.dl_next linkage in per-state-machine list of leases 9333431Scarlsonj dhcp_lease_t.dl_prev linkage in per-state-machine list of leases 9343431Scarlsonj dhcp_lease_t.dl_smach back pointer to state machine 9353431Scarlsonj dhcp_lease_t.dl_lifs pointer to first LIF configured by lease 9363431Scarlsonj dhcp_lease_t.dl_nlifs number of configured consecutive LIFs 9373431Scarlsonj dhcp_lease_t.dl_hold_count reference counter 9383431Scarlsonj dhcp_lease_t.dl_removed removed from list flag 9393431Scarlsonj dhcp_lease_t.dl_stale lease was not updated by Renew/Rebind 9403431Scarlsonj 9413431Scarlsonj 9423431ScarlsonjSnoop 9433431Scarlsonj 9443431Scarlsonj The snoop changes are fairly straightforward. As snoop just decodes 9453431Scarlsonj the messages, and the message format is quite different between 9463431Scarlsonj DHCPv4 and DHCPv6, a new module will be created to handle DHCPv6 9473431Scarlsonj decoding, and will export a interpret_dhcpv6() function. 9483431Scarlsonj 9493431Scarlsonj The one bit of commonality between the two protocols is the use of 9503431Scarlsonj ARP Hardware Type numbers, which are found in the underlying BOOTP 9513431Scarlsonj message format for DHCPv4 and in the DUID-LL and DUID-LLT 9523431Scarlsonj construction for DHCPv6. To simplify this, the existing static 9533431Scarlsonj show_htype() function in snoop_dhcp.c will be renamed to arp_htype() 9543431Scarlsonj (to better reflect its functionality), updated with more modern 9553431Scarlsonj hardware types, moved to snoop_arp.c (where it belongs), and made a 9563431Scarlsonj public symbol within snoop. 9573431Scarlsonj 9583431Scarlsonj While I'm there, I'll update snoop_arp.c so that when it prints an 9593431Scarlsonj ARP message in verbose mode, it uses arp_htype() to translate the 9603431Scarlsonj ar_hrd value. 9613431Scarlsonj 9623431Scarlsonj The snoop updates also involve the addition of a new "dhcp6" keyword 9633431Scarlsonj for filtering. As a part of this, CR 6487534 will be fixed. 9643431Scarlsonj 9653431Scarlsonj 9663431ScarlsonjIPv6 Source Address Selection 9673431Scarlsonj 9683431Scarlsonj One of the customer requests for DHCPv6 is to be able to predict the 9693431Scarlsonj address selection behavior in the presence of both stateful and 9703431Scarlsonj stateless addresses on the same network. 9713431Scarlsonj 9723431Scarlsonj Solaris implements RFC 3484 address selection behavior. In this 9733431Scarlsonj scheme, the first seven rules implement some basic preferences for 9743431Scarlsonj addresses, with Rule 8 being a deterministic tie breaker. 9753431Scarlsonj 9763431Scarlsonj Rule 8 relies on a special function, CommonPrefixLen, defined in the 9773431Scarlsonj RFC, that compares leading bits of the address without regard to 9783431Scarlsonj configured prefix length. As Rule 1 eliminates equal addresses, 9793431Scarlsonj this always picks a single address. 9803431Scarlsonj 9813431Scarlsonj This rule, though, allows for additional checks: 9823431Scarlsonj 9833431Scarlsonj Rule 8 may be superseded if the implementation has other means of 9843431Scarlsonj choosing among source addresses. For example, if the implementation 9853431Scarlsonj somehow knows which source address will result in the "best" 9863431Scarlsonj communications performance. 9873431Scarlsonj 9883431Scarlsonj We will thus split Rule 8 into three separate rules: 9893431Scarlsonj 9903431Scarlsonj - First, compare on configured prefix. The interface with the 9913431Scarlsonj longest configured prefix length that also matches the candidate 9923431Scarlsonj address will be preferred. 9933431Scarlsonj 9943431Scarlsonj - Next, check the type of address. Prefer statically configured 9953431Scarlsonj addresses above all others. Next, those from DHCPv6. Next, 9963431Scarlsonj stateless autoconfigured addresses. Finally, temporary addresses. 9973431Scarlsonj (Note that Rule 7 will take care of temporary address preferences, 9983431Scarlsonj so that this rule doesn't actually need to look at them.) 9993431Scarlsonj 10003431Scarlsonj - Finally, run the check-all-bits (CommonPrefixLen) tie breaker. 10013431Scarlsonj 10023431Scarlsonj The result of this is that if there's a local address in the same 10033431Scarlsonj configured prefix, then we'll prefer that over other addresses. If 10043431Scarlsonj there are multiple to choose from, then will pick static first, then 10053431Scarlsonj DHCPv6, then dynamic. Finally, if there are still multiples, we'll 10063431Scarlsonj use the "closest" address, bitwise. 10073431Scarlsonj 10083431Scarlsonj Also, this basic implementation scheme also addresses CR 6485164, so 10093431Scarlsonj a fix for that will be included with this project. 10103431Scarlsonj 10113431Scarlsonj 10123431ScarlsonjMinor Improvements 10133431Scarlsonj 10143431Scarlsonj Various small problems with the system encountered during 10153431Scarlsonj development will be fixed along with this project. Some of these 10163431Scarlsonj are: 10173431Scarlsonj 10183431Scarlsonj - List of ARPHRD_* types is a bit short; add some new ones. 10193431Scarlsonj 10203431Scarlsonj - List of IPPORT_* values is similarly sparse; add others in use by 10213431Scarlsonj snoop. 10223431Scarlsonj 10233431Scarlsonj - dhcpmsg.h lacks PRINTFLIKE for dhcpmsg(); add it. 10243431Scarlsonj 10253431Scarlsonj - CR 6482163 causes excessive lint errors with libxnet; will fix. 10263431Scarlsonj 10273431Scarlsonj - libdhcpagent uses gettimeofday() for I/O timing, and this can 10283431Scarlsonj drift on systems with NTP. It should use a stable time source 10293431Scarlsonj (gethrtime()) instead, and should return better error values. 10303431Scarlsonj 10313431Scarlsonj - Controlling debug mode in the daemon shouldn't require changing 10323431Scarlsonj the command line arguments or jumping through special hoops. I've 10333431Scarlsonj added undocumented ".DEBUG_LEVEL=[0-3]" and ".VERBOSE=[01]" 10343431Scarlsonj features to /etc/default/dhcpagent. 10353431Scarlsonj 10363431Scarlsonj - The various attributes of the IPC commands (requires privileges, 10373431Scarlsonj creates a new session, valid with BOOTP, immediate reply) should 10383431Scarlsonj be gathered together into one look-up table rather than scattered 10393431Scarlsonj as hard-coded tests. 10403431Scarlsonj 10413431Scarlsonj - Remove the event unregistration from the command dispatch loop and 10423431Scarlsonj get rid of the ipc_action_pending() botch. We'll get a 10433431Scarlsonj zero-length read any time the client goes away, and that will be 10443431Scarlsonj enough to trigger termination. This fix removes async_pending() 10453431Scarlsonj and async_timeout() as well, and fixes CR 6487958 as a 10463431Scarlsonj side-effect. 10473431Scarlsonj 10483431Scarlsonj - Throughout the dhcpagent code, there are private implementations 10493431Scarlsonj of doubly-linked and singly-linked lists for each data type. 10503431Scarlsonj These will all be removed and replaced with insque(3C) and 10513431Scarlsonj remque(3C). 10523431Scarlsonj 10533431Scarlsonj 10543431ScarlsonjTesting 10553431Scarlsonj 10563431Scarlsonj The implementation was tested using the TAHI test suite for DHCPv6 10573431Scarlsonj (www.tahi.org). There are some peculiar aspects to this test suite, 10583431Scarlsonj and these issues directed some of the design. In particular: 10593431Scarlsonj 10603431Scarlsonj - If Renew/Rebind doesn't mention one of our leases, then we need to 10613431Scarlsonj allow the message to be retransmitted. Real servers are unlikely 10623431Scarlsonj to do this. 10633431Scarlsonj 10643431Scarlsonj - We must look for a status code within IAADDR and within IA_NA, and 10653431Scarlsonj handle the paradoxical case of "NoAddrAvail." That doesn't make 10663431Scarlsonj sense, as a server with no addresses wouldn't use those options. 10673431Scarlsonj That option makes more sense at the top level of the message. 10683431Scarlsonj 10693431Scarlsonj - If we get "UseMulticast" when we were already using multicast, 10703431Scarlsonj then ignore the error code. Sending another request would cause a 10713431Scarlsonj loop. 10723431Scarlsonj 10733431Scarlsonj - TAHI uses "NoBinding" at the top level of the message. This 10743431Scarlsonj status code only makes sense within an IA, as it refers to the 10753431Scarlsonj GUID:IAID binding, which doesn't exist outside an IA. We must 10763431Scarlsonj ignore such errors -- treat them as success. 10773431Scarlsonj 10783431Scarlsonj 10793431ScarlsonjInteractions With Other Projects 10803431Scarlsonj 10813431Scarlsonj Clearview UV (vanity naming) will cause link names, and thus IP 10823431Scarlsonj interface names, to become changeable over time. This will break 10833431Scarlsonj the IAID stability mechanism if UV is used for arbitrary renaming, 10843431Scarlsonj rather than as just a DR enhancement. 10853431Scarlsonj 10863431Scarlsonj When this portion of Clearview integrates, this part of the DHCPv6 10873431Scarlsonj design may need to be revisited. (The solution will likely be 10883431Scarlsonj handled at some higher layer, such as within Network Automagic.) 10893431Scarlsonj 10903431Scarlsonj Clearview is also contributing a new libdlpi that will work for 10913431Scarlsonj dhcpagent, and is thus removing the private dlpi_io.[ch] functions 10923431Scarlsonj from this daemon. When that Clearview project integrates, the 10933431Scarlsonj DHCPv6 project will need to adjust to the new interfaces, and remove 10943431Scarlsonj or relocate the dlpi_to_arp() function. 10953431Scarlsonj 10963431Scarlsonj 10973431ScarlsonjFutures 10983431Scarlsonj 10993431Scarlsonj Zones currently cannot address any IP interfaces by way of DHCP. 11003431Scarlsonj This project will not fix that problem, but the DUID/IAID could be 11013431Scarlsonj used to help fix it in the future. 11023431Scarlsonj 11033431Scarlsonj In particular, the DUID allows the client to obtain separate sets of 11043431Scarlsonj addresses and configuration parameters on a single interface, just 11053431Scarlsonj like an IPv4 Client ID, but it includes a clean mechanism for vendor 11063431Scarlsonj extensions. If we associate the DUID with the zone identifier or 11073431Scarlsonj name through an extension, then we have a really simple way of 11083431Scarlsonj allocating per-zone addresses. 11093431Scarlsonj 11103431Scarlsonj Moreover, RFC 4361 describes a handy way of using DHCPv6 DUID/IAID 11113431Scarlsonj values with IPv4 DHCP, which would quickly solve the problem of 11123431Scarlsonj using DHCP for IPv4 address assignment in non-global zones as well. 11133431Scarlsonj 11143431Scarlsonj (One potential risk with this plan is that there may be server 11153431Scarlsonj implementations that either do not implement the RFC correctly or 11163431Scarlsonj otherwise mishandle the DUID. This has apparently bitten some early 11173431Scarlsonj adopters.) 11183431Scarlsonj 11193431Scarlsonj Implementing the FQDN option for DHCPv6 would, given the current 11203431Scarlsonj libdhcputil design, require a new 'type' of entry for the inittab6 11213431Scarlsonj file. This is because the design does not allow for any simple 11223431Scarlsonj means to ``compose'' a sequence of basic types together. Thus, 11233431Scarlsonj every type of option must either be a basic type, or an array of 11243431Scarlsonj multiple instances of the same basic type. 11253431Scarlsonj 11263431Scarlsonj If we implement FQDN in the future, it may be useful to explore some 11273431Scarlsonj means of allowing a given option instance to be a sequence of basic 11283431Scarlsonj types. 11293431Scarlsonj 11303431Scarlsonj This project does not make the DNS resolver or any other subsystem 11313431Scarlsonj use the data gathered by DHCPv6. It just makes the data available 11323431Scarlsonj through dhcpinfo(1). Future projects should modify those services 11333431Scarlsonj to use configuration data learned via DHCPv6. (One of the reasons 11343431Scarlsonj this is not being done now is that Network Automagic [NWAM] will 11353431Scarlsonj likely be changing this area substantially in the very near future, 11363431Scarlsonj and thus the effort would be largely wasted.) 11373431Scarlsonj 11383431Scarlsonj 11393431ScarlsonjAppendix A - Choice of Venue 11403431Scarlsonj 11413431Scarlsonj There are three logical places to implement DHCPv6: 11423431Scarlsonj 11433431Scarlsonj - in dhcpagent 11443431Scarlsonj - in in.ndpd 11453431Scarlsonj - in a new daemon (say, 'dhcp6agent') 11463431Scarlsonj 11473431Scarlsonj We need to access parameters via dhcpinfo, and should provide the 11483431Scarlsonj same set of status and control features via ifconfig as are present 11493431Scarlsonj for IPv4. (For the latter, if we fail to do that, it will likely 11503431Scarlsonj confuse users. The expense for doing it is comparatively small, and 11513431Scarlsonj it will be useful for testing, even though it should not be needed 11523431Scarlsonj in normal operation.) 11533431Scarlsonj 11543431Scarlsonj If we implement somewhere other than dhcpagent, then we need to give 11553431Scarlsonj that new daemon (in.ndpd or dhcp6agent) the same basic IPC features 11563431Scarlsonj as dhcpagent already has. This means either extracting those bits 11573431Scarlsonj (async.c and ipc_action.c) into a shared library or just copying 11583431Scarlsonj them. Obviously, the former would be preferred, but as those bits 11593431Scarlsonj depend on the rest of the dhcpagent infrastructure for timers and 11603431Scarlsonj state handling, this means that the new process would have to look a 11613431Scarlsonj lot like dhcpagent. 11623431Scarlsonj 11633431Scarlsonj Implementing DHCPv6 as part of in.ndpd is attractive, as it 11643431Scarlsonj eliminates the confusion that the router discovery process for 11653431Scarlsonj determining interface netmasks can cause, along with the need to do 11663431Scarlsonj any signaling at all to bring DHCPv6 up. However, the need to make 11673431Scarlsonj in.ndpd more like dhcpagent is unattractive. 11683431Scarlsonj 11693431Scarlsonj Having a new dhcp6agent daemon seems to have little to recommend it, 11703431Scarlsonj other than leaving the existing dhcpagent code untouched. If we do 11713431Scarlsonj that, then we end up with two implementations that do many similar 11723431Scarlsonj things, and must be maintained in parallel. 11733431Scarlsonj 11743431Scarlsonj Thus, although it leads to some complexity in reworking the data 11753431Scarlsonj structures to fit both protocols, on balance the simplest solution 11763431Scarlsonj is to extend dhcpagent. 11773431Scarlsonj 11783431Scarlsonj 11793431ScarlsonjAppendix B - Cross-Reference 11803431Scarlsonj 11813431Scarlsonj in.ndpd 11823431Scarlsonj 11833431Scarlsonj - Start dhcpagent and issue "dhcp start" command via libdhcpagent 11843431Scarlsonj - Parse StatefulAddrConf interface option from ndpd.conf 11853431Scarlsonj - Watch for M and O bits to trigger DHCPv6 11863431Scarlsonj - Handle "no routers found" case and start DHCPv6 11873431Scarlsonj - Track prefixes and set prefix length on IFF_DHCPRUNNING aliases 11883431Scarlsonj - Send new Router Solicitation when prefix unknown 11893431Scarlsonj - Change privileges so that dhcpagent can be launched successfully 11903431Scarlsonj 11913431Scarlsonj libdhcputil 11923431Scarlsonj 11933431Scarlsonj - Parse new /etc/dhcp/inittab6 file 11943431Scarlsonj - Handle new UNUMBER24, SNUMBER64, IPV6, DUID and DOMAIN types 11953431Scarlsonj - Add DHCPv6 option iterators (dhcpv6_find_option and 11963431Scarlsonj dhcpv6_pkt_option) 11973431Scarlsonj - Add dlpi_to_arp function (temporary) 11983431Scarlsonj 11993431Scarlsonj libdhcpagent 12003431Scarlsonj 12013431Scarlsonj - Add stable DUID and IAID creation and storage support 12023431Scarlsonj functions and add new dhcp_stable.h include file 12033431Scarlsonj - Support new DECLINING and RELEASING states introduced by DHCPv6. 12043431Scarlsonj - Update implementation so that it doesn't rely on gettimeofday() 12053431Scarlsonj for I/O timeouts 12063431Scarlsonj - Extend the hostconf functions to support DHCPv6, using a new 12073431Scarlsonj ".dh6" file 12083431Scarlsonj 12093431Scarlsonj snoop 12103431Scarlsonj 12113431Scarlsonj - Add support for DHCPv6 packet decoding (all types) 12123431Scarlsonj - Add "dhcp6" filter keyword 12133431Scarlsonj - Fix known bugs in DHCP filtering 12143431Scarlsonj 12153431Scarlsonj ifconfig 12163431Scarlsonj 12173431Scarlsonj - Remove inet-only restriction on "dhcp" keyword 12183431Scarlsonj 12193431Scarlsonj netstat 12203431Scarlsonj 12213431Scarlsonj - Remove strange "-I list" feature. 12223431Scarlsonj - Add support for DHCPv6 and iterating over IPv6 interfaces. 12233431Scarlsonj 12243431Scarlsonj ip 12253431Scarlsonj 12263431Scarlsonj - Add extensions to IPv6 source address selection to prefer DHCPv6 12273431Scarlsonj addresses when all else is equal 12283431Scarlsonj - Fix known bugs in source address selection (remaining from TX 12293431Scarlsonj integration) 12303431Scarlsonj 12313431Scarlsonj other 12323431Scarlsonj 12333431Scarlsonj - Add ifindex and source/destination address into PKT_LIST. 12343431Scarlsonj - Add more ARPHDR_* and IPPORT_* values. 1235