diff --git a/Cargo.toml b/Cargo.toml index 6261471..08e3507 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ futures-channel = "0.3.11" log = "0.4.8" thiserror = "1" netlink-sys = { version = "0.8" } -netlink-packet-route = { version = "0.28" } +netlink-packet-route = { version = "0.29" } netlink-packet-core = { version = "0.8" } netlink-proto = { default-features = false, version = "0.12.0" } nix = { version = "0.30.0", default-features = false, features = ["fs", "mount", "sched", "signal"] } diff --git a/examples/create_vxcan.rs b/examples/create_vxcan.rs new file mode 100644 index 0000000..e2a38d4 --- /dev/null +++ b/examples/create_vxcan.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT + +use futures_util::stream::TryStreamExt; +use rtnetlink::{new_connection, Error, Handle, LinkUnspec, LinkVxcan}; + +#[tokio::main] +async fn main() -> Result<(), String> { + let (connection, handle, _) = new_connection().unwrap(); + tokio::spawn(connection); + + let link_name = "vxcan0"; + let peer_name = "vxcan0-peer"; + + handle + .link() + .add(LinkVxcan::new(link_name, peer_name).build()) + .execute() + .await + .map_err(|e| format!("{e}"))?; + + set_link_up(&handle, link_name) + .await + .map_err(|e| format!("{e}"))?; + + set_link_up(&handle, peer_name) + .await + .map_err(|e| format!("{e}"))?; + + Ok(()) +} + +async fn set_link_up(handle: &Handle, name: &str) -> Result<(), Error> { + let mut links = handle.link().get().match_name(name.to_string()).execute(); + if let Some(link) = links.try_next().await? { + handle + .link() + .set(LinkUnspec::new_with_index(link.header.index).up().build()) + .execute() + .await? + } else { + println!("no link {name} found"); + } + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 009c9a3..6c5caed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,7 +53,8 @@ pub use crate::{ LinkBridgeVlan, LinkDelPropRequest, LinkDelRequest, LinkDummy, LinkGetRequest, LinkHandle, LinkMacSec, LinkMacVlan, LinkMacVtap, LinkMessageBuilder, LinkNetkit, LinkSetRequest, LinkUnspec, LinkVeth, - LinkVlan, LinkVrf, LinkVxlan, LinkWireguard, LinkXfrm, QosMapping, + LinkVlan, LinkVrf, LinkVxcan, LinkVxlan, LinkWireguard, LinkXfrm, + QosMapping, }, multicast::MulticastGroup, neighbour::{ diff --git a/src/link/bond.rs b/src/link/bond.rs index cf1c96d..07f1e33 100644 --- a/src/link/bond.rs +++ b/src/link/bond.rs @@ -5,9 +5,9 @@ use std::net::{Ipv4Addr, Ipv6Addr}; use crate::{ link::LinkMessageBuilder, packet_route::link::{ - BondAllPortActive, BondArpAllTargets, BondArpValidate, BondFailOverMac, - BondLacpRate, BondMode, BondPrimaryReselect, BondXmitHashPolicy, - InfoBond, InfoData, InfoKind, + BondAdSelect, BondAllPortActive, BondArpAllTargets, BondArpValidate, + BondFailOverMac, BondLacpRate, BondMode, BondPrimaryReselect, + BondXmitHashPolicy, InfoBond, InfoData, InfoKind, }, }; @@ -218,7 +218,7 @@ impl LinkMessageBuilder { /// Adds the `ad_select` attribute to the bond /// This is equivalent to `ip link add name NAME type bond ad_select /// AD_SELECT`. - pub fn ad_select(self, ad_select: u8) -> Self { + pub fn ad_select(self, ad_select: BondAdSelect) -> Self { self.append_info_data(InfoBond::AdSelect(ad_select)) } diff --git a/src/link/bridge_port.rs b/src/link/bridge_port.rs index 6022535..79c8803 100644 --- a/src/link/bridge_port.rs +++ b/src/link/bridge_port.rs @@ -148,7 +148,7 @@ impl LinkMessageBuilder { /// `ip link set name NAME type bridge_slave \ /// neigh_vlan_suppress { on | off }`. pub fn neigh_vlan_suppress(self, v: bool) -> Self { - self.append_info_data(InfoBridgePort::NeighVlanSupress(v)) + self.append_info_data(InfoBridgePort::NeighVlanSuppress(v)) } /// This is equivalent to diff --git a/src/link/mod.rs b/src/link/mod.rs index 69df943..bb01029 100644 --- a/src/link/mod.rs +++ b/src/link/mod.rs @@ -22,6 +22,7 @@ mod set; mod veth; mod vlan; mod vrf; +mod vxcan; mod vxlan; mod wireguard; mod xfrm; @@ -47,6 +48,7 @@ pub use self::{ veth::LinkVeth, vlan::{LinkVlan, QosMapping}, vrf::LinkVrf, + vxcan::LinkVxcan, vxlan::LinkVxlan, wireguard::LinkWireguard, xfrm::LinkXfrm, diff --git a/src/link/vxcan.rs b/src/link/vxcan.rs new file mode 100644 index 0000000..346bb4d --- /dev/null +++ b/src/link/vxcan.rs @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT + +use crate::{ + packet_route::link::{InfoData, InfoKind, InfoVxcan}, + LinkMessageBuilder, LinkUnspec, +}; + +/// Represent virtual can interface. +/// Example code on creating a vxcan pair +/// ```no_run +/// use rtnetlink::{new_connection, LinkVxcan}; +/// #[tokio::main] +/// async fn main() -> Result<(), String> { +/// let (connection, handle, _) = new_connection().unwrap(); +/// tokio::spawn(connection); +/// +/// handle +/// .link() +/// .add(LinkVxcan::new("vxcan0", "vxcan1").build()) +/// .execute() +/// .await +/// .map_err(|e| format!("{e}")) +/// } +/// ``` +/// +/// Please check LinkMessageBuilder:: for more detail. +#[derive(Debug)] +pub struct LinkVxcan; + +impl LinkVxcan { + /// Equal to `LinkMessageBuilder::::new(name, peer)` + pub fn new(name: &str, peer: &str) -> LinkMessageBuilder { + LinkMessageBuilder::::new(name, peer) + } +} + +impl LinkMessageBuilder { + /// Create [LinkMessageBuilder] for Vxcan + pub fn new(name: &str, peer: &str) -> Self { + LinkMessageBuilder::::new_with_info_kind(InfoKind::Vxcan) + .name(name.to_string()) + .peer(peer) + } + + pub fn peer(mut self, peer: &str) -> Self { + let peer_msg = LinkMessageBuilder::::new() + .name(peer.to_string()) + .build(); + + self.info_data = Some(InfoData::Vxcan(InfoVxcan::Peer(peer_msg))); + self + } +}