Skip to content

feat(network): apply richer IPAM at network creation time#15

Draft
chrisgeo wants to merge 1 commit into
mainfrom
feat/chaos-1334-network-ipam
Draft

feat(network): apply richer IPAM at network creation time#15
chrisgeo wants to merge 1 commit into
mainfrom
feat/chaos-1334-network-ipam

Conversation

@chrisgeo

@chrisgeo chrisgeo commented May 2, 2026

Copy link
Copy Markdown

Summary

Extends container network create and the container-network-vmnet plugin to honor six compose-spec / Docker-style network creation options that were previously silently dropped: --gateway, --ip-range, --aux-address, --driver-opt, --ipv6, and --attachable.

The vmnet plugin actually wires the user's gateway override and IPv4 sub-range constraints through to the runtime; aux-address reservations are pre-allocated in the per-network attachment allocator so the dynamic pool never hands them out.

This is the upstream-shaped staging PR for CHAOS-1334 (Container-Compose). Companion downstream PR will land after this is reviewed.

CLI surface

container network create mynet \
    --subnet 10.0.0.0/24 \
    --gateway 10.0.0.254 \
    --ip-range 10.0.0.128/28 \
    --aux-address db=10.0.0.10 \
    --aux-address web=10.0.0.20 \
    --driver-opt mtu=1500 \
    --ipv6 \
    --attachable
Flag Where it takes effect Notes
--gateway <IPv4> vmnet_network_configuration_set_ipv4_subnet's gateway parameter (Reserved + AllocationOnly variants) Replaces hard-coded subnet.lower + 1. Requires --subnet.
--ip-range <CIDRv4> AttachmentAllocator lower/size bounds Restricts dynamic IPv4 pool to a sub-CIDR of --subnet.
--aux-address HOSTNAME=IP RotatingAddressAllocator.reserve(_:) pre-reservation Repeatable. In-range entries are reserved; out-of-range entries are recorded but require no allocator state.
--driver-opt KEY=VALUE Persisted on NetworkConfiguration and forwarded to plugin argv Repeatable. vmnet plugin does not interpret any keys today; surface exists for future enhancements without another wire break.
--ipv6 (bare) Reserved variant only — vmnet auto-allocates IPv6 prefix AllocationOnly variant rejects with actionable error pointing at reserved variant on macOS 26+.
--attachable No-op on apple/container (no swarm concept) Accepted for compose-spec parity. CLI emits explicit advisory on stderr.

What changed

  • Sources/ContainerResource/Network/NetworkConfiguration.swift — six new optional fields with decodeIfPresent / encodeIfPresent Codable plumbing and end-to-end validation.
  • Sources/ContainerCommands/Network/NetworkCreate.swift — matching CLI flags.
  • Sources/Services/ContainerAPIService/Server/Networks/NetworksService.swiftregisterService serializes the new fields into plugin start argv (JSON for the aux-address dict; repeated --driver-opt for opts).
  • Sources/Plugins/NetworkVmnet/NetworkVmnetHelper+Start.swift — parses the new argv and reconstructs the richer NetworkConfiguration.
  • Sources/Services/ContainerNetworkService/Server/{Reserved,AllocationOnly}VmnetNetwork.swift — honor user-provided gateway; AllocationOnly explicitly rejects IPv6 requests.
  • Sources/Services/ContainerNetworkService/Server/NetworkService.swift — allocator range respects ipv4Range; pre-reserves custom gateway + in-range auxAddresses.
  • Sources/Services/ContainerNetworkService/Server/AttachmentAllocator.swift — new reserveHostname(hostname:address:) helper around the underlying allocator's reserve(_:).

Wire compatibility

All new NetworkConfiguration fields are optional and decoded with decodeIfPresent. Configurations persisted by older daemons decode cleanly with nil defaults (covered by testLegacyConfigurationDecodesWithoutNewFields). Plugin argv is purely additive — newer server vs. older plugin and vice versa both behave correctly.

Known limitations (intentional, follow-up work)

  • --attachable is parsed but produces no behavioural change on apple/container today. The CLI surfaces this explicitly on stderr.
  • --driver-opt is forwarded but the vmnet plugin interprets no specific keys yet.
  • Bare --ipv6 is honored on the reserved variant only; AllocationOnly emits an actionable error pointing at the reserved variant on macOS 26+.
  • The IPv4 gateway override only takes effect when an explicit --subnet is also supplied (vmnet is source of truth otherwise).

Verification

  • swift build -c release — clean on macOS 26 / Apple silicon.
  • swift test --filter ContainerResourceTests.NetworkConfigurationTest — 11/11 passing (3 pre-existing + 8 new). Coverage: gateway/range/aux-address positive + negative validation, full-shape Codable round-trip, legacy-config decode regression.

@linear

linear Bot commented May 2, 2026

Copy link
Copy Markdown

@github-actions github-actions Bot added the cli label May 2, 2026
Extends `container network create` and the `container-network-vmnet`
plugin to honor six compose-spec / Docker-style network creation
options that were previously silently dropped: `--gateway`,
`--ip-range`, `--aux-address`, `--driver-opt`, `--ipv6`, and
`--attachable`. The vmnet plugin now actually wires the user's
gateway override and IPv4 sub-range constraints through to the
runtime; aux-address reservations are pre-allocated in the per-network
attachment allocator so the dynamic pool never hands them out.

Motivation
----------

