Skip to main content

DeviceImpl

Struct DeviceImpl 

Source
pub struct DeviceImpl { /* private fields */ }
Expand description

A TUN device using the TUN/TAP Linux driver.

Implementations§

Source§

impl DeviceImpl

Source

pub fn if_index(&self) -> Result<u32>

Available on Unix and (Linux and non-target_env=ohos, or macOS, or FreeBSD, or OpenBSD, or NetBSD) only.

Retrieves the interface index for the network interface.

This function converts the interface name (obtained via self.name()) into a C-compatible string (CString) and then calls the libc function if_nametoindex to retrieve the corresponding interface index.

Source

pub fn addresses(&self) -> Result<Vec<IpAddr>>

Available on Unix and (Linux and non-target_env=ohos, or macOS, or FreeBSD, or OpenBSD, or NetBSD) only.

Retrieves all IP addresses associated with the network interface.

This function calls getifaddrs with the interface name, then iterates over the returned list of interface addresses, extracting and collecting the IP addresses into a vector.

Source§

impl DeviceImpl

Source

pub fn udp_gso(&self) -> bool

Available on Linux and non-target_env=ohos only.

Returns whether UDP Generic Segmentation Offload (GSO) is enabled.

This is determined by the udp_gso flag in the device.

Source

pub fn tcp_gso(&self) -> bool

Available on Linux and non-target_env=ohos only.

Returns whether TCP Generic Segmentation Offload (GSO) is enabled.

In this implementation, this is represented by the vnet_hdr flag.

Source

pub fn set_tx_queue_len(&self, tx_queue_len: u32) -> Result<()>

Available on Linux and non-target_env=ohos only.

Sets the transmit queue length for the network interface.

This method constructs an interface request (ifreq) structure, assigns the desired transmit queue length to the ifru_metric field, and calls the change_tx_queue_len function using the control file descriptor. If the underlying operation fails, an I/O error is returned.

Source

pub fn tx_queue_len(&self) -> Result<u32>

Available on Linux and non-target_env=ohos only.

Retrieves the current transmit queue length for the network interface.

This function constructs an interface request structure and calls tx_queue_len to populate it with the current transmit queue length. The value is then returned.

Source

pub fn persist(&self) -> Result<()>

Available on Linux and non-target_env=ohos only.

Make the device persistent.

By default, TUN/TAP devices are destroyed when the process exits. Calling this method makes the device persist after the program terminates, allowing it to be reused by other processes.

§Example
use tun_rs::DeviceBuilder;

let dev = DeviceBuilder::new()
    .name("persistent-tun")
    .ipv4("10.0.0.1", 24, None)
    .build_sync()?;

// Make the device persistent so it survives after program exit
dev.persist()?;
println!("Device will persist after program exits");
Source

pub fn user(&self, value: i32) -> Result<()>

Available on Linux and non-target_env=ohos only.

Set the owner (UID) of the device.

This allows non-root users to access the TUN/TAP device.

§Example
use tun_rs::DeviceBuilder;

let dev = DeviceBuilder::new()
    .ipv4("10.0.0.1", 24, None)
    .build_sync()?;

// Set ownership to UID 1000 (typical first user on Linux)
dev.user(1000)?;
println!("Device ownership set to UID 1000");
Source

pub fn group(&self, value: i32) -> Result<()>

Available on Linux and non-target_env=ohos only.

Set the group (GID) of the device.

This allows members of a specific group to access the TUN/TAP device.

§Example
use tun_rs::DeviceBuilder;

let dev = DeviceBuilder::new()
    .ipv4("10.0.0.1", 24, None)
    .build_sync()?;

// Set group ownership to GID 1000
dev.group(1000)?;
println!("Device group ownership set to GID 1000");
Source

pub fn send_multiple<B: ExpandBuffer>( &self, gro_table: &mut GROTable, bufs: &mut [B], offset: usize, ) -> Result<usize>

Available on Linux and non-target_env=ohos only.

Sends multiple packets in a batch with GRO (Generic Receive Offload) coalescing.

This method allows efficient transmission of multiple packets by batching them together and applying GRO optimizations. When offload is enabled, packets may be coalesced to reduce system call overhead and improve throughput.

