mirror of
https://github.com/apple/container.git
synced 2026-09-12 02:35:42 +00:00
Netlink: Add stats support (#308)
Adds support for grabbing stats for an iface. This will be surfaced in a coming change to get container level statistics from the guest, where one field will be network stats.
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Copyright © 2025 Apple Inc. and the Containerization project authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Statistics for a network interface.
|
||||
public struct InterfaceStatistics {
|
||||
public var name: String
|
||||
public var receivedPackets: UInt64?
|
||||
public var transmittedPackets: UInt64?
|
||||
public var receivedBytes: UInt64?
|
||||
public var transmittedBytes: UInt64?
|
||||
public var receivedErrors: UInt64?
|
||||
public var transmittedErrors: UInt64?
|
||||
|
||||
public init(
|
||||
name: String,
|
||||
receivedPackets: UInt64?,
|
||||
transmittedPackets: UInt64?,
|
||||
receivedBytes: UInt64?,
|
||||
transmittedBytes: UInt64?,
|
||||
receivedErrors: UInt64?,
|
||||
transmittedErrors: UInt64?
|
||||
) {
|
||||
self.name = name
|
||||
self.receivedPackets = receivedPackets
|
||||
self.transmittedPackets = transmittedPackets
|
||||
self.receivedBytes = receivedBytes
|
||||
self.transmittedBytes = transmittedBytes
|
||||
self.receivedErrors = receivedErrors
|
||||
self.transmittedErrors = transmittedErrors
|
||||
}
|
||||
}
|
||||
@@ -154,6 +154,11 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextClientProtoc
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<Com_Apple_Containerization_Sandbox_V3_ConfigureHostsRequest, Com_Apple_Containerization_Sandbox_V3_ConfigureHostsResponse>
|
||||
|
||||
func interfaceStatistics(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest,
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest, Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse>
|
||||
|
||||
func sync(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_SyncRequest,
|
||||
callOptions: CallOptions?
|
||||
@@ -603,6 +608,24 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextClientProtocol {
|
||||
)
|
||||
}
|
||||
|
||||
/// Get statistics about an interface.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to InterfaceStatistics.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||
public func interfaceStatistics(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest, Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse> {
|
||||
return self.makeUnaryCall(
|
||||
path: Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.interfaceStatistics.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeInterfaceStatisticsInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
/// Perform the sync syscall.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -823,6 +846,11 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncClientP
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<Com_Apple_Containerization_Sandbox_V3_ConfigureHostsRequest, Com_Apple_Containerization_Sandbox_V3_ConfigureHostsResponse>
|
||||
|
||||
func makeInterfaceStatisticsCall(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest, Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse>
|
||||
|
||||
func makeSyncCall(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_SyncRequest,
|
||||
callOptions: CallOptions?
|
||||
@@ -1132,6 +1160,18 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncClientProtoco
|
||||
)
|
||||
}
|
||||
|
||||
public func makeInterfaceStatisticsCall(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncUnaryCall<Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest, Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse> {
|
||||
return self.makeAsyncUnaryCall(
|
||||
path: Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.interfaceStatistics.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeInterfaceStatisticsInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
public func makeSyncCall(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_SyncRequest,
|
||||
callOptions: CallOptions? = nil
|
||||
@@ -1447,6 +1487,18 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncClientProtoco
|
||||
)
|
||||
}
|
||||
|
||||
public func interfaceStatistics(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse {
|
||||
return try await self.performAsyncUnaryCall(
|
||||
path: Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.interfaceStatistics.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeInterfaceStatisticsInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
public func sync(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_SyncRequest,
|
||||
callOptions: CallOptions? = nil
|
||||
@@ -1563,6 +1615,9 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextClientInterc
|
||||
/// - Returns: Interceptors to use when invoking 'configureHosts'.
|
||||
func makeConfigureHostsInterceptors() -> [ClientInterceptor<Com_Apple_Containerization_Sandbox_V3_ConfigureHostsRequest, Com_Apple_Containerization_Sandbox_V3_ConfigureHostsResponse>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'interfaceStatistics'.
|
||||
func makeInterfaceStatisticsInterceptors() -> [ClientInterceptor<Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest, Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'sync'.
|
||||
func makeSyncInterceptors() -> [ClientInterceptor<Com_Apple_Containerization_Sandbox_V3_SyncRequest, Com_Apple_Containerization_Sandbox_V3_SyncResponse>]
|
||||
|
||||
@@ -1599,6 +1654,7 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata {
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipRouteAddDefault,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.configureDns,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.configureHosts,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.interfaceStatistics,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.sync,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.kill,
|
||||
]
|
||||
@@ -1749,6 +1805,12 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata {
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
public static let interfaceStatistics = GRPCMethodDescriptor(
|
||||
name: "InterfaceStatistics",
|
||||
path: "/com.apple.containerization.sandbox.v3.SandboxContext/InterfaceStatistics",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
public static let sync = GRPCMethodDescriptor(
|
||||
name: "Sync",
|
||||
path: "/com.apple.containerization.sandbox.v3.SandboxContext/Sync",
|
||||
@@ -1842,6 +1904,9 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextProvider: Ca
|
||||
/// Configure /etc/hosts.
|
||||
func configureHosts(request: Com_Apple_Containerization_Sandbox_V3_ConfigureHostsRequest, context: StatusOnlyCallContext) -> EventLoopFuture<Com_Apple_Containerization_Sandbox_V3_ConfigureHostsResponse>
|
||||
|
||||
/// Get statistics about an interface.
|
||||
func interfaceStatistics(request: Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest, context: StatusOnlyCallContext) -> EventLoopFuture<Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse>
|
||||
|
||||
/// Perform the sync syscall.
|
||||
func sync(request: Com_Apple_Containerization_Sandbox_V3_SyncRequest, context: StatusOnlyCallContext) -> EventLoopFuture<Com_Apple_Containerization_Sandbox_V3_SyncResponse>
|
||||
|
||||
@@ -2077,6 +2142,15 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextProvider {
|
||||
userFunction: self.configureHosts(request:context:)
|
||||
)
|
||||
|
||||
case "InterfaceStatistics":
|
||||
return UnaryServerHandler(
|
||||
context: context,
|
||||
requestDeserializer: ProtobufDeserializer<Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest>(),
|
||||
responseSerializer: ProtobufSerializer<Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse>(),
|
||||
interceptors: self.interceptors?.makeInterfaceStatisticsInterceptors() ?? [],
|
||||
userFunction: self.interfaceStatistics(request:context:)
|
||||
)
|
||||
|
||||
case "Sync":
|
||||
return UnaryServerHandler(
|
||||
context: context,
|
||||
@@ -2254,6 +2328,12 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvide
|
||||
context: GRPCAsyncServerCallContext
|
||||
) async throws -> Com_Apple_Containerization_Sandbox_V3_ConfigureHostsResponse
|
||||
|
||||
/// Get statistics about an interface.
|
||||
func interfaceStatistics(
|
||||
request: Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest,
|
||||
context: GRPCAsyncServerCallContext
|
||||
) async throws -> Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse
|
||||
|
||||
/// Perform the sync syscall.
|
||||
func sync(
|
||||
request: Com_Apple_Containerization_Sandbox_V3_SyncRequest,
|
||||
@@ -2502,6 +2582,15 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvider {
|
||||
wrapping: { try await self.configureHosts(request: $0, context: $1) }
|
||||
)
|
||||
|
||||
case "InterfaceStatistics":
|
||||
return GRPCAsyncServerHandler(
|
||||
context: context,
|
||||
requestDeserializer: ProtobufDeserializer<Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest>(),
|
||||
responseSerializer: ProtobufSerializer<Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse>(),
|
||||
interceptors: self.interceptors?.makeInterfaceStatisticsInterceptors() ?? [],
|
||||
wrapping: { try await self.interfaceStatistics(request: $0, context: $1) }
|
||||
)
|
||||
|
||||
case "Sync":
|
||||
return GRPCAsyncServerHandler(
|
||||
context: context,
|
||||
@@ -2624,6 +2713,10 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextServerInterc
|
||||
/// Defaults to calling `self.makeInterceptors()`.
|
||||
func makeConfigureHostsInterceptors() -> [ServerInterceptor<Com_Apple_Containerization_Sandbox_V3_ConfigureHostsRequest, Com_Apple_Containerization_Sandbox_V3_ConfigureHostsResponse>]
|
||||
|
||||
/// - Returns: Interceptors to use when handling 'interfaceStatistics'.
|
||||
/// Defaults to calling `self.makeInterceptors()`.
|
||||
func makeInterfaceStatisticsInterceptors() -> [ServerInterceptor<Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest, Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse>]
|
||||
|
||||
/// - Returns: Interceptors to use when handling 'sync'.
|
||||
/// Defaults to calling `self.makeInterceptors()`.
|
||||
func makeSyncInterceptors() -> [ServerInterceptor<Com_Apple_Containerization_Sandbox_V3_SyncRequest, Com_Apple_Containerization_Sandbox_V3_SyncResponse>]
|
||||
@@ -2662,6 +2755,7 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata {
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.ipRouteAddDefault,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.configureDns,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.configureHosts,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.interfaceStatistics,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.sync,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.kill,
|
||||
]
|
||||
@@ -2812,6 +2906,12 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata {
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
public static let interfaceStatistics = GRPCMethodDescriptor(
|
||||
name: "InterfaceStatistics",
|
||||
path: "/com.apple.containerization.sandbox.v3.SandboxContext/InterfaceStatistics",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
public static let sync = GRPCMethodDescriptor(
|
||||
name: "Sync",
|
||||
path: "/com.apple.containerization.sandbox.v3.SandboxContext/Sync",
|
||||
|
||||
@@ -954,6 +954,89 @@ public struct Com_Apple_Containerization_Sandbox_V3_ConfigureHostsResponse: Send
|
||||
public init() {}
|
||||
}
|
||||
|
||||
public struct Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest: Sendable {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
public var interface: String = String()
|
||||
|
||||
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
public init() {}
|
||||
}
|
||||
|
||||
public struct Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse: Sendable {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
public var receivedPackets: UInt64 {
|
||||
get {return _receivedPackets ?? 0}
|
||||
set {_receivedPackets = newValue}
|
||||
}
|
||||
/// Returns true if `receivedPackets` has been explicitly set.
|
||||
public var hasReceivedPackets: Bool {return self._receivedPackets != nil}
|
||||
/// Clears the value of `receivedPackets`. Subsequent reads from it will return its default value.
|
||||
public mutating func clearReceivedPackets() {self._receivedPackets = nil}
|
||||
|
||||
public var transmittedPackets: UInt64 {
|
||||
get {return _transmittedPackets ?? 0}
|
||||
set {_transmittedPackets = newValue}
|
||||
}
|
||||
/// Returns true if `transmittedPackets` has been explicitly set.
|
||||
public var hasTransmittedPackets: Bool {return self._transmittedPackets != nil}
|
||||
/// Clears the value of `transmittedPackets`. Subsequent reads from it will return its default value.
|
||||
public mutating func clearTransmittedPackets() {self._transmittedPackets = nil}
|
||||
|
||||
public var receivedBytes: UInt64 {
|
||||
get {return _receivedBytes ?? 0}
|
||||
set {_receivedBytes = newValue}
|
||||
}
|
||||
/// Returns true if `receivedBytes` has been explicitly set.
|
||||
public var hasReceivedBytes: Bool {return self._receivedBytes != nil}
|
||||
/// Clears the value of `receivedBytes`. Subsequent reads from it will return its default value.
|
||||
public mutating func clearReceivedBytes() {self._receivedBytes = nil}
|
||||
|
||||
public var transmittedBytes: UInt64 {
|
||||
get {return _transmittedBytes ?? 0}
|
||||
set {_transmittedBytes = newValue}
|
||||
}
|
||||
/// Returns true if `transmittedBytes` has been explicitly set.
|
||||
public var hasTransmittedBytes: Bool {return self._transmittedBytes != nil}
|
||||
/// Clears the value of `transmittedBytes`. Subsequent reads from it will return its default value.
|
||||
public mutating func clearTransmittedBytes() {self._transmittedBytes = nil}
|
||||
|
||||
public var receivedErrors: UInt64 {
|
||||
get {return _receivedErrors ?? 0}
|
||||
set {_receivedErrors = newValue}
|
||||
}
|
||||
/// Returns true if `receivedErrors` has been explicitly set.
|
||||
public var hasReceivedErrors: Bool {return self._receivedErrors != nil}
|
||||
/// Clears the value of `receivedErrors`. Subsequent reads from it will return its default value.
|
||||
public mutating func clearReceivedErrors() {self._receivedErrors = nil}
|
||||
|
||||
public var transmittedErrors: UInt64 {
|
||||
get {return _transmittedErrors ?? 0}
|
||||
set {_transmittedErrors = newValue}
|
||||
}
|
||||
/// Returns true if `transmittedErrors` has been explicitly set.
|
||||
public var hasTransmittedErrors: Bool {return self._transmittedErrors != nil}
|
||||
/// Clears the value of `transmittedErrors`. Subsequent reads from it will return its default value.
|
||||
public mutating func clearTransmittedErrors() {self._transmittedErrors = nil}
|
||||
|
||||
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
public init() {}
|
||||
|
||||
fileprivate var _receivedPackets: UInt64? = nil
|
||||
fileprivate var _transmittedPackets: UInt64? = nil
|
||||
fileprivate var _receivedBytes: UInt64? = nil
|
||||
fileprivate var _transmittedBytes: UInt64? = nil
|
||||
fileprivate var _receivedErrors: UInt64? = nil
|
||||
fileprivate var _transmittedErrors: UInt64? = nil
|
||||
}
|
||||
|
||||
public struct Com_Apple_Containerization_Sandbox_V3_SyncRequest: Sendable {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
@@ -2781,6 +2864,104 @@ extension Com_Apple_Containerization_Sandbox_V3_ConfigureHostsResponse: SwiftPro
|
||||
}
|
||||
}
|
||||
|
||||
extension Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
public static let protoMessageName: String = _protobuf_package + ".InterfaceStatisticsRequest"
|
||||
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "interface"),
|
||||
]
|
||||
|
||||
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularStringField(value: &self.interface) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if !self.interface.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.interface, fieldNumber: 1)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest, rhs: Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest) -> Bool {
|
||||
if lhs.interface != rhs.interface {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
public static let protoMessageName: String = _protobuf_package + ".InterfaceStatisticsResponse"
|
||||
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "receivedPackets"),
|
||||
2: .same(proto: "transmittedPackets"),
|
||||
3: .same(proto: "receivedBytes"),
|
||||
4: .same(proto: "transmittedBytes"),
|
||||
5: .same(proto: "receivedErrors"),
|
||||
6: .same(proto: "transmittedErrors"),
|
||||
]
|
||||
|
||||
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularUInt64Field(value: &self._receivedPackets) }()
|
||||
case 2: try { try decoder.decodeSingularUInt64Field(value: &self._transmittedPackets) }()
|
||||
case 3: try { try decoder.decodeSingularUInt64Field(value: &self._receivedBytes) }()
|
||||
case 4: try { try decoder.decodeSingularUInt64Field(value: &self._transmittedBytes) }()
|
||||
case 5: try { try decoder.decodeSingularUInt64Field(value: &self._receivedErrors) }()
|
||||
case 6: try { try decoder.decodeSingularUInt64Field(value: &self._transmittedErrors) }()
|
||||
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
|
||||
try { if let v = self._receivedPackets {
|
||||
try visitor.visitSingularUInt64Field(value: v, fieldNumber: 1)
|
||||
} }()
|
||||
try { if let v = self._transmittedPackets {
|
||||
try visitor.visitSingularUInt64Field(value: v, fieldNumber: 2)
|
||||
} }()
|
||||
try { if let v = self._receivedBytes {
|
||||
try visitor.visitSingularUInt64Field(value: v, fieldNumber: 3)
|
||||
} }()
|
||||
try { if let v = self._transmittedBytes {
|
||||
try visitor.visitSingularUInt64Field(value: v, fieldNumber: 4)
|
||||
} }()
|
||||
try { if let v = self._receivedErrors {
|
||||
try visitor.visitSingularUInt64Field(value: v, fieldNumber: 5)
|
||||
} }()
|
||||
try { if let v = self._transmittedErrors {
|
||||
try visitor.visitSingularUInt64Field(value: v, fieldNumber: 6)
|
||||
} }()
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse, rhs: Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse) -> Bool {
|
||||
if lhs._receivedPackets != rhs._receivedPackets {return false}
|
||||
if lhs._transmittedPackets != rhs._transmittedPackets {return false}
|
||||
if lhs._receivedBytes != rhs._receivedBytes {return false}
|
||||
if lhs._transmittedBytes != rhs._transmittedBytes {return false}
|
||||
if lhs._receivedErrors != rhs._receivedErrors {return false}
|
||||
if lhs._transmittedErrors != rhs._transmittedErrors {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Com_Apple_Containerization_Sandbox_V3_SyncRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
public static let protoMessageName: String = _protobuf_package + ".SyncRequest"
|
||||
public static let _protobuf_nameMap = SwiftProtobuf._NameMap()
|
||||
|
||||
@@ -58,6 +58,9 @@ service SandboxContext {
|
||||
rpc ConfigureDns(ConfigureDnsRequest) returns (ConfigureDnsResponse);
|
||||
// Configure /etc/hosts.
|
||||
rpc ConfigureHosts(ConfigureHostsRequest) returns (ConfigureHostsResponse);
|
||||
// Get statistics about an interface.
|
||||
rpc InterfaceStatistics(InterfaceStatisticsRequest) returns (InterfaceStatisticsResponse);
|
||||
|
||||
// Perform the sync syscall.
|
||||
rpc Sync(SyncRequest) returns (SyncResponse);
|
||||
// Send a signal to a process via the PID.
|
||||
@@ -273,6 +276,19 @@ message ConfigureHostsRequest {
|
||||
|
||||
message ConfigureHostsResponse {}
|
||||
|
||||
message InterfaceStatisticsRequest {
|
||||
string interface = 1;
|
||||
}
|
||||
|
||||
message InterfaceStatisticsResponse {
|
||||
optional uint64 receivedPackets = 1;
|
||||
optional uint64 transmittedPackets = 2;
|
||||
optional uint64 receivedBytes = 3;
|
||||
optional uint64 transmittedBytes = 4;
|
||||
optional uint64 receivedErrors = 5;
|
||||
optional uint64 transmittedErrors = 6;
|
||||
}
|
||||
|
||||
message SyncRequest {}
|
||||
message SyncResponse {}
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ public protocol VirtualMachineAgent: Sendable {
|
||||
func routeAddDefault(name: String, gateway: String) async throws
|
||||
func configureDNS(config: DNS, location: String) async throws
|
||||
func configureHosts(config: Hosts, location: String) async throws
|
||||
func interfaceStatistics(name: String) async throws -> InterfaceStatistics
|
||||
}
|
||||
|
||||
extension VirtualMachineAgent {
|
||||
@@ -82,4 +83,8 @@ extension VirtualMachineAgent {
|
||||
public func writeFile(path: String, data: Data, flags: WriteFileFlags, mode: UInt32) async throws {
|
||||
throw ContainerizationError(.unsupported, message: "writeFile")
|
||||
}
|
||||
|
||||
public func interfaceStatistics(name: String) async throws -> InterfaceStatistics {
|
||||
throw ContainerizationError(.unsupported, message: "interfaceStatistics")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,23 @@ extension Vminitd: VirtualMachineAgent {
|
||||
})
|
||||
}
|
||||
|
||||
/// Get statistics about an interface.
|
||||
public func interfaceStatistics(name: String) async throws -> InterfaceStatistics {
|
||||
let stats = try await client.interfaceStatistics(
|
||||
.with {
|
||||
$0.interface = name
|
||||
})
|
||||
return InterfaceStatistics(
|
||||
name: name,
|
||||
receivedPackets: stats.hasReceivedPackets ? stats.receivedPackets : nil,
|
||||
transmittedPackets: stats.hasTransmittedPackets ? stats.transmittedPackets : nil,
|
||||
receivedBytes: stats.hasReceivedBytes ? stats.receivedBytes : nil,
|
||||
transmittedBytes: stats.hasTransmittedBytes ? stats.transmittedBytes : nil,
|
||||
receivedErrors: stats.hasReceivedErrors ? stats.receivedErrors : nil,
|
||||
transmittedErrors: stats.hasTransmittedErrors ? stats.transmittedErrors : nil
|
||||
)
|
||||
}
|
||||
|
||||
/// Mount a filesystem in the sandbox's environment.
|
||||
public func mount(_ mount: ContainerizationOCI.Mount) async throws {
|
||||
_ = try await client.mount(
|
||||
|
||||
@@ -121,7 +121,7 @@ public struct NetlinkSession {
|
||||
/// Performs a link get command on an interface.
|
||||
/// Returns information about the interface.
|
||||
/// - Parameter interface: The name of the interface to query.
|
||||
public func linkGet(interface: String? = nil) throws -> [LinkResponse] {
|
||||
public func linkGet(interface: String? = nil, includeStats: Bool = false) throws -> [LinkResponse] {
|
||||
// ip link ip show
|
||||
let maskAttr = RTAttribute(
|
||||
len: UInt16(RTAttribute.size + MemoryLayout<UInt32>.size), type: LinkAttributeType.IFLA_EXT_MASK)
|
||||
@@ -150,11 +150,16 @@ public struct NetlinkSession {
|
||||
change: InterfaceFlags.DEFAULT_CHANGE)
|
||||
requestOffset = try requestInfo.appendBuffer(&requestBuffer, offset: requestOffset)
|
||||
|
||||
var filters = LinkAttributeMaskFilter.RTEXT_FILTER_VF
|
||||
if !includeStats {
|
||||
filters |= LinkAttributeMaskFilter.RTEXT_FILTER_SKIP_STATS
|
||||
}
|
||||
|
||||
requestOffset = try maskAttr.appendBuffer(&requestBuffer, offset: requestOffset)
|
||||
guard
|
||||
var requestOffset = requestBuffer.copyIn(
|
||||
as: UInt32.self,
|
||||
value: LinkAttributeMaskFilter.RTEXT_FILTER_VF | LinkAttributeMaskFilter.RTEXT_FILTER_SKIP_STATS,
|
||||
value: filters,
|
||||
offset: requestOffset)
|
||||
else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
@@ -167,7 +172,6 @@ public struct NetlinkSession {
|
||||
else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
|
||||
requestOffset = updatedRequestOffset
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ struct InterfaceFlags {
|
||||
struct LinkAttributeType {
|
||||
static let IFLA_EXT_IFNAME: UInt16 = 3
|
||||
static let IFLA_MTU: UInt16 = 4
|
||||
static let IFLA_STATS64: UInt16 = 23
|
||||
static let IFLA_EXT_MASK: UInt16 = 29
|
||||
}
|
||||
|
||||
@@ -568,6 +569,267 @@ public struct RTAttributeData {
|
||||
public struct LinkResponse {
|
||||
public let interfaceIndex: Int32
|
||||
public let attrDatas: [RTAttributeData]
|
||||
|
||||
/// Extract network interface statistics from the response attributes
|
||||
public func getStatistics() throws -> LinkStatistics64? {
|
||||
for attrData in attrDatas {
|
||||
if attrData.attribute.type == LinkAttributeType.IFLA_STATS64 {
|
||||
var stats = LinkStatistics64()
|
||||
var buffer = attrData.data
|
||||
_ = try stats.bindBuffer(&buffer, offset: 0)
|
||||
return stats
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Network interface statistics (64-bit version)
|
||||
public struct LinkStatistics64: Bindable {
|
||||
static let size = 23 * 8
|
||||
|
||||
public var rxPackets: UInt64
|
||||
public var txPackets: UInt64
|
||||
public var rxBytes: UInt64
|
||||
public var txBytes: UInt64
|
||||
public var rxErrors: UInt64
|
||||
public var txErrors: UInt64
|
||||
public var rxDropped: UInt64
|
||||
public var txDropped: UInt64
|
||||
public var multicast: UInt64
|
||||
public var collisions: UInt64
|
||||
public var rxLengthErrors: UInt64
|
||||
public var rxOverErrors: UInt64
|
||||
public var rxCrcErrors: UInt64
|
||||
public var rxFrameErrors: UInt64
|
||||
public var rxFifoErrors: UInt64
|
||||
public var rxMissedErrors: UInt64
|
||||
public var txAbortedErrors: UInt64
|
||||
public var txCarrierErrors: UInt64
|
||||
public var txFifoErrors: UInt64
|
||||
public var txHeartbeatErrors: UInt64
|
||||
public var txWindowErrors: UInt64
|
||||
public var rxCompressed: UInt64
|
||||
public var txCompressed: UInt64
|
||||
|
||||
public init() {
|
||||
self.rxPackets = 0
|
||||
self.txPackets = 0
|
||||
self.rxBytes = 0
|
||||
self.txBytes = 0
|
||||
self.rxErrors = 0
|
||||
self.txErrors = 0
|
||||
self.rxDropped = 0
|
||||
self.txDropped = 0
|
||||
self.multicast = 0
|
||||
self.collisions = 0
|
||||
self.rxLengthErrors = 0
|
||||
self.rxOverErrors = 0
|
||||
self.rxCrcErrors = 0
|
||||
self.rxFrameErrors = 0
|
||||
self.rxFifoErrors = 0
|
||||
self.rxMissedErrors = 0
|
||||
self.txAbortedErrors = 0
|
||||
self.txCarrierErrors = 0
|
||||
self.txFifoErrors = 0
|
||||
self.txHeartbeatErrors = 0
|
||||
self.txWindowErrors = 0
|
||||
self.rxCompressed = 0
|
||||
self.txCompressed = 0
|
||||
}
|
||||
|
||||
func appendBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: rxPackets, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: txPackets, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: rxBytes, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: txBytes, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: rxErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: txErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: rxDropped, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: txDropped, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: multicast, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: collisions, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: rxLengthErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: rxOverErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: rxCrcErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: rxFrameErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: rxFifoErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: rxMissedErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: txAbortedErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: txCarrierErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: txFifoErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: txHeartbeatErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: txWindowErrors, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: rxCompressed, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
guard let offset = buffer.copyIn(as: UInt64.self, value: txCompressed, offset: offset) else {
|
||||
throw NetlinkDataError.sendMarshalFailure
|
||||
}
|
||||
|
||||
return offset
|
||||
}
|
||||
|
||||
mutating func bindBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
rxPackets = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
txPackets = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
rxBytes = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
txBytes = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
rxErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
txErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
rxDropped = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
txDropped = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
multicast = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
collisions = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
rxLengthErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
rxOverErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
rxCrcErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
rxFrameErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
rxFifoErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
rxMissedErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
txAbortedErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
txCarrierErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
txFifoErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
txHeartbeatErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
txWindowErrors = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
rxCompressed = value
|
||||
|
||||
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
||||
throw NetlinkDataError.recvUnmarshalFailure
|
||||
}
|
||||
txCompressed = value
|
||||
|
||||
return offset
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors thrown when parsing netlink data.
|
||||
|
||||
@@ -907,6 +907,47 @@ extension Initd: Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvid
|
||||
return .init()
|
||||
}
|
||||
|
||||
func interfaceStatistics(
|
||||
request: Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsRequest,
|
||||
context: GRPC.GRPCAsyncServerCallContext
|
||||
) async throws -> Com_Apple_Containerization_Sandbox_V3_InterfaceStatisticsResponse {
|
||||
log.debug(
|
||||
"interfaceStatistics",
|
||||
metadata: [
|
||||
"name": "\(request.interface)"
|
||||
])
|
||||
|
||||
do {
|
||||
let socket = try DefaultNetlinkSocket()
|
||||
let session = NetlinkSession(socket: socket, log: log)
|
||||
let responses = try session.linkGet(interface: request.interface, includeStats: true)
|
||||
guard responses.count == 1 else {
|
||||
throw ContainerizationError(
|
||||
.internalError,
|
||||
message: "linkGet returned invalid number of interfaces: \(responses.count)"
|
||||
)
|
||||
}
|
||||
let stats = try responses[0].getStatistics()
|
||||
return .with {
|
||||
if let stats {
|
||||
$0.receivedPackets = stats.rxPackets
|
||||
$0.transmittedPackets = stats.txPackets
|
||||
$0.receivedBytes = stats.rxBytes
|
||||
$0.transmittedBytes = stats.txBytes
|
||||
$0.receivedErrors = stats.rxErrors
|
||||
$0.transmittedErrors = stats.txErrors
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
log.error(
|
||||
"interfaceStatistics",
|
||||
metadata: [
|
||||
"error": "\(error)"
|
||||
])
|
||||
throw GRPCStatus(code: .internalError, message: "interfaceStatistics: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
private func swiftErrno(_ msg: Logger.Message) -> POSIXError {
|
||||
let error = POSIXError(.init(rawValue: errno)!)
|
||||
log.error(
|
||||
|
||||
Reference in New Issue
Block a user