rtnetlink Rust Crate

repository·main·Indexed 41 days ago

https://github.com/rust-netlink/rtnetlink

A Rust crate providing high-level methods to manipulate Linux networking resources via the rtnetlink protocol. Version 0.23.0 allows programmatic management of network links, IP addresses, ARP/neighbor tables, route tables, routing rules, and traffic control (tc) settings. It includes specialized handles like LinkHandle, AddressHandle, RouteHandle, and NeighbourHandle, as well as support for various link types such as Bond, CAN, Bridge, and VLAN.

Tokens
9.1K
Snippets
14
Records
36
Agent score
47%

What's inside rtnetlink

  1. Overview of the rtnetlink crate

    main

    The rtnetlink crate provides a Rust interface for manipulating Linux networking resources using the rtnetlink protocol. It allows developers to programmatically manage:

    • Links: Network interfaces.
    • Addresses: IP addresses assigned to interfaces.
    • ARP tables: Address Resolution Protocol entries.
    • Route tables: IP routing configurations.

    This crate is a specialized implementation of the netlink route protocol as defined in the Linux man pages.

  2. Create an rmnet interface

    main

    You can create an rmnet interface using LinkRmNet::new(name). Because rmnet interfaces are dependent on a parent device, you must specify the parent device name using .parent_dev_name().

    Common configuration options include:

    • .mux_id(u16): Sets the MUXID (equivalent to mux_id MUXID in the ip link command).
    • .flags(flags, mask): Sets the rmnet flags using RmNetFlags and a mask.
    • .parent_dev_name(parent): Specifies the parent device name (equivalent to link DEVICE in the ip link command).
    use rtnetlink::{new_connection, LinkRmNet};
    
    #[tokio::main]
    async fn main() -> Result<(), String> {
        let (connection, handle, _) = new_connection().unwrap();
        tokio::spawn(connection);
    
        handle
            .link()
            .add(
                LinkRmNet::new("rmnet0")
                    .parent_dev_name("dummy0")
                    .mux_id(10)
                    .build(),
            )
            .execute()
            .await
            .map_err(|e| format!("{e}"))
    }
  3. Create a Netkit virtual interface pair

    main

    Netkit devices are used for container networking and BPF programs. You can create a netkit pair using LinkNetkit::new(name, peer, mode) which returns a LinkMessageBuilder<LinkNetkit>. This builder allows you to configure specific netkit attributes before executing the command via a netlink handle.

    To create a netkit pair, use the following pattern:

    1. Initialize a connection and handle.
    2. Use LinkNetkit::new with the desired interface name, peer name, and NetkitMode.
    3. Call .build() on the builder.
    4. Use .link().add(...).execute().await on the handle to send the request.
    use rtnetlink::{new_connection, LinkNetkit, packet_route::link::NetkitMode};
    
    #[tokio::main]
    async fn main() -> Result<(), String> {
        let (connection, handle, _) = new_connection().unwrap();
        tokio::spawn(connection);
    
        handle
            .link()
            .add(LinkNetkit::new("netkit0", "netkit0-peer", NetkitMode::L3).build())
            .execute()
            .await
            .map_err(|e| format!("{e}"))
    }
  4. Create a WWAN network interface

    main

    You can create a WWAN (Wireless Wide Area Network) interface using LinkWwan::new(name). When creating a WWAN interface, you must specify the parent device using .parent_dev_name(). You can also optionally set a linkid using .linkid().

    This corresponds to the following ip link command structure: ip link add name NAME parentdev PARENTDEV type wwan linkid LINKID

    use rtnetlink::{new_connection, LinkWwan};
    
    #[tokio::main]
    async fn main() -> Result<(), String> {
        let (connection, handle, _) = new_connection().unwrap();
        tokio::spawn(connection);
    
        handle
            .link()
            .add(
                LinkWwan::new("wwan0p")
                    .parent_dev_name("wwan0")
                    .linkid(15)
                    .build(),
            )
            .execute()
            .await
            .map_err(|e| format!("{e}"))
    }
  5. Create a GTP network interface

    main

    Use LinkGtp::new(name) to initialize a LinkMessageBuilder for a GTP (GPRS Tunneling Protocol) interface. You can then configure the interface using methods like .role(), .pdp_hashsize(), and .restart_count() before calling .build() and executing the command via a netlink handle.

    Note that create_sockets is automatically set to true by default to match iproute2 behavior.

    use rtnetlink::{new_connection, LinkGtp};
    use rtnetlink::packet_route::link::GtpRole;
    
    #[tokio::main]
    async fn main() -> Result<(), String> {
        let (connection, handle, _) = new_connection().unwrap();
        tokio::spawn(connection);
    
        handle
            .link()
            .add(
                LinkGtp::new("gtp0")
                    .role(GtpRole::Sgsn)
                    .build(),
            )
            .execute()
            .await
            .map_err(|e| format!("{e}"))
    }
  6. Create an HSR (High-availability Seamless Redundancy) interface

    main

    You can create and configure an HSR network interface using LinkHsr. This is done by initializing a LinkMessageBuilder via LinkHsr::new(name) and then chaining configuration methods to set port indices, protocol versions, and other HSR-specific parameters. Once configured, use the handle.link().add(...) method to execute the creation of the link.

    use rtnetlink::{new_connection, LinkHsr};
    
    #[tokio::main]
    async fn main() -> Result<(), String> {
        let (connection, handle, _) = new_connection().unwrap();
        tokio::spawn(connection);
    
        handle
            .link()
            .add(
                LinkHsr::new("hsr0")
                    .port1(3)
                    .port2(4)
                    .build()
            )
            .execute()
            .await
            .map_err(|e| format!("{e}"))
    }
  7. Create an IP-in-IP (IPIP) interface

    main

    Use LinkIpIp and its LinkMessageBuilder to create new IP-in-IP network links. This is the programmatic equivalent of the ip link add name NAME type ipip ... command.

    To create an interface, call LinkIpIp::new("interface_name") to get a builder, configure the tunnel parameters, and then use the link handle to execute the command.

    use std::net::Ipv4Addr;
    use rtnetlink::{new_connection, LinkIpIp};
    
    #[tokio::main]
    async fn main() -> Result<(), String> {
        let (connection, handle, _) = new_connection().unwrap();
        tokio::spawn(connection);
    
        handle
            .link()
            .add(
                LinkIpIp::new("ipip0")
                    .local(Ipv4Addr::new(192, 168, 1, 1))
                    .remote(Ipv4Addr::new(10, 0, 0, 1))
                    .build(),
            )
            .execute()
            .await
            .map_err(|e| format!("{e}"))
    }
  8. Create a SIT network interface

    main

    Use LinkSit::new(name) to initialize a builder for a Simple Internet Transition (SIT) interface. You can then configure the interface using various builder methods that correspond to the ip link add ... type sit command. Once configured, use the handle.link().add(...).execute() pattern to apply the changes to the system.

    Common configuration methods include:

    • .local(Ipv4Addr): Sets the local IPv4 address.
    • .remote(Ipv4Addr): Sets the remote IPv4 address.
    • .ttl(u8): Sets the Time To Live.
    • .tos(u8): Sets the Type of Service.
    • .protocol(IpProtocol): Sets the encapsulation protocol.
    • .isatap(bool): Enables or disables ISATAP mode.
    • .dev(u32): Specifies the physical device index.
    use std::net::Ipv4Addr;
    use rtnetlink::{new_connection, LinkSit};
    
    #[tokio::main]
    async fn main() -> Result<(), String> {
        let (connection, handle, _) = new_connection().unwrap();
        tokio::spawn(connection);
    
        handle
            .link()
            .add(
                LinkSit::new("sit0")
                    .local(Ipv4Addr::new(192, 168, 1, 1))
                    .remote(Ipv4Addr::new(10, 0, 0, 1))
                    .build(),
            )
            .execute()
            .await
            .map_err(|e| format!("{e}"))
    }
  9. Create an IP6TNL network interface

    main

    Use LinkIp6Tnl::new(name) to create a builder for an IPv6 Tunnel (IP6TNL) interface. You can configure properties like local/remote addresses, TTL, and encapsulation settings using the LinkMessageBuilder methods. Once configured, use the handle.link().add(...).execute().await pattern to create the interface on the system.

    use std::net::Ipv6Addr;
    use rtnetlink::{new_connection, LinkIp6Tnl};
    
    #[tokio::main]
    async fn main() -> Result<(), String> {
        let (connection, handle, _) = new_connection().unwrap();
        tokio::spawn(connection);
    
        handle
            .link()
            .add(
                LinkIp6Tnl::new("ip6tnl0")
                    .local(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1))
                    .remote(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 2))
                    .build(),
            )
            .execute()
            .await
            .map_err(|e| format!("{e}"))
    }
  10. Create a VXLAN interface

    main

    To create a VXLAN interface, use LinkVxlan::new(name, vni) to initialize a LinkMessageBuilder. You can then chain configuration methods to define attributes like the physical device index, destination port, and IP addresses before calling .build() and executing the command via a link handle.

    Note: LinkMessageBuilder::link() is not compatible with VXLAN; use the .dev(index) method instead to specify the physical device index.

    use rtnetlink::{new_connection, LinkVxlan};
    
    #[tokio::main]
    async fn main() -> Result<(), String> {
        let (connection, handle, _) = new_connection().unwrap();
        tokio::spawn(connection);
    
        handle
            .link()
            .add(LinkVxlan::new("vxlan100", 100)
                .dev(10)
                .port(4789)
                .up()
                .build())
            .execute()
            .await
            .map_err(|e| format!("{e}"))
    }
  11. Create a bond network interface

    main

    Use LinkBond::new(name) to initialize a LinkMessageBuilder for a bond interface. You can then chain various configuration methods to set attributes like mode, miimon, updelay, and downdelay before calling .build() to create the message. Finally, use the link handle to execute the addition of the interface.

    This process is equivalent to the CLI command: ip link add name <NAME> type bond [options].

    use rtnetlink::{new_connection, LinkBond, packet_route::link::BondMode};
    
    #[tokio::main]
    async fn main() -> Result<(), String> {
        let (connection, handle, _) = new_connection().map_err(|e|
            format!("{e}"))?;
        tokio::spawn(connection);
    
        let message = LinkBond::new("bond0")
           .mode(BondMode::ActiveBackup)
           .miimon(100)
           .updelay(100)
           .downdelay(100)
           .min_links(2)
           .up()
           .build();
    
        handle
            .link()
            .add(message)
            .execute()
            .await
            .map_err(|e| format!("{e}"))
    }
  12. Create a CAN network interface

    main

    Use LinkCan::new(name) to initialize a LinkMessageBuilder for a CAN interface. You can then chain configuration methods like .bitrate(u32) or .bit_timing(CanBitTiming) before calling .build() to prepare the interface for addition via the netlink handle.

    Note: The .bitrate() method is a shorthand for setting the bitrate within the bit timing parameters, equivalent to the ip link add ... type can bitrate BITRATE command.

    use rtnetlink::{new_connection, LinkCan};
    
    #[tokio::main]
    async fn main() -> Result<(), String> {
        let (connection, handle, _) = new_connection().unwrap();
        tokio::spawn(connection);
    
        handle
            .link()
            .add(
                LinkCan::new("can0")
                    .bitrate(500000)
                    .build()
            )
            .execute()
            .await
            .map_err(|e| format!("{e}"))
    }