§Arguments
  • gro_table - A mutable reference to a GROTable that manages packet coalescing state. This table can be reused across multiple calls to amortize allocation overhead.
  • bufs - A mutable slice of buffers containing the packets to send. Each buffer must implement the ExpandBuffer trait.
  • offset - The byte offset within each buffer where the packet data begins. Must be >= VIRTIO_NET_HDR_LEN to accommodate the virtio network header when offload is enabled.
§Returns

Returns the total number of bytes successfully sent, or an I/O error.

§Example
use tun_rs::{DeviceBuilder, GROTable, VIRTIO_NET_HDR_LEN};

let dev = DeviceBuilder::new()
    .ipv4("10.0.0.1", 24, None)
    .with(|builder| {
        builder.offload(true)  // Enable offload for GRO
    })
    .build_sync()?;

let mut gro_table = GROTable::default();
let offset = VIRTIO_NET_HDR_LEN;

// Prepare packets to send
let mut packet1 = vec![0u8; offset + 100];  // VIRTIO_NET_HDR + packet data
let mut packet2 = vec![0u8; offset + 200];
// Fill in packet data at offset...

let mut bufs = vec![packet1, packet2];

// Send all packets in one batch
let bytes_sent = dev.send_multiple(&mut gro_table, &mut bufs, offset)?;
println!("Sent {} bytes across {} packets", bytes_sent, bufs.len());
§Platform

This method is only available on Linux.

§Performance Notes
  • Use IDEAL_BATCH_SIZE for optimal batch size (typically 128 packets)
  • Reuse the same GROTable instance across calls to avoid allocations
  • Enable offload via .offload(true) in DeviceBuilder for best performance
Source

pub fn recv_multiple<B: AsRef<[u8]> + AsMut<[u8]>>( &self, original_buffer: &mut [u8], bufs: &mut [B], sizes: &mut [usize], offset: usize, ) -> Result<usize>

Available on Linux and non-target_env=ohos only.

Receives multiple packets in a batch with GSO (Generic Segmentation Offload) splitting.

When offload is enabled, this method can receive large GSO packets from the TUN device and automatically split them into MTU-sized segments, significantly improving receive performance for high-bandwidth traffic.

§Arguments
  • original_buffer - A mutable buffer to store the raw received data, including the virtio network header and the potentially large GSO packet. Recommended size is VIRTIO_NET_HDR_LEN + 65535 bytes.
  • bufs - A mutable slice of buffers to store the segmented packets. Each buffer will receive one MTU-sized packet after GSO splitting.
  • sizes - A mutable slice to store the actual size of each packet in bufs. Must have the same length as bufs.
  • offset - The byte offset within each output buffer where packet data should be written. This allows for pre-allocated header space.
§Returns

Returns the number of packets successfully received and split, or an I/O error.

§Example
use tun_rs::{DeviceBuilder, VIRTIO_NET_HDR_LEN, IDEAL_BATCH_SIZE};

let dev = DeviceBuilder::new()
    .ipv4("10.0.0.1", 24, None)
    .with(|builder| {
        builder.offload(true)  // Enable offload for GSO
    })
    .build_sync()?;

// Buffer for the raw received packet (with virtio header)
let mut original_buffer = vec![0u8; VIRTIO_NET_HDR_LEN + 65535];

// Output buffers for segmented packets
let mut bufs = vec![vec![0u8; 1500]; IDEAL_BATCH_SIZE];
let mut sizes = vec![0usize; IDEAL_BATCH_SIZE];
let offset = 0;

loop {
    // Receive and segment packets
    let num_packets = dev.recv_multiple(
        &mut original_buffer,
        &mut bufs,
        &mut sizes,
        offset
    )?;

    // Process each segmented packet
    for i in 0..num_packets {
        let packet = &bufs[i][offset..offset + sizes[i]];
        println!("Received packet {}: {} bytes", i, sizes[i]);
        // Process packet...
    }
}
§Platform

This method is only available on Linux.

