A two-layer network and system-configuration stack for FreeBSD. The lower layer (Phase 1, shipped) is dhcpcd in master mode + wpa_supplicant — both run directly by launchd, handling DHCPv4/v6/RA/SLAAC, link-state, hot-plug, and WiFi association. The upper layer (Phase 2+, planned) is a port of Apple's configd as netconfigd, providing a SystemConfiguration-like dynamic store, Distributed Objects IPC for scutil and GUI tooling, and a declarative Network.plist watcher that translates user intent into dhcpcd.conf overrides. Companion to the freebsd-launchd port.
configd/ at the top of the launchd repo, alongside src/ (launchd) and kmodloader/.netconfigd as one long-running daemon owning everything — spawning dhclient/rtsold/wpa_supplicant as managed children, parsing PF_ROUTE itself, exposing DO IPC. Phase 1 implementation showed the autoconfig portion is well-served by dhcpcd (master mode covers DHCP + RA + SLAAC + IPv4LL + link-state in one daemon, with proper bridge/lagg/vlan layering recognition and userspace RDNSS/DNSSL parsing the kernel can't do). Letting dhcpcd own that layer eliminates ~800 LOC of NCDaemon work and gives us features (DHCPv6, link-up recovery, IPv4LL fallback) we'd otherwise have to write.dhcpcd (port: net/dhcpcd) running in master mode via org.freebsd.dhcpcd.plist, foreground (-B), supervised by launchd with KeepAlive=true.wpa_supplicant (port: security/wpa_supplicant) supersedes the base version — faster WPA3-SAE/OWE uptake, current EAP methods, more aggressive CVE backports.NCDaemon in the configd source tree exists as a Phase 1 stub (logs and exits). The real port resumes in Phase 2.netconfigd as a launchd-supervised daemon that sits above dhcpcd. It owns the dynamic store, exposes DO IPC (scutil and GUI clients query it), watches /Local/Library/Preferences/Network.plist for declarative config, translates per-iface preferences into dhcpcd.conf drop-in overrides, and writes /etc/resolv.conf from the merged DHCP-supplied + plist-overridden DNS state.configd-963.270.3 source already imported under configd/src/; Phase 1 amputation already done. The remaining ~14k LOC of port work is Phase 2 forward.libxpc, no IOKit, no AirPort/CoreWLAN. All Mach/IOKit paths in the imported source are deleted; service-to-service IPC uses GNUstep Distributed Objects (NSConnection + NSPortCoder) over AF_UNIX.DISPATCH_SOURCE_TYPE_VNODE on Network.plist for live config reload; DISPATCH_SOURCE_TYPE_READ on PF_ROUTE for state-query observation (not for action — dhcpcd does action); DISPATCH_SOURCE_TYPE_PROC for managed-child supervision (only if we need to manage anything beyond what dhcpcd already covers)./Local/Library/Preferences/Network.plist — the canonical config netconfigd reads and the GUI edits. netconfigd merges this with DHCP-supplied state and writes appropriate dhcpcd config and /etc/resolv.conf.Network.plist needed for the auto path; that file's role begins when Phase 2 ships.configd source files retain their Apache 2.0 headers per-file. NOTICE enumerates Apple, GNUstep, dhcpcd, wpa_supplicant, and us.A FreeBSD live ISO that boots with launchd as PID 1, gets a working network in seconds without user intervention (Phase 1 shipped), and grows over Phase 2+ a SystemConfiguration-equivalent layer on top — declarative config via Network.plist, a clean ObjC API for GUI tooling, and a scutil-equivalent CLI — while delegating the protocol-level work (DHCP, RA, WiFi association) to the well-maintained ports daemons that already handle it.
accept_rtadv path doesn't.wpa_supplicant. dhcpcd auto-coordinates with wpa_supplicant via its built-in hook for wifi-iface DHCP after association.InterfaceNamer uses IOKit to assign persistent names; FreeBSD names interfaces in-kernel.mach/... include and every .defs file is amputated. NSConnection over AF_UNIX is the IPC./etc/rc.conf compatibility layer. Network.plist is the only declarative config netconfigd reads.Two layers, separable in time and ownership:
Apple's configd has both layers fused — IPConfiguration agent (DHCP/RA) lives inside the configd process. That's twenty years of Apple-internal work. FreeBSD's stack has a different shape: dhcpcd already does what IPConfiguration does, including features (DHCPv6, IPv4LL, RDNSS in userspace, master-mode hot-plug) that took Apple a long time to add. We get those for free by running dhcpcd directly, and free our netconfigd work for what's actually missing on FreeBSD: the SystemConfiguration layer (dynamic store + DO IPC + declarative config) on top.
The boundary between layers is clean: dhcpcd owns actions (acquire lease, configure address, follow link state); netconfigd owns policy (read Network.plist, decide what to ask dhcpcd to do, expose state to clients). They communicate via dhcpcd's existing config files + signals + lease-state files; netconfigd doesn't need to talk a custom protocol to dhcpcd.
Run directly by launchd via /System/Library/LaunchDaemons/org.freebsd.dhcpcd.plist. ProgramArguments=["/usr/local/sbin/dhcpcd", "-B"] — the -B flag keeps dhcpcd in foreground so launchd's KeepAlive=true can supervise it. Master mode (no iface argument) means dhcpcd:
RTM_NEWLINK/equivalent for new ifaces appearing (hot-plug USB ethernet, etc.).IFDISABLED on the iface before sending IPv6 packets — we don't have to add -ifdisabled to ifconfig invocations.Listed in pkglist.txt. Installs to /usr/local/sbin/wpa_supplicant, supersedes the base version. Reasons: faster WPA3-SAE / OWE feature uptake, current EAP method support, more aggressive CVE backports. dhcpcd has a built-in wpa_supplicant hook that detects the control socket and gates DHCP behind ASSOCIATED state — out-of-the-box pairing.
Phase 1 doesn't ship a launchd plist for wpa_supplicant. SSID configuration is still user-driven via /etc/wpa_supplicant.conf or wpa_cli. Phase 2+ will introduce a netconfigd-managed flow where Network.plist declares wpa_supplicant config that netconfigd materializes and starts wpa_supplicant per wifi iface.
The Phase 1 NCDaemon is a stub:
- (void)start {
NSLog(@"netconfigd: Phase 1 placeholder (pid=%d)", getpid());
NSLog(@"netconfigd: network auto-config is dhcpcd's job; "
@"this stub exits cleanly until Phase 2");
}
It doesn't get launched (no plist references it). It builds and installs to /usr/libexec/netconfigd just to keep the configd build pipeline live; the binary sits unused until Phase 2 swaps it for the real implementation. Apple's imported source under configd/src/ is intact and ready for Phase 2 work to begin against.
The Apple configd port resumes in Phase 2. End state: a launchd-supervised long-running daemon that reads /Local/Library/Preferences/Network.plist, exposes DO IPC, and translates declarative config into dhcpcd / wpa_supplicant / kernel state. Distinct from the original plan in that it does not spawn DHCP/RA/WiFi children itself — it shapes what the lower layer does via files and signals.
Apple's configd publishes state to the SystemConfiguration "dynamic store" — a key-value space (keys like State:/Network/Interface/en0/IPv4) that processes subscribe to. We keep the same key naming for compatibility-of-mental-model, back it with an NSMutableDictionary protected by a serial dispatch queue. Subscribers register interest via the DO connection; NSDistributedNotificationCenter-style fan-out notifies them when subscribed keys change.
Sources of state:
PF_ROUTE socket: address adds/removes, link-state, route changes → populate State:/Network/Interface/<iface>/IPv{4,6}./var/db/ (or a ZeroMQ-style hook script dhcpcd runs on lease events): populate State:/Network/Service/<uuid>/DHCP.State:/Network/Interface/<iface>/WiFi with associated SSID + auth state.Network.plist: populate Setup:-prefixed keys with the user's declared config.netconfigd's main outbound effect on the lower layer. When Network.plist changes:
NSPropertyListSerialization.static ip_address=...), DNS overrides (static domain_name_servers=...), iface excludes (denyinterfaces ...), per-iface profiles./etc/dhcpcd.conf.d/netconfigd.conf (drop-in path dhcpcd reads).SIGHUP to dhcpcd's pid (in /var/run/dhcpcd.pid); dhcpcd re-reads config.For DNS specifically: dhcpcd writes /etc/resolv.conf via resolvconf(8) by default. If Network.plist declares DNS.Servers, netconfigd merges those with DHCP-supplied servers and either uses dhcpcd's nooption domain_name_servers + static domain_name_servers=... shape, or takes resolv.conf ownership directly via nohook resolv.conf in dhcpcd.conf and writes resolv.conf itself.
| Source type | Watches | Reaction |
|---|---|---|
DISPATCH_SOURCE_TYPE_VNODE | /Local/Library/Preferences/Network.plist | reload via NSPropertyListSerialization; diff against last snapshot; regenerate /etc/dhcpcd.conf.d/netconfigd.conf; SIGHUP dhcpcd |
DISPATCH_SOURCE_TYPE_READ | PF_ROUTE socket | parse routing message; update dynamic store State:/Network/Interface/<iface>/...; fan out to DO subscribers |
DISPATCH_SOURCE_TYPE_VNODE | dhcpcd lease database directory | refresh dynamic store DHCP-state keys when leases change |
DISPATCH_SOURCE_TYPE_SIGNAL | SIGTERM / SIGHUP | SIGTERM: clean shutdown. SIGHUP: force config reload from plist. |
freebsd-launchd/configd/freebsd-launchd/configd/
├── Makefile gmake build, installs to /usr/libexec/netconfigd
├── compat/ FreeBSD shims for Apple-internal headers
├── scripts/import-source.sh (Phase 0) clones apple-oss-distributions/configd
└── src/ Apple configd-963.270.3 (post-amputation)
├── configd.tproj/
│ ├── main.m (Phase 1) Foundation entry, calls NCDaemon
│ ├── NCDaemon.{h,m} (Phase 1) stub; Phase 2 grows it
│ ├── _SC_dynamicStore_*.{c,h} (Phase 2) ObjC rewrite
│ └── ... Apple imports, Mach paths amputated
├── Plugins/
│ ├── IPMonitor/ (Phase 2 port — repurposed for resolv.conf merge)
│ ├── KernelEventMonitor/ (Phase 2 rewrite — PF_ROUTE source)
│ ├── LinkConfiguration/ (Phase 2 port)
│ ├── PreferencesMonitor/ (Phase 2 port — Network.plist watcher)
│ └── SCNetworkReachability/ (Phase 2 port — DO API)
├── libSystemConfiguration/
├── nwi/
├── scutil.tproj/ (Phase 2 port — DO client)
├── SystemConfiguration.fproj/
├── common/
└── logging/
Top-level (freebsd-launchd/) hosts:
overlays/System/Library/LaunchDaemons/org.freebsd.dhcpcd.plist — Phase 1, in place.overlays/System/Library/LaunchDaemons/org.freebsd.netconfigd.plist — removed in Phase 1; will return in Phase 2.pkglist.txt — lists dhcpcd + wpa_supplicant.build.sh — chroot-side, runs make-configd.sh after launchd build to keep the configd build live; the resulting binary is unused in Phase 1.build.sh handles configdSame chroot session that builds launchd + kmodloader. build.sh rsyncs configd/ into chroot:/tmp/configd/ and runs make-configd.sh against the just-installed Foundation/libdispatch. Installs to /usr/libexec/netconfigd.
| Decision | Choice |
|---|---|
| Target kernel | FreeBSD 14.x and 15.x. No Linux, no NetBSD. |
| DHCPv4 / DHCPv6 / RA / SLAAC / IPv4LL | dhcpcd in master mode (Phase 1). NOT dhclient + rtsold + dhcp6c. NOT internal to netconfigd. |
| WiFi authentication | wpa_supplicant from ports. dhcpcd auto-coordinates via built-in wpa_supplicant hook. |
| Mach IPC / XPC / IOKit / AirPort / CoreWLAN | None. All Mach paths in imported source amputated; ObjC NSConnection over AF_UNIX is the IPC for Phase 2+. |
| Service-to-service IPC | GNUstep Distributed Objects (Phase 2+). No gdomap — direct NSSocketPort on a known path. |
| Event loop (Phase 2+) | libdispatch dispatch sources only. |
| Plist parsing | GNUstep NSPropertyListSerialization (XML + binary). |
| Source of truth for declarative config | /Local/Library/Preferences/Network.plist (Phase 2+). No rc.conf parser. No manually-edited resolv.conf (netconfigd writes it). |
| Auto-config default (Phase 1) | dhcpcd master mode covers everything — no Network.plist needed for working network. The plist's role begins in Phase 2. |
| License (top-level) | BSD-2-Clause. Apple configd files retain Apache 2.0 per-file. |
| Build platform | FreeBSD only, inside the same VM-action chroot the launchd build uses. |
configd/src/)Imported source: Apple configd-963.270.3. 289 source files; ~5.5 MB. Phase 0 amputation already done (drops the wholly-Mach files and explicit non-goals: AirPort, IOKit-based InterfaceNamer, SimulatorSupport, QoSMarking). What remains needs Phase 2 work.
configd.xcodeproj/, xcconfigs/, xcscripts/ — Xcode build infra**/*.defs — MIG interface definitions (Mach-RPC IDL)configd.tproj/_SC_*.{c,h} Mach-IPC plumbing — entire IPC server replaced by DOPlugins/QoSMarking/, Plugins/SimulatorSupport/, Plugins/InterfaceNamer/Plugins/IPMonitor/IPMonitorAWDReport.{c,h} — Apple-Wireless-DiagnosticsSCTest-Swift/ — Swift test harnesslibSystemConfiguration/SCDPlugin*.{c,h} — Mach-style plugin loader| File / dir | Apple LOC | Action | Target LOC |
|---|---|---|---|
configd.tproj/configd.{c,h} | ~1.5k | Rewrite. dispatch_main loop; NSConnection-rooted DO server. Keep dynamic-store data shape. | ~600 |
configd.tproj/_SC_dynamicStore_*.{c,h} | ~3k | Rewrite as ObjC. NSMutableDictionary + serial dispatch queue. DO callback fan-out. | ~800 |
Plugins/IPMonitor/ | ~8k | Repurpose. Original Apple role: drive IPConfiguration agent. New role: read dhcpcd lease files, populate dynamic store DHCP keys, merge with Network.plist overrides, write resolv.conf. Drop AWD reporter. | ~2.5k |
Plugins/KernelEventMonitor/ | ~2k | Rewrite. Replace PF_SYSTEM / KEV_NETWORK_CLASS with PF_ROUTE socket parsing. Observation only — actions belong to dhcpcd. | ~600 |
Plugins/LinkConfiguration/ | ~1k | Trim heavily. dhcpcd handles link-state actions; this plugin's role shrinks to dynamic-store updates on link transitions. | ~300 |
Plugins/PreferencesMonitor/ | ~2k | Port. Watches Network.plist; diff against current; regenerate /etc/dhcpcd.conf.d/netconfigd.conf; SIGHUP dhcpcd. The new core. | ~700 |
Plugins/SCNetworkReachability/ | ~3k | Port. Provides reachability API to apps via DO. Uses PF_ROUTE for change events. | ~1.2k |
libSystemConfiguration/ | ~1k | Prune Mach refs; back store-client API with DO calls. | ~600 |
nwi/ | ~600 | Keep mostly as-is (pure data structures). | ~500 |
scutil.tproj/ | ~5k | Substantial rewrite. DO client; shell-style command parsing (show, get, set, watch). | ~2k |
SystemConfiguration.fproj/ | ~10k | Trim. Keep public framework API surface; drop Apple-specific bits. | ~3k |
common/, logging/ | ~1k | Keep mostly as-is. | ~800 |
Total post-Phase-2: roughly 13-14k LOC vs Apple's ~37k pre-amputation. Slightly less than the original estimate because IPMonitor's role shrank with dhcpcd taking the IPConfiguration burden.
| Feature | Apple's configd does | This port (FreeBSD-only) |
|---|---|---|
| DHCP | Internal IPConfiguration agent (years of Apple-internal work) | dhcpcd port. DHCPv4 + DHCPv6 + IPv4LL out of the box; netconfigd drives policy via dhcpcd.conf. |
| RA / SLAAC | Internal kernel nd6 integration | dhcpcd userspace RA processing — supports RDNSS / DNSSL the kernel doesn't. |
| Kernel iface events | PF_SYSTEM + KEV_NETWORK_CLASS + kern_event | PF_ROUTE socket — standard, simpler, less Darwin-specific glue. Observation-only role; dhcpcd watches independently for action. |
| Service IPC | Mach ports + XPC + bootstrap server | GNUstep DO over AF_UNIX. Full ObjC messaging; NSPortCoder for marshalling. |
| WiFi auth | AirPort framework + eapolclient | wpa_supplicant from ports. dhcpcd auto-coordinates via built-in hook. |
| Iface naming | InterfaceNamer plugin: IOKit USB/PCI introspection | FreeBSD kernel handles this. Drop the plugin. |
| Plugin loading | Mach host port + bundle dlopen | No plugins as separate dylibs; link statically into the daemon. |
| Build-system gates | iOS / macOS / sim / catalyst #if TARGET_OS_* | Delete them all. One target. |
Build-time: clang, lld (FreeBSD base); the gnustep-make framework already installed by the launchd build; pkgconf; system-domain headers/libraries at /System/Library/.
Runtime (Phase 1, on the ISO):
net/dhcpcd, security/wpa_supplicant (in pkglist.txt).resolvconf(8) (used by dhcpcd to write /etc/resolv.conf via standard hooks).Runtime (Phase 2+, when netconfigd ships):
libdispatch.so, libgnustep-base.so, libgnustep-corebase.so, libobjc.so, libBlocksRuntime.so (all from system domain — already present from launchd).<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>Label</key> <string>org.freebsd.dhcpcd</string>
<key>ProgramArguments</key> <array>
<string>/usr/local/sbin/dhcpcd</string>
<string>-B</string>
</array>
<key>RunAtLoad</key> <true/>
<key>KeepAlive</key> <true/>
</dict>
</plist>
-B keeps dhcpcd in foreground for launchd supervision; without it dhcpcd would daemonize on its own and launchd would think the job ended. KeepAlive=true respawns dhcpcd if it dies.
<plist version="1.0">
<dict>
<key>Label</key> <string>org.freebsd.netconfigd</string>
<key>ProgramArguments</key> <array><string>/usr/libexec/netconfigd</string></array>
<key>RunAtLoad</key> <true/>
<key>KeepAlive</key> <true/>
<key>Sockets</key> <dict>
<key>Listeners</key> <dict>
<key>SockPathName</key> <string>/var/run/netconfigd.sock</string>
<key>SockType</key> <string>stream</string>
<key>SockPathMode</key> <integer>438</integer> <!-- 0666 -->
</dict>
</dict>
</dict>
</plist>
launchd opens the AF_UNIX listener at boot, hands the fd to netconfigd via the launchd-port's launch_activate_socket-equivalent. Until netconfigd is up, queued connections from scutil / GUI tools sit in the kernel's socket queue.
Network.plist schema (Phase 2+)One canonical declarative configuration file. The GUI tooling reads/writes it; netconfigd watches it and translates to dhcpcd config + resolv.conf.
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>Hostname</key>
<string>my-host</string>
<key>Interfaces</key>
<dict>
<key>em0</key>
<dict>
<key>Method</key> <string>DHCP</string>
</dict>
<key>em1</key>
<dict>
<key>Method</key> <string>Static</string>
<key>IPv4</key>
<dict>
<key>Address</key> <string>192.168.1.10/24</string>
<key>Router</key> <string>192.168.1.1</string>
</dict>
</dict>
<key>wlan0</key>
<dict>
<key>Method</key> <string>WPA</string>
<key>WPA</key>
<dict>
<key>ConfigFile</key> <string>/etc/wpa_supplicant.conf</string>
</dict>
<key>IPv4</key>
<dict>
<key>Method</key> <string>DHCP</string>
</dict>
</dict>
</dict>
<key>DNS</key>
<dict>
<!-- Optional. If absent, DNS is taken from DHCP. -->
<key>Servers</key>
<array>
<string>1.1.1.1</string>
<string>1.0.0.1</string>
</array>
<key>Search</key>
<array><string>example.com</string></array>
</dict>
</dict>
</plist>
Empty / absent Network.plist → dhcpcd's defaults apply (auto-DHCP everything, RA on every iface). This is the Phase 1 behavior; Phase 2+ keeps it as the no-config-needed default.
Per-iface dict missing → dhcpcd's defaults apply for that iface. A user who wants em0 to NOT auto-DHCP adds {"Method": "Disabled"}, which translates to denyinterfaces em0 in the generated dhcpcd.conf.
Add a top-level "Version" key (integer) once we have post-v1 schema changes. v1 is implicit; v2+ ships the daemon's accepted version range.
scutil CLI tool (Phase 2+)Apple's scutil is the system-configuration shell. Ported as a DO client of netconfigd. Initial command set:
scutil --show — dump the entire dynamic storescutil --get Hostname / --set Hostname my-host — single-key editsscutil --interfaces — list managed interfaces with current statescutil --reload — force netconfigd to re-read Network.plistscutil --watch <key> — long-running, prints on store changesThe interactive Mach-shell mode is dropped (depended on Mach store semantics).
Top-level BSD-2-Clause; Apple configd source files retain their Apache 2.0 headers per-file (inbound=outbound). New code is BSD-2-Clause with SPDX headers.
| Source | License | How we handle it |
|---|---|---|
Apple configd-963.270.3 | Apache 2.0 (Apple OSRef) | Keep Apple header verbatim. Files stay Apache regardless of top-level. |
| dhcpcd, wpa_supplicant (linked separately, not in tree) | BSD-2-Clause / BSD-3-Clause | Listed in NOTICE. |
| GNUstep base / corebase / libobjc2 (linked, not in tree) | LGPL 2.1+ / LGPL 3 (linking exception) / MIT | Listed in NOTICE. |
| libdispatch (linked, not in tree) | Apache 2.0 with Runtime Library Exception | Listed in NOTICE. |
| This repo's new code | BSD-2-Clause | Each new file gets a BSD-2-Clause SPDX header. |
configd/ at the top of freebsd-launchd; configd/scripts/import-source.sh clones apple-oss-distributions/configd at configd-963.270.3.Initial NCDaemon implementation enumerated ifaces via getifaddrs(3), ran ifconfig <iface> up, ifconfig <iface> inet6 accept_rtadv auto_linklocal, dhclient -b <iface> per ethernet, and rtsold -a once. Bench testing surfaced gaps: no IPv6 (we never cleared IFDISABLED), no link-flap recovery (devd-shaped flow we'd never built), no DHCPv6 path, no IPv4LL fallback. Dropped in Phase 1d.
dhcpcd to pkglist.txt. Created org.freebsd.dhcpcd.plist running dhcpcd in master mode (-B for foreground supervision).wpa_supplicant to pkglist (newer than base; better WPA3-SAE/OWE coverage).org.freebsd.netconfigd.plist from overlays. Simplified NCDaemon to a Phase-1 stub that logs and exits.configd.tproj/ rewrite: NSConnection-rooted DO server, NSMutableDictionary-backed dynamic store with serial dispatch queue.Plugins/PreferencesMonitor/ port: vnode source on Network.plist; diff against current; regenerate /etc/dhcpcd.conf.d/netconfigd.conf; SIGHUP dhcpcd.Plugins/KernelEventMonitor/ rewrite: PF_ROUTE source for state observation, populates dynamic store keys.Plugins/IPMonitor/ repurpose: read dhcpcd lease state, merge with plist DNS overrides, write resolv.conf.org.freebsd.netconfigd.plist with the launchd Sockets entry for the DO listener.scutil.tproj as a DO client.--show, --get, --set, --interfaces, --reload, --watch <key>.libSystemConfiguration.so; under the hood, DO calls to netconfigd.Network.plist./etc/wpa_supplicant-<iface>.conf from plist; manages a wpa_supplicant launchd job per wifi iface.configd/ at the top of freebsd-launchd.
/usr/libexec/netconfigd for the daemon (Phase 2+); /usr/sbin/scutil for the CLI client.
/etc/resolv.conf ownership in Phase 2+. dhcpcd writes resolv.conf via resolvconf(8) by default. When netconfigd ships, it has the option to take over (nohook resolv.conf in dhcpcd.conf, netconfigd writes resolv.conf merging dhcpcd state with plist overrides) or to keep dhcpcd in charge and pass overrides via static domain_name_servers=.... Decision: probably the latter (less work, dhcpcd already integrates with resolvconf cleanly). Settle when Phase 2 implementation begins.
Network.plist → dhcpcd.conf translation: drop-in file or whole-file rewrite? dhcpcd reads /etc/dhcpcd.conf.d/*.conf drop-ins after the main /etc/dhcpcd.conf. netconfigd should write /etc/dhcpcd.conf.d/netconfigd.conf and leave the main file untouched — lets advanced users tune dhcpcd globals without netconfigd clobbering. Decision deferrable.
Network.plist (PSK in plist) is simple but plaintext. A keychain layer is more secure but more work. Apple did inline for the macOS first iterations; keychain came later. Probably the same path: Phase 5 inline, future phase keychain.
gdomap or direct NSSocketPort. Direct NSSocketPort at /var/run/netconfigd.sock; no gdomap. If we end up with multiple DO services that need lookup, revisit.
"Version" key when v2 ships, or when a GUI tool needs to know which schema it's reading.
configd-963.270.3).man 8 dhcpcd; config reference in man 5 dhcpcd.conf.security/wpa_supplicant.route(4) / PF_ROUTE: man 4 route.