mirror of
https://github.com/apple/container.git
synced 2026-09-13 11:15:41 +00:00
- Bindable is generally useful, so it makes sense to move it out of the netlink library. Removed Equatable conformance from Bindable as this isn't generally necessary (it's only used for unit tests in netlink). - Fix some offset checks in a couple data binding functions and improve the unit tests.
879 lines
34 KiB
Swift
879 lines
34 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
// Copyright © 2025-2026 Apple Inc. and the Containerization project authors.
|
|
//
|
|
// 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.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import ContainerizationExtras
|
|
import Foundation
|
|
|
|
struct SocketType {
|
|
static let SOCK_RAW: Int32 = 3
|
|
}
|
|
|
|
struct AddressFamily {
|
|
static let AF_UNSPEC: UInt16 = 0
|
|
static let AF_INET: UInt16 = 2
|
|
static let AF_INET6: UInt16 = 10
|
|
static let AF_NETLINK: UInt16 = 16
|
|
static let AF_PACKET: UInt16 = 17
|
|
}
|
|
|
|
struct ArpHardware {
|
|
static let ARPHRD_ETHER: UInt16 = 1
|
|
}
|
|
|
|
struct NetlinkProtocol {
|
|
static let NETLINK_ROUTE: Int32 = 0
|
|
}
|
|
|
|
struct NetlinkType {
|
|
static let NLMSG_NOOP: UInt16 = 1
|
|
static let NLMSG_ERROR: UInt16 = 2
|
|
static let NLMSG_DONE: UInt16 = 3
|
|
static let NLMSG_OVERRUN: UInt16 = 4
|
|
static let RTM_NEWLINK: UInt16 = 16
|
|
static let RTM_DELLINK: UInt16 = 17
|
|
static let RTM_GETLINK: UInt16 = 18
|
|
static let RTM_NEWADDR: UInt16 = 20
|
|
static let RTM_NEWROUTE: UInt16 = 24
|
|
}
|
|
|
|
struct NetlinkFlags {
|
|
static let NLM_F_REQUEST: UInt16 = 0x01
|
|
static let NLM_F_MULTI: UInt16 = 0x02
|
|
static let NLM_F_ACK: UInt16 = 0x04
|
|
static let NLM_F_ECHO: UInt16 = 0x08
|
|
static let NLM_F_DUMP_INTR: UInt16 = 0x10
|
|
static let NLM_F_DUMP_FILTERED: UInt16 = 0x20
|
|
|
|
// GET request
|
|
static let NLM_F_ROOT: UInt16 = 0x100
|
|
static let NLM_F_MATCH: UInt16 = 0x200
|
|
static let NLM_F_ATOMIC: UInt16 = 0x400
|
|
static let NLM_F_DUMP: UInt16 = NetlinkFlags.NLM_F_ROOT | NetlinkFlags.NLM_F_MATCH
|
|
|
|
// NEW request flags
|
|
static let NLM_F_REPLACE: UInt16 = 0x100
|
|
static let NLM_F_EXCL: UInt16 = 0x200
|
|
static let NLM_F_CREATE: UInt16 = 0x400
|
|
static let NLM_F_APPEND: UInt16 = 0x800
|
|
}
|
|
|
|
struct NetlinkScope {
|
|
static let RT_SCOPE_UNIVERSE: UInt8 = 0
|
|
}
|
|
|
|
struct InterfaceFlags {
|
|
static let IFF_UP: UInt32 = 1 << 0
|
|
static let IFF_LOOPBACK: UInt32 = 1 << 3
|
|
static let IFF_POINTOPOINT: UInt32 = 1 << 4
|
|
static let DEFAULT_CHANGE: UInt32 = 0xffff_ffff
|
|
}
|
|
|
|
struct LinkAttributeType {
|
|
static let IFLA_ADDRESS: UInt16 = 1
|
|
static let IFLA_BROADCAST: UInt16 = 2
|
|
static let IFLA_IFNAME: UInt16 = 3
|
|
static let IFLA_MTU: UInt16 = 4
|
|
static let IFLA_STATS64: UInt16 = 23
|
|
static let IFLA_EXT_MASK: UInt16 = 29
|
|
}
|
|
|
|
struct LinkAttributeMaskFilter {
|
|
static let RTEXT_FILTER_VF: UInt32 = 1 << 0
|
|
static let RTEXT_FILTER_SKIP_STATS: UInt32 = 1 << 3
|
|
}
|
|
|
|
struct AddressAttributeType {
|
|
// subnet mask
|
|
static let IFA_ADDRESS: UInt16 = 1
|
|
// IPv4 address
|
|
static let IFA_LOCAL: UInt16 = 2
|
|
}
|
|
|
|
struct RouteTable {
|
|
static let MAIN: UInt8 = 254
|
|
}
|
|
|
|
struct RouteProtocol {
|
|
static let UNSPEC: UInt8 = 0
|
|
static let REDIRECT: UInt8 = 1
|
|
static let KERNEL: UInt8 = 2
|
|
static let BOOT: UInt8 = 3
|
|
static let STATIC: UInt8 = 4
|
|
}
|
|
|
|
struct RouteScope {
|
|
static let UNIVERSE: UInt8 = 0
|
|
static let LINK: UInt8 = 253
|
|
}
|
|
|
|
struct RouteType {
|
|
static let UNSPEC: UInt8 = 0
|
|
static let UNICAST: UInt8 = 1
|
|
}
|
|
|
|
struct RouteAttributeType {
|
|
static let UNSPEC: UInt16 = 0
|
|
static let DST: UInt16 = 1
|
|
static let SRC: UInt16 = 2
|
|
static let IIF: UInt16 = 3
|
|
static let OIF: UInt16 = 4
|
|
static let GATEWAY: UInt16 = 5
|
|
static let PRIORITY: UInt16 = 6
|
|
static let PREFSRC: UInt16 = 7
|
|
}
|
|
|
|
struct SockaddrNetlink: Bindable, Equatable {
|
|
static let size = 12
|
|
|
|
var family: UInt16
|
|
var _pad: UInt16 = 0
|
|
var pid: UInt32
|
|
var groups: UInt32
|
|
|
|
init(family: UInt16 = 0, pid: UInt32 = 0, groups: UInt32 = 0) {
|
|
self.family = family
|
|
self.pid = pid
|
|
self.groups = groups
|
|
}
|
|
|
|
func appendBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let offset = buffer.copyIn(as: UInt16.self, value: family, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "SockaddrNetlink", field: "family")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt16.self, value: 0, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "SockaddrNetlink", field: "_pad")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt32.self, value: pid, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "SockaddrNetlink", field: "pid")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt32.self, value: groups, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "SockaddrNetlink", field: "groups")
|
|
}
|
|
|
|
return offset
|
|
}
|
|
|
|
mutating func bindBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let (offset, value) = buffer.copyOut(as: UInt16.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "SockaddrNetlink", field: "family")
|
|
}
|
|
family = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt16.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "SockaddrNetlink", field: "_pad")
|
|
}
|
|
_pad = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt32.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "SockaddrNetlink", field: "pid")
|
|
}
|
|
pid = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt32.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "SockaddrNetlink", field: "groups")
|
|
}
|
|
groups = value
|
|
|
|
return offset
|
|
}
|
|
}
|
|
|
|
struct NetlinkMessageHeader: Bindable, Equatable {
|
|
static let size = 16
|
|
|
|
var len: UInt32
|
|
var type: UInt16
|
|
var flags: UInt16
|
|
var seq: UInt32
|
|
var pid: UInt32
|
|
|
|
init(len: UInt32 = 0, type: UInt16 = 0, flags: UInt16 = 0, seq: UInt32? = nil, pid: UInt32 = 0) {
|
|
self.len = len
|
|
self.type = type
|
|
self.flags = flags
|
|
self.seq = seq ?? UInt32.random(in: 0..<UInt32.max)
|
|
self.pid = pid
|
|
}
|
|
|
|
func appendBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let offset = buffer.copyIn(as: UInt32.self, value: len, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "NetlinkMessageHeader", field: "len")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt16.self, value: type, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "NetlinkMessageHeader", field: "type")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt16.self, value: flags, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "NetlinkMessageHeader", field: "flags")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt32.self, value: seq, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "NetlinkMessageHeader", field: "seq")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt32.self, value: pid, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "NetlinkMessageHeader", field: "pid")
|
|
}
|
|
|
|
return offset
|
|
}
|
|
|
|
mutating func bindBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let (offset, value) = buffer.copyOut(as: UInt32.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "NetlinkMessageHeader", field: "len")
|
|
}
|
|
len = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt16.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "NetlinkMessageHeader", field: "type")
|
|
}
|
|
type = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt16.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "NetlinkMessageHeader", field: "flags")
|
|
}
|
|
flags = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt32.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "NetlinkMessageHeader", field: "seq")
|
|
}
|
|
seq = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt32.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "NetlinkMessageHeader", field: "pid")
|
|
}
|
|
pid = value
|
|
|
|
return offset
|
|
}
|
|
|
|
var moreResponses: Bool {
|
|
(self.flags & NetlinkFlags.NLM_F_MULTI) != 0
|
|
&& (self.type != NetlinkType.NLMSG_DONE && self.type != NetlinkType.NLMSG_ERROR
|
|
&& self.type != NetlinkType.NLMSG_OVERRUN)
|
|
}
|
|
}
|
|
|
|
struct InterfaceInfo: Bindable, Equatable {
|
|
static let size = 16
|
|
|
|
var family: UInt8
|
|
var _pad: UInt8 = 0
|
|
var type: UInt16
|
|
var index: Int32
|
|
var flags: UInt32
|
|
var change: UInt32
|
|
|
|
init(
|
|
family: UInt8 = UInt8(AddressFamily.AF_UNSPEC), type: UInt16 = 0, index: Int32 = 0, flags: UInt32 = 0,
|
|
change: UInt32 = 0
|
|
) {
|
|
self.family = family
|
|
self.type = type
|
|
self.index = index
|
|
self.flags = flags
|
|
self.change = change
|
|
}
|
|
|
|
func appendBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: family, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "InterfaceInfo", field: "family")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: _pad, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "InterfaceInfo", field: "_pad")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt16.self, value: type, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "InterfaceInfo", field: "type")
|
|
}
|
|
guard let offset = buffer.copyIn(as: Int32.self, value: index, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "InterfaceInfo", field: "index")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt32.self, value: flags, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "InterfaceInfo", field: "flags")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt32.self, value: change, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "InterfaceInfo", field: "change")
|
|
}
|
|
|
|
return offset
|
|
}
|
|
|
|
mutating func bindBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "InterfaceInfo", field: "family")
|
|
}
|
|
family = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "InterfaceInfo", field: "_pad")
|
|
}
|
|
_pad = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt16.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "InterfaceInfo", field: "type")
|
|
}
|
|
type = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: Int32.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "InterfaceInfo", field: "index")
|
|
}
|
|
index = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt32.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "InterfaceInfo", field: "flags")
|
|
}
|
|
flags = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt32.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "InterfaceInfo", field: "change")
|
|
}
|
|
change = value
|
|
|
|
return offset
|
|
}
|
|
}
|
|
|
|
struct AddressInfo: Bindable, Equatable {
|
|
static let size = 8
|
|
|
|
var family: UInt8
|
|
var prefixLength: UInt8
|
|
var flags: UInt8
|
|
var scope: UInt8
|
|
var index: UInt32
|
|
|
|
init(
|
|
family: UInt8 = UInt8(AddressFamily.AF_UNSPEC), prefixLength: UInt8 = 32, flags: UInt8 = 0, scope: UInt8 = 0,
|
|
index: UInt32 = 0
|
|
) {
|
|
self.family = family
|
|
self.prefixLength = prefixLength
|
|
self.flags = flags
|
|
self.scope = scope
|
|
self.index = index
|
|
}
|
|
|
|
func appendBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: family, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "AddressInfo", field: "family")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: prefixLength, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "AddressInfo", field: "prefixLength")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: flags, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "AddressInfo", field: "flags")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: scope, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "AddressInfo", field: "scope")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt32.self, value: index, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "AddressInfo", field: "index")
|
|
}
|
|
|
|
return offset
|
|
}
|
|
|
|
mutating func bindBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "AddressInfo", field: "family")
|
|
}
|
|
family = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "AddressInfo", field: "prefixLength")
|
|
}
|
|
prefixLength = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "AddressInfo", field: "flags")
|
|
}
|
|
flags = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "AddressInfo", field: "scope")
|
|
}
|
|
scope = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt32.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "AddressInfo", field: "index")
|
|
}
|
|
index = value
|
|
|
|
return offset
|
|
}
|
|
}
|
|
|
|
struct RouteInfo: Bindable, Equatable {
|
|
static let size = 12
|
|
|
|
var family: UInt8
|
|
var dstLen: UInt8
|
|
var srcLen: UInt8
|
|
var tos: UInt8
|
|
var table: UInt8
|
|
var proto: UInt8
|
|
var scope: UInt8
|
|
var type: UInt8
|
|
var flags: UInt32
|
|
|
|
init(
|
|
family: UInt8 = UInt8(AddressFamily.AF_INET),
|
|
dstLen: UInt8,
|
|
srcLen: UInt8,
|
|
tos: UInt8,
|
|
table: UInt8,
|
|
proto: UInt8,
|
|
scope: UInt8,
|
|
type: UInt8,
|
|
flags: UInt32
|
|
) {
|
|
self.family = family
|
|
self.dstLen = dstLen
|
|
self.srcLen = srcLen
|
|
self.tos = tos
|
|
self.table = table
|
|
self.proto = proto
|
|
self.scope = scope
|
|
self.type = type
|
|
self.flags = flags
|
|
}
|
|
|
|
func appendBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: family, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "RouteInfo", field: "family")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: dstLen, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "RouteInfo", field: "dstLen")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: srcLen, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "RouteInfo", field: "srcLen")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: tos, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "RouteInfo", field: "tos")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: table, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "RouteInfo", field: "table")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: proto, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "RouteInfo", field: "proto")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: scope, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "RouteInfo", field: "scope")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt8.self, value: type, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "RouteInfo", field: "type")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt32.self, value: flags, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "RouteInfo", field: "flags")
|
|
}
|
|
|
|
return offset
|
|
}
|
|
|
|
mutating func bindBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "RouteInfo", field: "family")
|
|
}
|
|
family = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "RouteInfo", field: "dstLen")
|
|
}
|
|
dstLen = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "RouteInfo", field: "srcLen")
|
|
}
|
|
srcLen = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "RouteInfo", field: "tos")
|
|
}
|
|
tos = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "RouteInfo", field: "table")
|
|
}
|
|
table = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "RouteInfo", field: "proto")
|
|
}
|
|
proto = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "RouteInfo", field: "scope")
|
|
}
|
|
scope = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt8.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "RouteInfo", field: "type")
|
|
}
|
|
type = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt32.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "RouteInfo", field: "flags")
|
|
}
|
|
flags = value
|
|
|
|
return offset
|
|
}
|
|
}
|
|
|
|
/// A route information.
|
|
public struct RTAttribute: Bindable, Equatable {
|
|
package static let size = 4
|
|
|
|
public var len: UInt16
|
|
public var type: UInt16
|
|
public var paddedLen: Int { Int(((len + 3) >> 2) << 2) }
|
|
|
|
init(len: UInt16 = 0, type: UInt16 = 0) {
|
|
self.len = len
|
|
self.type = type
|
|
}
|
|
|
|
package func appendBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let offset = buffer.copyIn(as: UInt16.self, value: len, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "RTAttribute", field: "len")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt16.self, value: type, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "RTAttribute", field: "type")
|
|
}
|
|
|
|
return offset
|
|
}
|
|
|
|
package mutating func bindBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let (offset, value) = buffer.copyOut(as: UInt16.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "RTAttribute", field: "len")
|
|
}
|
|
len = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt16.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "RTAttribute", field: "type")
|
|
}
|
|
type = value
|
|
|
|
return offset
|
|
}
|
|
}
|
|
|
|
/// A route information with data.
|
|
public struct RTAttributeData {
|
|
public let attribute: RTAttribute
|
|
public let data: [UInt8]
|
|
}
|
|
|
|
/// A response from the get link command.
|
|
public struct LinkResponse {
|
|
public let interfaceIndex: Int32
|
|
public let interfaceFlags: UInt32
|
|
public let interfaceType: UInt16
|
|
public let attrDatas: [RTAttributeData]
|
|
|
|
public var isLoopback: Bool {
|
|
(interfaceFlags & InterfaceFlags.IFF_LOOPBACK) != 0
|
|
}
|
|
|
|
public var isEthernet: Bool {
|
|
interfaceType == ArpHardware.ARPHRD_ETHER
|
|
&& (interfaceFlags & (InterfaceFlags.IFF_LOOPBACK | InterfaceFlags.IFF_POINTOPOINT)) == 0
|
|
}
|
|
|
|
public var address: [UInt8]? {
|
|
attrDatas
|
|
.filter { $0.attribute.type == LinkAttributeType.IFLA_ADDRESS }
|
|
.first
|
|
.map { $0.data }
|
|
}
|
|
|
|
/// 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, Equatable {
|
|
package 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
|
|
}
|
|
|
|
package func appendBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: rxPackets, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "rxPackets")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: txPackets, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "txPackets")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: rxBytes, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "rxBytes")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: txBytes, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "txBytes")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: rxErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "rxErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: txErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "txErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: rxDropped, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "rxDropped")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: txDropped, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "txDropped")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: multicast, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "multicast")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: collisions, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "collisions")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: rxLengthErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "rxLengthErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: rxOverErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "rxOverErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: rxCrcErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "rxCrcErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: rxFrameErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "rxFrameErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: rxFifoErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "rxFifoErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: rxMissedErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "rxMissedErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: txAbortedErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "txAbortedErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: txCarrierErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "txCarrierErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: txFifoErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "txFifoErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: txHeartbeatErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "txHeartbeatErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: txWindowErrors, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "txWindowErrors")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: rxCompressed, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "rxCompressed")
|
|
}
|
|
guard let offset = buffer.copyIn(as: UInt64.self, value: txCompressed, offset: offset) else {
|
|
throw BindError.sendMarshalFailure(type: "LinkStatistics64", field: "txCompressed")
|
|
}
|
|
|
|
return offset
|
|
}
|
|
|
|
package mutating func bindBuffer(_ buffer: inout [UInt8], offset: Int) throws -> Int {
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "rxPackets")
|
|
}
|
|
rxPackets = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "txPackets")
|
|
}
|
|
txPackets = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "rxBytes")
|
|
}
|
|
rxBytes = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "txBytes")
|
|
}
|
|
txBytes = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "rxErrors")
|
|
}
|
|
rxErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "txErrors")
|
|
}
|
|
txErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "rxDropped")
|
|
}
|
|
rxDropped = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "txDropped")
|
|
}
|
|
txDropped = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "multicast")
|
|
}
|
|
multicast = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "collisions")
|
|
}
|
|
collisions = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "rxLengthErrors")
|
|
}
|
|
rxLengthErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "rxOverErrors")
|
|
}
|
|
rxOverErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "rxCrcErrors")
|
|
}
|
|
rxCrcErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "rxFrameErrors")
|
|
}
|
|
rxFrameErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "rxFifoErrors")
|
|
}
|
|
rxFifoErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "rxMissedErrors")
|
|
}
|
|
rxMissedErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "txAbortedErrors")
|
|
}
|
|
txAbortedErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "txCarrierErrors")
|
|
}
|
|
txCarrierErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "txFifoErrors")
|
|
}
|
|
txFifoErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "txHeartbeatErrors")
|
|
}
|
|
txHeartbeatErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "txWindowErrors")
|
|
}
|
|
txWindowErrors = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "rxCompressed")
|
|
}
|
|
rxCompressed = value
|
|
|
|
guard let (offset, value) = buffer.copyOut(as: UInt64.self, offset: offset) else {
|
|
throw BindError.recvMarshalFailure(type: "LinkStatistics64", field: "txCompressed")
|
|
}
|
|
txCompressed = value
|
|
|
|
return offset
|
|
}
|
|
}
|
|
|
|
/// Errors thrown when parsing netlink data.
|
|
public enum NetlinkDataError: Swift.Error, CustomStringConvertible, Equatable {
|
|
case responseError(rc: Int32)
|
|
case unsupportedPlatform
|
|
|
|
/// The description of the errors.
|
|
public var description: String {
|
|
switch self {
|
|
case .responseError(let rc):
|
|
return "netlink response indicates error, rc = \(rc)"
|
|
case .unsupportedPlatform:
|
|
return "unsupported platform"
|
|
}
|
|
}
|
|
}
|