Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions Sources/Containerization/ContainerManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -302,15 +302,17 @@ public struct ContainerManager: Sendable {
if let imageConfig {
config.process = .init(from: imageConfig)
}
if networking, let interface = try self.network?.createInterface(id) {
config.interfaces = [interface]
guard let gateway = interface.ipv4Gateway else {
throw ContainerizationError(
.invalidState,
message: "missing ipv4 gateway for container \(id)"
)
if networking {
if let interface = try self.network?.createInterface(id) {
config.interfaces = [interface]
guard let gateway = interface.ipv4Gateway else {
throw ContainerizationError(
.invalidState,
message: "missing ipv4 gateway for container \(id)"
)
}
config.dns = .init(nameservers: [gateway.description])
}
config.dns = .init(nameservers: [gateway.description])
}
config.bootLog = BootLog.file(path: self.containerRoot.appendingPathComponent(id).appendingPathComponent("bootlog.log"))
try configuration(&config)
Expand Down
11 changes: 10 additions & 1 deletion Sources/Containerization/Interface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,16 @@ public protocol Interface: Sendable {
/// Example: `192.168.64.3/24`
var ipv4Address: CIDRv4 { get }

/// The IP address for the default route, or nil for no default route.
/// The IPv4 gateway address for the default route, or nil for no IPv4 default route.
var ipv4Gateway: IPv4Address? { get }

/// The interface IPv6 address and subnet prefix length, as a CIDRv6 address, or nil for no IPv6 address.
/// Example: `fd00::1/64`
var ipv6Address: CIDRv6? { get }

/// The IPv6 gateway address for the default route, or nil for no IPv6 default route.
var ipv6Gateway: IPv6Address? { get }

/// The interface MAC address, or nil to auto-configure the address.
var macAddress: MACAddress? { get }

Expand All @@ -34,4 +41,6 @@ public protocol Interface: Sendable {

extension Interface {
public var mtu: UInt32 { 1500 }
public var ipv6Address: CIDRv6? { nil }
public var ipv6Gateway: IPv6Address? { nil }
}
22 changes: 6 additions & 16 deletions Sources/Containerization/LinuxContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -635,22 +635,12 @@ extension LinuxContainer {
var defaultRouteSet = false
for (index, i) in self.interfaces.enumerated() {
let name = "eth\(index)"
self.logger?.debug("setting up interface \(name) with address \(i.ipv4Address)")
try await agent.addressAdd(name: name, ipv4Address: i.ipv4Address)
try await agent.up(name: name, mtu: i.mtu)
if defaultRouteSet {
continue
}
if let ipv4Gateway = i.ipv4Gateway {
if !i.ipv4Address.contains(ipv4Gateway) {
self.logger?.debug("gateway \(ipv4Gateway) is outside subnet \(i.ipv4Address), adding a route first")
try await agent.routeAddLink(name: name, dstIPv4Addr: ipv4Gateway, srcIPv4Addr: i.ipv4Address.address)
}
try await agent.routeAddDefault(name: name, ipv4Gateway: ipv4Gateway)
} else {
self.logger?.debug("no gateway for \(name)")
try await agent.routeAddDefault(name: name, ipv4Gateway: nil)
}
try await agent.setupInterface(
i,
name: name,
setDefaultRoute: !defaultRouteSet,
logger: self.logger
)
defaultRouteSet = true
}

Expand Down
22 changes: 6 additions & 16 deletions Sources/Containerization/LinuxPod.swift
Original file line number Diff line number Diff line change
Expand Up @@ -659,22 +659,12 @@ extension LinuxPod {
var defaultRouteSet = false
for (index, i) in self.interfaces.enumerated() {
let name = "eth\(index)"
self.logger?.debug("setting up interface \(name) with address \(i.ipv4Address)")
try await agent.addressAdd(name: name, ipv4Address: i.ipv4Address)
try await agent.up(name: name, mtu: i.mtu)
if defaultRouteSet {
continue
}
if let ipv4Gateway = i.ipv4Gateway {
if !i.ipv4Address.contains(ipv4Gateway) {
self.logger?.debug("gateway \(ipv4Gateway) is outside subnet \(i.ipv4Address), adding a route first")
try await agent.routeAddLink(name: name, dstIPv4Addr: ipv4Gateway, srcIPv4Addr: nil)
}
try await agent.routeAddDefault(name: name, ipv4Gateway: ipv4Gateway)
} else {
self.logger?.debug("no gateway for \(name)")
try await agent.routeAddDefault(name: name, ipv4Gateway: nil)
}
try await agent.setupInterface(
i,
name: name,
setDefaultRoute: !defaultRouteSet,
logger: self.logger
)
defaultRouteSet = true
}

Expand Down
13 changes: 12 additions & 1 deletion Sources/Containerization/NATInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,23 @@ import ContainerizationExtras
public struct NATInterface: Interface {
public var ipv4Address: CIDRv4
public var ipv4Gateway: IPv4Address?
public var ipv6Address: CIDRv6?
public var ipv6Gateway: IPv6Address?
public var macAddress: MACAddress?
public var mtu: UInt32

public init(ipv4Address: CIDRv4, ipv4Gateway: IPv4Address?, macAddress: MACAddress? = nil, mtu: UInt32 = 1500) {
public init(
ipv4Address: CIDRv4,
ipv4Gateway: IPv4Address?,
ipv6Address: CIDRv6? = nil,
ipv6Gateway: IPv6Address? = nil,
macAddress: MACAddress? = nil,
mtu: UInt32 = 1500
) {
self.ipv4Address = ipv4Address
self.ipv4Gateway = ipv4Gateway
self.ipv6Address = ipv6Address
self.ipv6Gateway = ipv6Gateway
self.macAddress = macAddress
self.mtu = mtu
}
Expand Down
81 changes: 78 additions & 3 deletions Sources/Containerization/SandboxContext/SandboxContext.pb.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1098,9 +1098,20 @@ public struct Com_Apple_Containerization_Sandbox_V3_IpAddrAddRequest: Sendable {

public var ipv4Address: String = String()

public var ipv6Address: String {
get {_ipv6Address ?? String()}
set {_ipv6Address = newValue}
}
/// Returns true if `ipv6Address` has been explicitly set.
public var hasIpv6Address: Bool {self._ipv6Address != nil}
/// Clears the value of `ipv6Address`. Subsequent reads from it will return its default value.
public mutating func clearIpv6Address() {self._ipv6Address = nil}

public var unknownFields = SwiftProtobuf.UnknownStorage()

public init() {}

fileprivate var _ipv6Address: String? = nil
}

public struct Com_Apple_Containerization_Sandbox_V3_IpAddrAddResponse: Sendable {
Expand All @@ -1124,9 +1135,30 @@ public struct Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest: Senda

public var srcIpv4Addr: String = String()

public var dstIpv6Addr: String {
get {_dstIpv6Addr ?? String()}
set {_dstIpv6Addr = newValue}
}
/// Returns true if `dstIpv6Addr` has been explicitly set.
public var hasDstIpv6Addr: Bool {self._dstIpv6Addr != nil}
/// Clears the value of `dstIpv6Addr`. Subsequent reads from it will return its default value.
public mutating func clearDstIpv6Addr() {self._dstIpv6Addr = nil}

public var srcIpv6Addr: String {
get {_srcIpv6Addr ?? String()}
set {_srcIpv6Addr = newValue}
}
/// Returns true if `srcIpv6Addr` has been explicitly set.
public var hasSrcIpv6Addr: Bool {self._srcIpv6Addr != nil}
/// Clears the value of `srcIpv6Addr`. Subsequent reads from it will return its default value.
public mutating func clearSrcIpv6Addr() {self._srcIpv6Addr = nil}

public var unknownFields = SwiftProtobuf.UnknownStorage()

public init() {}

fileprivate var _dstIpv6Addr: String? = nil
fileprivate var _srcIpv6Addr: String? = nil
}

public struct Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkResponse: Sendable {
Expand All @@ -1148,9 +1180,20 @@ public struct Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefaultRequest: Se

public var ipv4Gateway: String = String()

public var ipv6Gateway: String {
get {_ipv6Gateway ?? String()}
set {_ipv6Gateway = newValue}
}
/// Returns true if `ipv6Gateway` has been explicitly set.
public var hasIpv6Gateway: Bool {self._ipv6Gateway != nil}
/// Clears the value of `ipv6Gateway`. Subsequent reads from it will return its default value.
public mutating func clearIpv6Gateway() {self._ipv6Gateway = nil}

public var unknownFields = SwiftProtobuf.UnknownStorage()

public init() {}

fileprivate var _ipv6Gateway: String? = nil
}

public struct Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefaultResponse: Sendable {
Expand Down Expand Up @@ -3193,7 +3236,7 @@ extension Com_Apple_Containerization_Sandbox_V3_IpLinkSetResponse: SwiftProtobuf

extension Com_Apple_Containerization_Sandbox_V3_IpAddrAddRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".IpAddrAddRequest"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}interface\0\u{1}ipv4Address\0")
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}interface\0\u{1}ipv4Address\0\u{1}ipv6Address\0")

public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
Expand All @@ -3203,24 +3246,33 @@ extension Com_Apple_Containerization_Sandbox_V3_IpAddrAddRequest: SwiftProtobuf.
switch fieldNumber {
case 1: try { try decoder.decodeSingularStringField(value: &self.interface) }()
case 2: try { try decoder.decodeSingularStringField(value: &self.ipv4Address) }()
case 3: try { try decoder.decodeSingularStringField(value: &self._ipv6Address) }()
default: break
}
}
}

public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
if !self.interface.isEmpty {
try visitor.visitSingularStringField(value: self.interface, fieldNumber: 1)
}
if !self.ipv4Address.isEmpty {
try visitor.visitSingularStringField(value: self.ipv4Address, fieldNumber: 2)
}
try { if let v = self._ipv6Address {
try visitor.visitSingularStringField(value: v, fieldNumber: 3)
} }()
try unknownFields.traverse(visitor: &visitor)
}

public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_IpAddrAddRequest, rhs: Com_Apple_Containerization_Sandbox_V3_IpAddrAddRequest) -> Bool {
if lhs.interface != rhs.interface {return false}
if lhs.ipv4Address != rhs.ipv4Address {return false}
if lhs._ipv6Address != rhs._ipv6Address {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
Expand All @@ -3247,7 +3299,7 @@ extension Com_Apple_Containerization_Sandbox_V3_IpAddrAddResponse: SwiftProtobuf

extension Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".IpRouteAddLinkRequest"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}interface\0\u{1}dstIpv4Addr\0\u{1}srcIpv4Addr\0")
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}interface\0\u{1}dstIpv4Addr\0\u{1}srcIpv4Addr\0\u{1}dstIpv6Addr\0\u{1}srcIpv6Addr\0")

public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
Expand All @@ -3258,12 +3310,18 @@ extension Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest: SwiftProt
case 1: try { try decoder.decodeSingularStringField(value: &self.interface) }()
case 2: try { try decoder.decodeSingularStringField(value: &self.dstIpv4Addr) }()
case 3: try { try decoder.decodeSingularStringField(value: &self.srcIpv4Addr) }()
case 4: try { try decoder.decodeSingularStringField(value: &self._dstIpv6Addr) }()
case 5: try { try decoder.decodeSingularStringField(value: &self._srcIpv6Addr) }()
default: break
}
}
}

public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
if !self.interface.isEmpty {
try visitor.visitSingularStringField(value: self.interface, fieldNumber: 1)
}
Expand All @@ -3273,13 +3331,21 @@ extension Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest: SwiftProt
if !self.srcIpv4Addr.isEmpty {
try visitor.visitSingularStringField(value: self.srcIpv4Addr, fieldNumber: 3)
}
try { if let v = self._dstIpv6Addr {
try visitor.visitSingularStringField(value: v, fieldNumber: 4)
} }()
try { if let v = self._srcIpv6Addr {
try visitor.visitSingularStringField(value: v, fieldNumber: 5)
} }()
try unknownFields.traverse(visitor: &visitor)
}