§Performance Notes
  • Use IDEAL_BATCH_SIZE (128) for the number of output buffers
  • A single recv_multiple call may return multiple MTU-sized packets from one large GSO packet
  • The performance benefit is most noticeable with TCP traffic using large send/receive windows
Source

pub fn remove_address_v6_impl(&self, addr: Ipv6Addr, prefix: u8) -> Result<()>

Available on Linux and non-target_env=ohos only.
Source§

impl DeviceImpl

Source

pub fn name(&self) -> Result<String>

Available on Linux and non-target_env=ohos only.

Retrieves the name of the network interface.

Source

pub fn remove_address_v6(&self, addr: Ipv6Addr, prefix: u8) -> Result<()>

Available on Linux and non-target_env=ohos only.
Source

pub fn set_name(&self, value: &str) -> Result<()>

Available on Linux and non-target_env=ohos only.

Sets a new name for the network interface.

This function converts the provided name into a C-compatible string, checks that its length does not exceed the maximum allowed (IFNAMSIZ), and then copies it into an interface request structure. It then uses a system call (via siocsifname) to apply the new name.

§Example
use tun_rs::DeviceBuilder;

let dev = DeviceBuilder::new()
    .name("tun0")
    .ipv4("10.0.0.1", 24, None)
    .build_sync()?;

// Rename the device
dev.set_name("vpn-tun")?;
println!("Device renamed to vpn-tun");
Source

pub fn is_running(&self) -> Result<bool>

Available on Linux and non-target_env=ohos only.

Checks whether the network interface is currently running.

The interface is considered running if both the IFF_UP and IFF_RUNNING flags are set.

Source

pub fn enabled(&self, value: bool) -> Result<()>

Available on Linux and non-target_env=ohos only.

Enables or disables the network interface.

If value is true, the interface is enabled by setting the IFF_UP and IFF_RUNNING flags. If false, the IFF_UP flag is cleared. The change is applied using a system call.

Source

pub fn broadcast(&self) -> Result<IpAddr>

Available on Linux and non-target_env=ohos only.

Retrieves the broadcast address of the network interface.

This function populates an interface request with the broadcast address via a system call, converts it into a sockaddr structure, and then extracts the IP address.

§Example
use tun_rs::DeviceBuilder;

let dev = DeviceBuilder::new()
    .ipv4("10.0.0.1", 24, None)
    .build_sync()?;

// Get the broadcast address
let broadcast = dev.broadcast()?;
println!("Broadcast address: {}", broadcast);
Source

pub fn set_broadcast(&self, value: IpAddr) -> Result<()>

Available on Linux and non-target_env=ohos only.

Sets the broadcast address of the network interface.

This function converts the given IP address into a sockaddr structure (with a specified overwrite size) and then applies it to the interface via a system call.

Source

pub fn set_network_address<IPv4: ToIpv4Address, Netmask: ToIpv4Netmask>( &self, address: IPv4, netmask: Netmask, destination: Option<IPv4>, ) -> Result<()>

Available on Linux and non-target_env=ohos only.

Sets the IPv4 network address, netmask, and an optional destination address. Remove all previous set IPv4 addresses and set the specified address.

§Example
use tun_rs::DeviceBuilder;

let dev = DeviceBuilder::new()
    .ipv4("10.0.0.1", 24, None)
    .build_sync()?;

// Change the primary IPv4 address
dev.set_network_address("10.1.0.1", 24, None)?;
println!("Updated device address to 10.1.0.1/24");
Source

pub fn add_address_v4<IPv4: ToIpv4Address, Netmask: ToIpv4Netmask>( &self, address: IPv4, netmask: Netmask, ) -> Result<()>

Available on Linux and non-target_env=ohos only.

Add IPv4 network address and netmask to the interface.

This allows multiple IPv4 addresses on a single TUN/TAP device.

§Example
use tun_rs::DeviceBuilder;

let dev = DeviceBuilder::new()
    .ipv4("10.0.0.1", 24, None)
    .build_sync()?;

// Add additional IPv4 addresses
dev.add_address_v4("10.0.1.1", 24)?;
dev.add_address_v4("10.0.2.1", 24)?;
println!("Added multiple IPv4 addresses");
Source

