Skip to content

Commit 40abf11

Browse files
yordselclaude
andcommitted
Add IPv6 gateway support for container networking
Add ipv6Gateway field to network attachments and status to enable proper IPv6 routing in containers. This complements the existing ipv6Address/ipv6Subnet fields. Changes: - Attachment: Add ipv6Gateway field - NetworkState: Add ipv6Gateway to NetworkStatus - IsolatedInterfaceStrategy: Pass IPv6 gateway to NATInterface - NonisolatedInterfaceStrategy: Pass IPv6 gateway to NATNetworkInterface - NetworkService: Include ipv6Gateway in attachment creation - ReservedVmnetNetwork: Calculate and store ipv6Gateway Depends on: apple/containerization IPv6 support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 474906d commit 40abf11

File tree

6 files changed

+24
-0
lines changed

6 files changed

+24
-0
lines changed

Sources/ContainerResource/Network/Attachment.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ public struct Attachment: Codable, Sendable {
2929
/// The CIDR address describing the interface IPv6 address, with the prefix length of the subnet.
3030
/// The address is nil if the IPv6 subnet could not be determined at network creation time.
3131
public let ipv6Address: CIDRv6?
32+
/// The IPv6 gateway address.
33+
/// The value is nil if the IPv6 subnet could not be determined at network creation time.
34+
public let ipv6Gateway: IPv6Address?
3235
/// The MAC address associated with the attachment (optional).
3336
public let macAddress: MACAddress?
3437

@@ -38,13 +41,15 @@ public struct Attachment: Codable, Sendable {
3841
ipv4Address: CIDRv4,
3942
ipv4Gateway: IPv4Address,
4043
ipv6Address: CIDRv6?,
44+
ipv6Gateway: IPv6Address? = nil,
4145
macAddress: MACAddress?
4246
) {
4347
self.network = network
4448
self.hostname = hostname
4549
self.ipv4Address = ipv4Address
4650
self.ipv4Gateway = ipv4Gateway
4751
self.ipv6Address = ipv6Address
52+
self.ipv6Gateway = ipv6Gateway
4853
self.macAddress = macAddress
4954
}
5055
}

Sources/ContainerResource/Network/NetworkState.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,20 @@ public struct NetworkStatus: Codable, Sendable {
3030
/// The value is nil if the IPv6 subnet cannot be determined at creation time.
3131
public let ipv6Subnet: CIDRv6?
3232

33+
/// The gateway IPv6 address.
34+
/// The value is nil if the IPv6 subnet cannot be determined at creation time.
35+
public let ipv6Gateway: IPv6Address?
36+
3337
public init(
3438
ipv4Subnet: CIDRv4,
3539
ipv4Gateway: IPv4Address,
3640
ipv6Subnet: CIDRv6?,
41+
ipv6Gateway: IPv6Address? = nil
3742
) {
3843
self.ipv4Subnet = ipv4Subnet
3944
self.ipv4Gateway = ipv4Gateway
4045
self.ipv6Subnet = ipv6Subnet
46+
self.ipv6Gateway = ipv6Gateway
4147
}
4248
}
4349