public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest, rhs: Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest) -> Bool {
if lhs.interface != rhs.interface {return false}
if lhs.dstIpv4Addr != rhs.dstIpv4Addr {return false}
if lhs.srcIpv4Addr != rhs.srcIpv4Addr {return false}
if lhs._dstIpv6Addr != rhs._dstIpv6Addr {return false}
if lhs._srcIpv6Addr != rhs._srcIpv6Addr {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
Expand All @@ -3306,7 +3372,7 @@ extension Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkResponse: SwiftPro

extension Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefaultRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".IpRouteAddDefaultRequest"
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}interface\0\u{1}ipv4Gateway\0")
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}interface\0\u{1}ipv4Gateway\0\u{1}ipv6Gateway\0")

public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
Expand All @@ -3316,24 +3382,33 @@ extension Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefaultRequest: SwiftP
switch fieldNumber {
case 1: try { try decoder.decodeSingularStringField(value: &self.interface) }()
case 2: try { try decoder.decodeSingularStringField(value: &self.ipv4Gateway) }()
case 3: try { try decoder.decodeSingularStringField(value: &self._ipv6Gateway) }()
default: break
}
}
}

public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
if !self.interface.isEmpty {
try visitor.visitSingularStringField(value: self.interface, fieldNumber: 1)
}
if !self.ipv4Gateway.isEmpty {
try visitor.visitSingularStringField(value: self.ipv4Gateway, fieldNumber: 2)
}
try { if let v = self._ipv6Gateway {
try visitor.visitSingularStringField(value: v, fieldNumber: 3)
} }()
try unknownFields.traverse(visitor: &visitor)
}

public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefaultRequest, rhs: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefaultRequest) -> Bool {
if lhs.interface != rhs.interface {return false}
if lhs.ipv4Gateway != rhs.ipv4Gateway {return false}
if lhs._ipv6Gateway != rhs._ipv6Gateway {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
Expand Down
4 changes: 4 additions & 0 deletions Sources/Containerization/SandboxContext/SandboxContext.proto
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ message IpLinkSetResponse {}
message IpAddrAddRequest {
string interface = 1;
string ipv4Address = 2;
optional string ipv6Address = 3;
}

message IpAddrAddResponse {}
Expand All @@ -311,13 +312,16 @@ message IpRouteAddLinkRequest {
string interface = 1;
string dstIpv4Addr = 2;
string srcIpv4Addr = 3;
optional string dstIpv6Addr = 4;
optional string srcIpv6Addr = 5;
}

message IpRouteAddLinkResponse {}

message IpRouteAddDefaultRequest {
string interface = 1;
string ipv4Gateway = 2;
optional string ipv6Gateway = 3;
}

message IpRouteAddDefaultResponse {}
Expand Down
Loading
Loading