blob: f869e35354922b0ed86580f3c7bca074ba48f91b [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library fuchsia.net.tun;
using zx;
using fuchsia.hardware.network;
using fuchsia.net;
/// Maximum number of multicast filters that a device will hold in `MacState`.
// NOTE: this number mirrors the number in the low level banjo definition in
// [`fuchsia.hardware.network.mac/MAX_MAC_FILTER`] which was chosen, in turn, based on common maximum
// number of multicast groups supported in established OSes.
const uint32 MAX_MULTICAST_FILTERS = 64;
/// Maximum number of pending [`fuchsia.net.tun/Device.WriteFrame`] or
/// [`fuchsia.net.tun/Device.ReadFrame`] that are allowed.
// NOTE: This number is chosen arbitrarily to maintain a determined upper bound on memory
// consumption for a `Device` instance.
const uint32 MAX_PENDING_OPERATIONS = 32;
/// Signals set in the `eventpair` returned by [`fuchsia.net.tun/Device.GetSignals`].
bits Signals : uint32 {
/// Indicates that write buffers are available to be used through
/// [`fuchsia.net.tun/Device.WriteFrame`].
WRITABLE = 0x01000000; // ZX_USER_SIGNAL_0
/// Indicates that read buffers are available to be used through
/// [`fuchsia.net.tun/Device.ReadFrame`].
READABLE = 0x02000000; // ZX_USER_SIGNAL_1
};
/// Maximum supported MTU.
// NOTE: Selected as the smallest power of 2 that will fit conventional jumbo frame sizes of 9KB.
// Source: https://en.wikipedia.org/wiki/Jumbo_frame. The value is chosen arbitrarily low (while
// abiding by the conventional jumbo frame sizes) to encourage sensible memory usage for clients of
// the NetworkDevice interface, as receive buffers must be at least MTU-sized for valid operation.
const uint32 MAX_MTU = 16384;
/// Common configuration used to create a `Device` or `DevicePair`.
table BaseConfig {
/// Device MTU (maximum transmit unit).
///
/// If a value greater than `MAX_MTU` is provided, creating a device will fail.
/// Defaults to `MAX_MTU`.
1: uint32 mtu;
/// Supported Rx frame types for device. Required.
///
/// Must be non-empty, otherwise creating the device will fail.
2: vector<fuchsia.hardware.network.FrameType>:fuchsia.hardware.network.MAX_FRAME_TYPES rx_types;
/// Supported Tx frame types on device. Required.
///
/// Must be non-empty, otherwise creating the device will fail.
3: vector<fuchsia.hardware.network.FrameTypeSupport>:fuchsia.hardware.network.MAX_FRAME_TYPES tx_types;
/// Report frame metadata on receiving frames. Defaults to `false`.
4: bool report_metadata;
/// Minimum requested TX buffer length, in bytes. Defaults to zero.
5: uint32 min_tx_buffer_length;
};
/// Configuration used to create a [`fuchsia.net.tun/Device`].
table DeviceConfig {
/// Common configuration. Required.
1: BaseConfig base;
/// Start device with link online. Defaults to `false`.
2: bool online;
/// If `true`, [`fuchsia.net.tun/Device.WriteFrame`] and [`fuchsia.net.tun/Device.ReadFrame`]
/// will block returning until the corresponding buffers are available to complete the call.
/// Defaults to `false`.
3: bool blocking;
/// MAC address to report. If provided, device will support the
/// [`fuchsia.hardware.network/MacAddressing`] protocol through `ConnectProtocols`.
4: fuchsia.net.MacAddress mac;
};
/// Configuration used to create a [`fuchsia.net.tun/DevicePair`].
table DevicePairConfig {
/// Common configuration. Required.
1: BaseConfig base;
/// If `true`, transmit buffers on the left end will be dropped if no receive buffers are
/// available on the right end to receive it. Otherwise, transmit buffers will wait until a
/// receive buffer is available to copy them to. Defaults to `false`.
2: bool fallible_transmit_left;
/// Like `fallible_transmit_left` but allows writes to the right end to be fallible.
3: bool fallible_transmit_right;
/// MAC address to report on the left side of the pair. If provided, the left device will
/// support the [`fuchsia.hardware.network/MacAddressing`] protocol through `ConnectProtocols`.
4: fuchsia.net.MacAddress mac_left;
/// Same as `mac_left`, but for the right side of the pair.
5: fuchsia.net.MacAddress mac_right;
};
/// State associated with Mac Address filtering.
///
/// Devices never perform any MAC address filtering, but they implement the
/// [`fuchsia.hardware.network/MacAddressing`] interface and store the values to be retrieved
/// through the [`fuchsia.net.tun/InternalState`] structure.
table MacState {
/// The currently configured MAC Address filtering mode.
1: fuchsia.hardware.network.MacFilterMode mode;
/// The full list of configured multicast address filtering.
2: vector<fuchsia.net.MacAddress>:MAX_MULTICAST_FILTERS multicast_filters;
};
/// Internal device state.
table InternalState {
/// Mac addressing state. Will only be provided if `mac` is provided in the `Config`
/// structure upon creation of the device.
1: MacState mac;
/// `true` if there is a session currently opened and running with the `Device`'s network device
/// endpoint.
2: bool has_session;
};
/// Extra frame metadata.
///
/// This is an opaque holder for extra information that is associated with Network Device data
/// frames.
// NOTE(brunodalbo): NetworkDevice's `InfoType` definition is still in its infancy. This solution
// allows access to the raw bytes in the sidecar metadata. We expect that this will envolve into a
// more type-safe solution which will be more transparent.
struct FrameMetadata {
/// Additional frame information type.
fuchsia.hardware.network.InfoType info_type;
/// Additional frame information value.
bytes:4096 info;
/// Frame flags. `RxFlags` for `WriteFrame` and `TxFlags` for `ReadFrame`.
uint32 flags;
};
/// Collection of request protocols that tun devices can offer.
resource table Protocols {
/// Connection request to the [`fuchsia.hardware.network/Device`] protocol.
///
/// The request is always fulfilled.
1: request<fuchsia.hardware.network.Device> network_device;
/// Connection request to the [`fuchsia.hardware.network/MacAddressing`] protocol.
///
/// The request will be immediately closed if the device was not created with a MAC address.
2: request<fuchsia.hardware.network.MacAddressing> mac_addressing;
};
/// A frame written to or read from a [`fuchsia.net.tun/Device`].
///
/// Required fields must always be provided to [`fuchsia.net.tun/Device.WriteFrame`] and are always
/// present when returned by [`fuchsia.net.tun/Device.ReadFrame`].
table Frame {
/// The type identifying this frame's payload. Required.
1: fuchsia.hardware.network.FrameType frame_type;
/// The frame's payload. Required. Must be non-empty.
2: bytes:MAX_MTU data;
/// Metadata associated with the frame.
3: FrameMetadata meta;
};
/// Provides control over the created device.
///
/// The lifetime of the device is tied to the channel over which this protocol is served; closing a
/// `Device` channel will trigger the destruction and deallocation of the underlying device, as well
/// as all associated endpoints.
protocol Device {
/// Writes a frame to the device (data coming from network-end).
/// Returns `ZX_ERR_BAD_STATE` if the device is offline.
///
/// If the device was created with the [`fuchsia.net.tun/DeviceConfig.blocking`] option set to
/// `true`, calls to `WriteFrame` will block until there is one buffer available to fulfill the
/// request. Up to [`fuchsia.net.tun/MAX_PENDING_OPERATIONS`] calls to `WriteFrame` may be
/// enqueued in such a way, after which `ZX_ERR_NO_RESOURCES` is returned.
///
/// Alternatively, if `blocking` is set to `false` calls to `WriteFrame` will return
/// `ZX_ERR_SHOULD_WAIT` if there are no buffers available to fulfill the request.
WriteFrame(Frame frame) -> () error zx.status;
/// Gets the next frame from the device (data coming from host-end).
///
/// If the device was created with the [`fuchsia.net.tun/DeviceConfig.blocking`] option set to
/// `true`, calls to `ReadFrame` will block until there is a frame available to be read. Up to
/// [`fuchsia.net.tun/MAX_PENDING_OPERATIONS`] calls to `ReadFrame` may be enqueued in such a
/// way, after which `ZX_ERR_NO_RESOURCES` is returned.
///
/// Alternatively, if `blocking` is set to `false` calls to `ReadFrame` will return
/// `ZX_ERR_SHOULD_WAIT` if there are no frames to be read.
ReadFrame() -> (Frame frame) error zx.status;
/// Retrieves an eventpair that is signalled with `SIGNAL_READABLE` and `SIGNAL_WRITABLE` when
/// read and write buffers are available, respectively.
GetSignals() -> (zx.handle:EVENTPAIR signals);
/// Gets a snapshot of the device's internal state.
GetState() -> (InternalState state);
/// Observes changes to internal state.
///
/// The first call will always return the current internal state, subsequent calls will block
/// until the internal state differs from the last one returned from a `WatchState` call.
///
/// `WatchState` does not provide full history of internal state changes. It is possible that
/// intermediary internal state changes are missed in between `WatchState` calls.
WatchState() -> (InternalState state);
/// Sets the device's online status.
///
/// The online status is visible through [`fuchsia.hardware.network/Device.GetStatus`]. Once
/// `SetOnline` returns, the status reported through `GetStatus` is guaranteed to be the one
/// passed to `SetOnline`, no guarantees can be made otherwise due to the asynchronous nature of
/// multi-channel operations.
SetOnline(bool online) -> ();
/// Connects to the requested protocols for this `Device`.
ConnectProtocols(Protocols protos);
};
/// A collection of connection requests to ends of a [`fuchsia.net.tun/DevicePair`].
///
/// Used to connect to a `DevicePair` through [`fuchsia.net.tun/DevicePair.ConnectProtocols`].
resource table DevicePairEnds {
/// Connection request to protocols on the left end.
1: Protocols left;
/// Connection request to protocols on the right end.
2: Protocols right;
};
/// Provides control over a pair of network devices.
///
/// A `DevicePair` is a simpler version of `Device` that "shorts" two network device interfaces,
/// named its "left" and "right" ends. The internal state of a `DevicePair` is not accessible, like
/// it is for `Device` and it provides a more streamlined (and considerably faster) pair of
/// [`fuchsia.hardware.network/Device`]s (and optionally
/// [`fuchsia.hardware.network/MacAddressing`]s). The transmit side of the left end is connected to
/// the receive side of the right end, and vice-versa. A `DevicePair`'s online signal is handled
/// internally (online if any of the ends has an active data session), and if MAC addresses are
/// provided on creation, the only supported MAC filtering mode is `PROMISCUOUS`. The lifetime of
/// the underlying devices is tied to the `DevicePair` channel, closing a `DevicePair` channel will
/// trigger the destruction and deallocation of the underlying devices.
protocol DevicePair {
/// Connects to the requested protocols of this `DevicePair`.
ConnectProtocols(DevicePairEnds requests);
};
/// Control interface.
/// `Control` allows creating an arbitrary number of `Device`s and `DevicePair`s.
[Discoverable]
protocol Control {
/// Creates a `Device` with given `config`.
/// If `config` is not valid or the device could not be created, `device` is closed with an
/// error epitaph.
CreateDevice(DeviceConfig config, request<Device> device);
/// Creates a `DevicePair` with given `config`.
/// If `config` is not valid or the device could not be created, `device_pair` is closed
/// with an error epitaph.
CreatePair(DevicePairConfig config, request<DevicePair> device_pair);
};