pub fn remove_address(&self, addr: IpAddr) -> Result<()>

Available on Linux and non-target_env=ohos only.

Removes an IP address from the interface.

For IPv4 addresses, it iterates over the current addresses and if a match is found, resets the address to 0.0.0.0 (unspecified). For IPv6 addresses, it retrieves the interface addresses by name and removes the matching address, taking into account its prefix length.

§Example
use std::net::IpAddr;
use tun_rs::DeviceBuilder;

let dev = DeviceBuilder::new()
    .ipv4("10.0.0.1", 24, None)
    .build_sync()?;

// Add an additional address
dev.add_address_v4("10.0.1.1", 24)?;

// Later, remove it
dev.remove_address("10.0.1.1".parse::<IpAddr>().unwrap())?;
println!("Removed address 10.0.1.1");
Source

pub fn add_address_v6<IPv6: ToIpv6Address, Netmask: ToIpv6Netmask>( &self, addr: IPv6, netmask: Netmask, ) -> Result<()>

Available on Linux and non-target_env=ohos only.

Adds an IPv6 address to the interface.

This function creates an in6_ifreq structure, fills in the interface index, prefix length, and IPv6 address (converted into a sockaddr structure), and then applies it using a system call.

§Example
use tun_rs::DeviceBuilder;

let dev = DeviceBuilder::new()
    .ipv4("10.0.0.1", 24, None)
    .build_sync()?;

// Add IPv6 addresses
dev.add_address_v6("fd00::1", 64)?;
dev.add_address_v6("fd00::2", 64)?;
println!("Added IPv6 addresses");
Source

pub fn mtu(&self) -> Result<u16>

Available on Linux and non-target_env=ohos only.

Retrieves the current MTU (Maximum Transmission Unit) for the interface.

This function constructs an interface request and uses a system call (via siocgifmtu) to obtain the MTU. The result is then converted to a u16.

Source

pub fn set_mtu(&self, value: u16) -> Result<()>

Available on Linux and non-target_env=ohos only.

Sets the MTU (Maximum Transmission Unit) for the interface.

This function creates an interface request, sets the ifru_mtu field to the new value, and then applies it via a system call.

§Example
use tun_rs::DeviceBuilder;

let dev = DeviceBuilder::new()
    .ipv4("10.0.0.1", 24, None)
    .mtu(1400)
    .build_sync()?;

// Change MTU to accommodate larger packets
dev.set_mtu(9000)?; // Jumbo frames
println!("MTU set to 9000 bytes");
Source

pub fn set_mac_address(&self, eth_addr: [u8; 6]) -> Result<()>

Available on Linux and non-target_env=ohos only.

Sets the MAC (hardware) address for the interface.

This function constructs an interface request and copies the provided MAC address into the hardware address field. It then applies the change via a system call. This operation is typically supported only for TAP devices.

Source

pub fn mac_address(&self) -> Result<[u8; 6]>

Available on Linux and non-target_env=ohos only.

Retrieves the MAC (hardware) address of the interface.

This function queries the MAC address by the interface name using a helper function. An error is returned if the MAC address cannot be found.

Trait Implementations§

Source§

impl AsFd for DeviceImpl

Available on Unix only.
Source§

fn as_fd(&self) -> BorrowedFd<'_>

Borrows the file descriptor. Read more
Source§

impl AsRawFd for DeviceImpl

Available on Unix only.
Source§

fn as_raw_fd(&self) -> RawFd

Extracts the raw file descriptor. Read more
Source§

impl FromRawFd for DeviceImpl

Available on Unix only.
Source§

unsafe fn from_raw_fd(fd: RawFd) -> Self

§Safety

The caller must ensure that fd is a valid, open file descriptor for a TUN/TAP device.

§Panics

This function will panic if the provided file descriptor is invalid or cannot be used to create a TUN/TAP device. This is acceptable because providing an invalid fd violates the safety contract of FromRawFd.

Source§

impl IntoRawFd for DeviceImpl

Available on Unix and neither FreeBSD nor NetBSD nor OpenBSD only.
Source§

fn into_raw_fd(self) -> RawFd

Consumes this object, returning the raw underlying file descriptor. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.