Sources/Helpers/RuntimeLinux/IsolatedInterfaceStrategy.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@ import Containerization
2525
struct IsolatedInterfaceStrategy: InterfaceStrategy {
2626
public func toInterface(attachment: Attachment, interfaceIndex: Int, additionalData: XPCMessage?) -> Interface {
2727
let ipv4Gateway = interfaceIndex == 0 ? attachment.ipv4Gateway : nil
28+
let ipv6Gateway = interfaceIndex == 0 ? attachment.ipv6Gateway : nil
2829
return NATInterface(
2930
ipv4Address: attachment.ipv4Address,
3031
ipv4Gateway: ipv4Gateway,
32+
ipv6Address: attachment.ipv6Address,
33+
ipv6Gateway: ipv6Gateway,
3134
macAddress: attachment.macAddress,
3235
// https://github.com/apple/containerization/pull/38
3336
mtu: 1280

Sources/Helpers/RuntimeLinux/NonisolatedInterfaceStrategy.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,12 @@ struct NonisolatedInterfaceStrategy: InterfaceStrategy {
4444

4545
log.info("creating NATNetworkInterface with network reference")
4646
let ipv4Gateway = interfaceIndex == 0 ? attachment.ipv4Gateway : nil
47+
let ipv6Gateway = interfaceIndex == 0 ? attachment.ipv6Gateway : nil
4748
return NATNetworkInterface(
4849
ipv4Address: attachment.ipv4Address,
4950
ipv4Gateway: ipv4Gateway,
51+
ipv6Address: attachment.ipv6Address,
52+
ipv6Gateway: ipv6Gateway,
5053
reference: networkRef,
5154
macAddress: attachment.macAddress,
5255
// https://github.com/apple/containerization/pull/38

Sources/Services/ContainerNetworkService/Server/NetworkService.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public actor NetworkService: Sendable {
7777
ipv4Address: try CIDRv4(ip, prefix: status.ipv4Subnet.prefix),
7878
ipv4Gateway: status.ipv4Gateway,
7979
ipv6Address: ipv6Address,
80+
ipv6Gateway: status.ipv6Gateway,
8081
macAddress: macAddress
8182
)
8283
log?.info(
@@ -86,6 +87,7 @@ public actor NetworkService: Sendable {
8687
"ipv4Address": "\(attachment.ipv4Address)",
8788
"ipv4Gateway": "\(attachment.ipv4Gateway)",
8889
"ipv6Address": "\(attachment.ipv6Address?.description ?? "unavailable")",
90+
"ipv6Gateway": "\(attachment.ipv6Gateway?.description ?? "unavailable")",
8991
"macAddress": "\(attachment.macAddress?.description ?? "unspecified")",
9092
])
9193
let reply = message.reply()
@@ -136,6 +138,7 @@ public actor NetworkService: Sendable {
136138
ipv4Address: ipv4Address,
137139
ipv4Gateway: status.ipv4Gateway,
138140
ipv6Address: ipv6Address,
141+
ipv6Gateway: status.ipv6Gateway,
139142
macAddress: macAddress
140143
)
141144
log?.debug(

Sources/Services/ContainerNetworkService/Server/ReservedVmnetNetwork.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public final class ReservedVmnetNetwork: Network {
4141
let ipv4Subnet: CIDRv4
4242
let ipv4Gateway: IPv4Address
4343
let ipv6Subnet: CIDRv6
44+
let ipv6Gateway: IPv6Address
4445
}
4546

4647
private let stateMutex: Mutex<State>
@@ -85,6 +86,7 @@ public final class ReservedVmnetNetwork: Network {
8586
ipv4Subnet: networkInfo.ipv4Subnet,
8687
ipv4Gateway: networkInfo.ipv4Gateway,
8788
ipv6Subnet: networkInfo.ipv6Subnet,
89+
ipv6Gateway: networkInfo.ipv6Gateway
8890
)
8991
state.networkState = NetworkState.running(configuration, networkStatus)
9092
state.network = networkInfo.network
@@ -183,6 +185,7 @@ public final class ReservedVmnetNetwork: Network {
183185
}
184186
let prefixIpv6Addr = try IPv6Address(prefixIpv6Bytes)
185187
let runningV6Subnet = try CIDRv6(prefixIpv6Addr, prefix: prefix)
188+
let runningV6Gateway = IPv6Address(runningV6Subnet.lower.value + 1)
186189

187190
log.info(
188191
"started vmnet network",
@@ -199,6 +202,7 @@ public final class ReservedVmnetNetwork: Network {
199202
ipv4Subnet: runningSubnet,
200203
ipv4Gateway: runningGateway,
201204
ipv6Subnet: runningV6Subnet,
205+
ipv6Gateway: runningV6Gateway
202206
)
203207
}
204208
}

0 commit comments

Comments
 (0)