Container-Compose (and other compose-spec orchestrators) decode these
fields from `docker-compose.yml` but cannot apply them today because
`container network create` only accepts `--label`, `--internal`,
`--subnet`, `--subnet-v6`, `--plugin`, and `--plugin-variant`. The
gap was tracked downstream in CHAOS-1334 and surfaced as warn-and-skip
behaviour in container-compose's `setupNetwork` path. With this PR
the runtime accepts the full IPAM surface and the plugin honours each
field at network start.

What this PR changes
--------------------

- Sources/ContainerResource/Network/NetworkConfiguration.swift: six
  new optional fields on the persisted `NetworkConfiguration`
  (`ipv4Gateway`, `ipv4Range`, `auxAddresses`, `driverOpts`,
  `attachable`, `enableIPv6`). All decoded with `decodeIfPresent`,
  encoded with `encodeIfPresent`, and validated end-to-end (gateway,
  range, and aux-addresses must lie inside `ipv4Subnet` when both are
  configured).
- Sources/ContainerCommands/Network/NetworkCreate.swift: matching CLI
  flags (`--gateway`, `--ip-range`, `--aux-address HOSTNAME=IP`
  repeatable, `--driver-opt KEY=VALUE` repeatable, `--ipv6`, and
  `--attachable`). The CLI emits an explicit advisory on stderr when
  `--attachable` is requested because apple/container has no swarm
  attachment concept.
- Sources/Services/ContainerAPIService/Server/Networks/NetworksService.swift:
  `registerService` now serializes the new configuration fields into
  argv passed to the plugin's `start` subcommand. `auxAddresses` is
  encoded as a single JSON argv value to keep the wire shape simple
  and trivially extensible; `driverOpts` is forwarded as repeated
  `--driver-opt KEY=VALUE` entries.
- Sources/Plugins/NetworkVmnet/NetworkVmnetHelper+Start.swift: parses
  the new argv (`--gateway`, `--ip-range`, `--aux-addresses`,
  `--driver-opt`, `--ipv6`) and reconstructs a richer
  `NetworkConfiguration` for the vmnet variants.
- Sources/Services/ContainerNetworkService/Server/ReservedVmnetNetwork.swift
  and AllocationOnlyVmnetNetwork.swift: the IPv4 gateway is no longer
  hard-coded to `subnet.lower + 1`. When the configuration carries an
  explicit `ipv4Gateway`, that address is passed directly to
  `vmnet_network_configuration_set_ipv4_subnet` and validated as
  in-subnet. The allocation-only variant explicitly rejects the IPv6
  request paths with an actionable error pointing users at the
  `reserved` variant on macOS 26+.
- Sources/Services/ContainerNetworkService/Server/NetworkService.swift:
  the per-network attachment allocator now accepts an `ipv4Range`
  override (so the dynamic pool spans the user-supplied sub-CIDR
  rather than the full subnet) and pre-reserves both a custom gateway
  and any in-range `auxAddresses` through `RotatingAddressAllocator`'s
  existing `reserve(_:)` API. Out-of-range aux entries are recorded
  for reference but require no allocator state because they are
  already outside the dynamic pool.
- Sources/Services/ContainerNetworkService/Server/AttachmentAllocator.swift:
  small `reserveHostname(hostname:address:)` helper that wraps the
  underlying allocator's `reserve(_:)` with the actor's
  hostname-to-index dictionary, so reserved entries round-trip
  through `lookup` / `deallocate`.

Wire compatibility
------------------

All new `NetworkConfiguration` fields are optional and decoded with
`decodeIfPresent`; configurations persisted by older daemons decode
cleanly with `nil` defaults (covered by the
`testLegacyConfigurationDecodesWithoutNewFields` regression test).
Plugin argv is purely additive: a newer `NetworksService` against an
older plugin will pass argv that the plugin ignores; an older
`NetworksService` against a newer plugin simply omits the new flags
and the plugin behaves as before.

Known limitations (intentional, follow-up work)
-----------------------------------------------

- `--attachable` is accepted at the CLI for compose-spec parity but
  is not threaded into the plugin and produces no behavioural change
  on apple/container, which has no swarm-mode attachment concept. The
  CLI surfaces this explicitly on stderr.
- `--driver-opt KEY=VALUE` is parsed, persisted on the configuration,
  and forwarded through to the plugin process, but the vmnet plugin
  does not currently interpret any specific keys. Keeping the surface
  on day one means future plugin enhancements can interpret options
  (e.g. DHCP toggles) without another wire-format break.
- Bare `--ipv6` (no `--subnet-v6`) takes effect on the `reserved`
  variant only; the `allocation-only` variant does not yet support
  IPv6 and now emits an actionable error pointing at the `reserved`
  variant on macOS 26+.
- The IPv4 gateway override only takes effect when an explicit
  `--subnet` is also supplied; without a subnet, vmnet is the source
  of truth for both subnet and gateway.

Verification
------------

- `swift build -c release` clean on macOS 26 / Apple silicon.
- `swift test --filter ContainerResourceTests.NetworkConfigurationTest`
  passes 11 tests (3 pre-existing + 8 new), covering: gateway/range/
  aux-address validation (positive and negative), full-shape Codable
  round-trip, and decoding a legacy (pre-PR) JSON configuration with
  none of the new fields populated.
@chrisgeo chrisgeo force-pushed the feat/chaos-1334-network-ipam branch from 237a1b4 to a8150c8 Compare May 24, 2026 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant