use std::net::Ipv4Addr;
use super::{
builder::MessageBuilder,
connection::Connection,
error::Result,
interface_ref::InterfaceRef,
message::NlMsgType,
protocol::Route,
types::link::{IfInfoMsg, IflaAttr, IflaInfo},
};
const NLM_F_CREATE: u16 = 0x400;
const NLM_F_EXCL: u16 = 0x200;
pub trait LinkConfig: Send + Sync {
fn name(&self) -> &str;
fn kind(&self) -> &str;
fn peer_name(&self) -> Option<&str> {
None
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
None
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>);
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct DummyLink {
name: String,
mtu: Option<u32>,
address: Option<[u8; 6]>,
}
impl DummyLink {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
mtu: None,
address: None,
}
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn address(mut self, addr: [u8; 6]) -> Self {
self.address = Some(addr);
self
}
}
impl LinkConfig for DummyLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"dummy"
}
fn write_to(&self, builder: &mut MessageBuilder, _parent_index: Option<u32>) {
write_simple_link(
builder,
&self.name,
"dummy",
self.mtu,
self.address.as_ref(),
);
}
}
#[derive(Debug)]
#[must_use = "builders do nothing unless used"]
pub struct VethLink {
name: String,
peer_name: String,
mtu: Option<u32>,
address: Option<[u8; 6]>,
peer_address: Option<[u8; 6]>,
peer_netns_fd: Option<i32>,
peer_netns_pid: Option<u32>,
_peer_netns_owned: Option<super::namespace::NamespaceFd>,
}
impl VethLink {
pub fn new(name: impl Into<String>, peer_name: impl Into<String>) -> Self {
Self {
name: name.into(),
peer_name: peer_name.into(),
mtu: None,
address: None,
peer_address: None,
peer_netns_fd: None,
peer_netns_pid: None,
_peer_netns_owned: None,
}
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn address(mut self, addr: [u8; 6]) -> Self {
self.address = Some(addr);
self
}
pub fn peer_address(mut self, addr: [u8; 6]) -> Self {
self.peer_address = Some(addr);
self
}
pub fn peer_netns_fd(mut self, fd: i32) -> Self {
self.peer_netns_fd = Some(fd);
self.peer_netns_pid = None;
self
}
pub fn peer_netns_pid(mut self, pid: u32) -> Self {
self.peer_netns_pid = Some(pid);
self.peer_netns_fd = None;
self
}
pub fn peer_netns(mut self, ns_name: &str) -> Result<Self> {
let ns_fd = super::namespace::open(ns_name)?;
self.peer_netns_fd = Some(ns_fd.as_raw_fd());
self.peer_netns_pid = None;
self._peer_netns_owned = Some(ns_fd);
Ok(self)
}
}
mod veth {
pub const VETH_INFO_PEER: u16 = 1;
}
impl LinkConfig for VethLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"veth"
}
fn peer_name(&self) -> Option<&str> {
Some(&self.peer_name)
}
fn write_to(&self, builder: &mut MessageBuilder, _parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(ref addr) = self.address {
builder.append_attr(IflaAttr::Address as u16, addr);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "veth");
let data = builder.nest_start(IflaInfo::Data as u16);
let peer = builder.nest_start(veth::VETH_INFO_PEER);
let peer_ifinfo = IfInfoMsg::new();
builder.append(&peer_ifinfo);
builder.append_attr_str(IflaAttr::Ifname as u16, &self.peer_name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(ref addr) = self.peer_address {
builder.append_attr(IflaAttr::Address as u16, addr);
}
if let Some(fd) = self.peer_netns_fd {
builder.append_attr_u32(IflaAttr::NetNsFd as u16, fd as u32);
} else if let Some(pid) = self.peer_netns_pid {
builder.append_attr_u32(IflaAttr::NetNsPid as u16, pid);
}
builder.nest_end(peer);
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct BridgeLink {
name: String,
mtu: Option<u32>,
address: Option<[u8; 6]>,
forward_delay: Option<u32>,
hello_time: Option<u32>,
max_age: Option<u32>,
ageing_time: Option<u32>,
stp_state: Option<u32>,
priority: Option<u16>,
vlan_filtering: Option<bool>,
vlan_default_pvid: Option<u16>,
}
mod bridge {
pub const IFLA_BR_FORWARD_DELAY: u16 = 1;
pub const IFLA_BR_HELLO_TIME: u16 = 2;
pub const IFLA_BR_MAX_AGE: u16 = 3;
pub const IFLA_BR_AGEING_TIME: u16 = 4;
pub const IFLA_BR_STP_STATE: u16 = 5;
pub const IFLA_BR_PRIORITY: u16 = 6;
pub const IFLA_BR_VLAN_FILTERING: u16 = 7;
pub const IFLA_BR_VLAN_DEFAULT_PVID: u16 = 39;
}
impl BridgeLink {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
mtu: None,
address: None,
forward_delay: None,
hello_time: None,
max_age: None,
ageing_time: None,
stp_state: None,
priority: None,
vlan_filtering: None,
vlan_default_pvid: None,
}
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn address(mut self, addr: [u8; 6]) -> Self {
self.address = Some(addr);
self
}
pub fn stp(mut self, enabled: bool) -> Self {
self.stp_state = Some(if enabled { 1 } else { 0 });
self
}
pub fn forward_delay_ms(mut self, ms: u32) -> Self {
self.forward_delay = Some(ms / 10);
self
}
pub fn hello_time_ms(mut self, ms: u32) -> Self {
self.hello_time = Some(ms / 10);
self
}
pub fn max_age_ms(mut self, ms: u32) -> Self {
self.max_age = Some(ms / 10);
self
}
pub fn ageing_time(mut self, seconds: u32) -> Self {
self.ageing_time = Some(seconds * 100);
self
}
pub fn priority(mut self, priority: u16) -> Self {
self.priority = Some(priority);
self
}
pub fn vlan_filtering(mut self, enabled: bool) -> Self {
self.vlan_filtering = Some(enabled);
self
}
pub fn vlan_default_pvid(mut self, pvid: u16) -> Self {
self.vlan_default_pvid = Some(pvid);
self
}
}
impl LinkConfig for BridgeLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"bridge"
}
fn write_to(&self, builder: &mut MessageBuilder, _parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(ref addr) = self.address {
builder.append_attr(IflaAttr::Address as u16, addr);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "bridge");
let has_options = self.forward_delay.is_some()
|| self.hello_time.is_some()
|| self.max_age.is_some()
|| self.ageing_time.is_some()
|| self.stp_state.is_some()
|| self.priority.is_some()
|| self.vlan_filtering.is_some()
|| self.vlan_default_pvid.is_some();
if has_options {
let data = builder.nest_start(IflaInfo::Data as u16);
if let Some(val) = self.forward_delay {
builder.append_attr_u32(bridge::IFLA_BR_FORWARD_DELAY, val);
}
if let Some(val) = self.hello_time {
builder.append_attr_u32(bridge::IFLA_BR_HELLO_TIME, val);
}
if let Some(val) = self.max_age {
builder.append_attr_u32(bridge::IFLA_BR_MAX_AGE, val);
}
if let Some(val) = self.ageing_time {
builder.append_attr_u32(bridge::IFLA_BR_AGEING_TIME, val);
}
if let Some(val) = self.stp_state {
builder.append_attr_u32(bridge::IFLA_BR_STP_STATE, val);
}
if let Some(val) = self.priority {
builder.append_attr_u16(bridge::IFLA_BR_PRIORITY, val);
}
if let Some(enabled) = self.vlan_filtering {
builder.append_attr_u8(bridge::IFLA_BR_VLAN_FILTERING, if enabled { 1 } else { 0 });
}
if let Some(pvid) = self.vlan_default_pvid {
builder.append_attr_u16(bridge::IFLA_BR_VLAN_DEFAULT_PVID, pvid);
}
builder.nest_end(data);
}
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct VlanLink {
name: String,
parent: InterfaceRef,
vlan_id: u16,
mtu: Option<u32>,
address: Option<[u8; 6]>,
protocol: Option<u16>,
flags: VlanFlags,
}
mod vlan {
pub const IFLA_VLAN_ID: u16 = 1;
pub const IFLA_VLAN_FLAGS: u16 = 2;
pub const IFLA_VLAN_PROTOCOL: u16 = 5;
pub const VLAN_FLAG_REORDER_HDR: u32 = 0x1;
pub const VLAN_FLAG_GVRP: u32 = 0x2;
pub const VLAN_FLAG_LOOSE_BINDING: u32 = 0x4;
pub const VLAN_FLAG_MVRP: u32 = 0x8;
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub struct VlanFlags {
pub flags: u32,
pub mask: u32,
}
impl VlanLink {
pub fn new(name: impl Into<String>, parent: impl Into<String>, vlan_id: u16) -> Self {
Self {
name: name.into(),
parent: InterfaceRef::Name(parent.into()),
vlan_id,
mtu: None,
address: None,
protocol: None,
flags: VlanFlags::default(),
}
}
pub fn with_parent_index(name: impl Into<String>, parent_index: u32, vlan_id: u16) -> Self {
Self {
name: name.into(),
parent: InterfaceRef::Index(parent_index),
vlan_id,
mtu: None,
address: None,
protocol: None,
flags: VlanFlags::default(),
}
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn address(mut self, addr: [u8; 6]) -> Self {
self.address = Some(addr);
self
}
pub fn qinq(mut self) -> Self {
self.protocol = Some(0x88a8);
self
}
pub fn gvrp(mut self, enabled: bool) -> Self {
self.flags.mask |= vlan::VLAN_FLAG_GVRP;
if enabled {
self.flags.flags |= vlan::VLAN_FLAG_GVRP;
} else {
self.flags.flags &= !vlan::VLAN_FLAG_GVRP;
}
self
}
pub fn mvrp(mut self, enabled: bool) -> Self {
self.flags.mask |= vlan::VLAN_FLAG_MVRP;
if enabled {
self.flags.flags |= vlan::VLAN_FLAG_MVRP;
} else {
self.flags.flags &= !vlan::VLAN_FLAG_MVRP;
}
self
}
pub fn loose_binding(mut self, enabled: bool) -> Self {
self.flags.mask |= vlan::VLAN_FLAG_LOOSE_BINDING;
if enabled {
self.flags.flags |= vlan::VLAN_FLAG_LOOSE_BINDING;
} else {
self.flags.flags &= !vlan::VLAN_FLAG_LOOSE_BINDING;
}
self
}
pub fn reorder_hdr(mut self, enabled: bool) -> Self {
self.flags.mask |= vlan::VLAN_FLAG_REORDER_HDR;
if enabled {
self.flags.flags |= vlan::VLAN_FLAG_REORDER_HDR;
} else {
self.flags.flags &= !vlan::VLAN_FLAG_REORDER_HDR;
}
self
}
}
impl LinkConfig for VlanLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"vlan"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
Some(&self.parent)
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
let idx = parent_index.expect("VlanLink requires parent_index");
builder.append_attr_u32(IflaAttr::Link as u16, idx);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(ref addr) = self.address {
builder.append_attr(IflaAttr::Address as u16, addr);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "vlan");
let data = builder.nest_start(IflaInfo::Data as u16);
builder.append_attr_u16(vlan::IFLA_VLAN_ID, self.vlan_id);
if let Some(proto) = self.protocol {
builder.append_attr_u16_be(vlan::IFLA_VLAN_PROTOCOL, proto);
}
if self.flags.mask != 0 {
let flags_bytes = unsafe {
std::slice::from_raw_parts(
&self.flags as *const VlanFlags as *const u8,
std::mem::size_of::<VlanFlags>(),
)
};
builder.append_attr(vlan::IFLA_VLAN_FLAGS, flags_bytes);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct VxlanLink {
name: String,
vni: u32,
mtu: Option<u32>,
address: Option<[u8; 6]>,
local: Option<Ipv4Addr>,
remote: Option<Ipv4Addr>,
group: Option<Ipv4Addr>,
dev: Option<InterfaceRef>,
port: Option<u16>,
port_range: Option<(u16, u16)>,
ttl: Option<u8>,
tos: Option<u8>,
learning: Option<bool>,
proxy: Option<bool>,
rsc: Option<bool>,
l2miss: Option<bool>,
l3miss: Option<bool>,
udp_csum: Option<bool>,
}
mod vxlan {
pub const IFLA_VXLAN_ID: u16 = 1;
pub const IFLA_VXLAN_GROUP: u16 = 2;
pub const IFLA_VXLAN_LINK: u16 = 3;
pub const IFLA_VXLAN_LOCAL: u16 = 4;
pub const IFLA_VXLAN_TTL: u16 = 5;
pub const IFLA_VXLAN_TOS: u16 = 6;
pub const IFLA_VXLAN_LEARNING: u16 = 7;
pub const IFLA_VXLAN_PORT_RANGE: u16 = 10;
pub const IFLA_VXLAN_PROXY: u16 = 11;
pub const IFLA_VXLAN_RSC: u16 = 12;
pub const IFLA_VXLAN_L2MISS: u16 = 13;
pub const IFLA_VXLAN_L3MISS: u16 = 14;
pub const IFLA_VXLAN_PORT: u16 = 15;
pub const IFLA_VXLAN_UDP_CSUM: u16 = 18;
}
impl VxlanLink {
pub fn new(name: impl Into<String>, vni: u32) -> Self {
Self {
name: name.into(),
vni,
mtu: None,
address: None,
local: None,
remote: None,
group: None,
dev: None,
port: None,
port_range: None,
ttl: None,
tos: None,
learning: None,
proxy: None,
rsc: None,
l2miss: None,
l3miss: None,
udp_csum: None,
}
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn address(mut self, addr: [u8; 6]) -> Self {
self.address = Some(addr);
self
}
pub fn local(mut self, addr: Ipv4Addr) -> Self {
self.local = Some(addr);
self
}
pub fn remote(mut self, addr: Ipv4Addr) -> Self {
self.remote = Some(addr);
self
}
pub fn group(mut self, addr: Ipv4Addr) -> Self {
self.group = Some(addr);
self
}
pub fn dev(mut self, dev: impl Into<String>) -> Self {
self.dev = Some(InterfaceRef::Name(dev.into()));
self
}
pub fn dev_index(mut self, index: u32) -> Self {
self.dev = Some(InterfaceRef::Index(index));
self
}
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
pub fn port_range(mut self, low: u16, high: u16) -> Self {
self.port_range = Some((low, high));
self
}
pub fn ttl(mut self, ttl: u8) -> Self {
self.ttl = Some(ttl);
self
}
pub fn tos(mut self, tos: u8) -> Self {
self.tos = Some(tos);
self
}
pub fn learning(mut self, enabled: bool) -> Self {
self.learning = Some(enabled);
self
}
pub fn proxy(mut self, enabled: bool) -> Self {
self.proxy = Some(enabled);
self
}
pub fn rsc(mut self, enabled: bool) -> Self {
self.rsc = Some(enabled);
self
}
pub fn l2miss(mut self, enabled: bool) -> Self {
self.l2miss = Some(enabled);
self
}
pub fn l3miss(mut self, enabled: bool) -> Self {
self.l3miss = Some(enabled);
self
}
pub fn udp_csum(mut self, enabled: bool) -> Self {
self.udp_csum = Some(enabled);
self
}
}
impl LinkConfig for VxlanLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"vxlan"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
self.dev.as_ref()
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(ref addr) = self.address {
builder.append_attr(IflaAttr::Address as u16, addr);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "vxlan");
let data = builder.nest_start(IflaInfo::Data as u16);
builder.append_attr_u32(vxlan::IFLA_VXLAN_ID, self.vni);
if let Some(addr) = self.local {
builder.append_attr(vxlan::IFLA_VXLAN_LOCAL, &addr.octets());
}
if let Some(addr) = self.remote {
builder.append_attr(vxlan::IFLA_VXLAN_GROUP, &addr.octets());
} else if let Some(addr) = self.group {
builder.append_attr(vxlan::IFLA_VXLAN_GROUP, &addr.octets());
}
if let Some(idx) = parent_index {
builder.append_attr_u32(vxlan::IFLA_VXLAN_LINK, idx);
}
if let Some(port) = self.port {
builder.append_attr_u16_be(vxlan::IFLA_VXLAN_PORT, port);
}
if let Some((low, high)) = self.port_range {
let range = [low.to_be(), high.to_be()];
let range_bytes = unsafe { std::slice::from_raw_parts(range.as_ptr() as *const u8, 4) };
builder.append_attr(vxlan::IFLA_VXLAN_PORT_RANGE, range_bytes);
}
if let Some(ttl) = self.ttl {
builder.append_attr_u8(vxlan::IFLA_VXLAN_TTL, ttl);
}
if let Some(tos) = self.tos {
builder.append_attr_u8(vxlan::IFLA_VXLAN_TOS, tos);
}
if let Some(enabled) = self.learning {
builder.append_attr_u8(vxlan::IFLA_VXLAN_LEARNING, if enabled { 1 } else { 0 });
}
if let Some(enabled) = self.proxy {
builder.append_attr_u8(vxlan::IFLA_VXLAN_PROXY, if enabled { 1 } else { 0 });
}
if let Some(enabled) = self.rsc {
builder.append_attr_u8(vxlan::IFLA_VXLAN_RSC, if enabled { 1 } else { 0 });
}
if let Some(enabled) = self.l2miss {
builder.append_attr_u8(vxlan::IFLA_VXLAN_L2MISS, if enabled { 1 } else { 0 });
}
if let Some(enabled) = self.l3miss {
builder.append_attr_u8(vxlan::IFLA_VXLAN_L3MISS, if enabled { 1 } else { 0 });
}
if let Some(enabled) = self.udp_csum {
builder.append_attr_u8(vxlan::IFLA_VXLAN_UDP_CSUM, if enabled { 1 } else { 0 });
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum MacvlanMode {
Private = 1,
Vepa = 2,
Bridge = 4,
Passthru = 8,
Source = 16,
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct MacvlanLink {
name: String,
parent: InterfaceRef,
mode: MacvlanMode,
mtu: Option<u32>,
address: Option<[u8; 6]>,
}
mod macvlan {
pub const IFLA_MACVLAN_MODE: u16 = 1;
}
impl MacvlanLink {
pub fn new(name: impl Into<String>, parent: impl Into<String>) -> Self {
Self {
name: name.into(),
parent: InterfaceRef::Name(parent.into()),
mode: MacvlanMode::Bridge,
mtu: None,
address: None,
}
}
pub fn with_parent_index(name: impl Into<String>, parent_index: u32) -> Self {
Self {
name: name.into(),
parent: InterfaceRef::Index(parent_index),
mode: MacvlanMode::Bridge,
mtu: None,
address: None,
}
}
pub fn mode(mut self, mode: MacvlanMode) -> Self {
self.mode = mode;
self
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn address(mut self, addr: [u8; 6]) -> Self {
self.address = Some(addr);
self
}
}
impl LinkConfig for MacvlanLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"macvlan"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
Some(&self.parent)
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
let idx = parent_index.expect("MacvlanLink requires parent_index");
builder.append_attr_u32(IflaAttr::Link as u16, idx);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(ref addr) = self.address {
builder.append_attr(IflaAttr::Address as u16, addr);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "macvlan");
let data = builder.nest_start(IflaInfo::Data as u16);
builder.append_attr_u32(macvlan::IFLA_MACVLAN_MODE, self.mode as u32);
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum IpvlanMode {
L2 = 0,
L3 = 1,
L3S = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum IpvlanFlags {
Bridge = 0,
Private = 1,
Vepa = 2,
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct IpvlanLink {
name: String,
parent: InterfaceRef,
mode: IpvlanMode,
flags: IpvlanFlags,
mtu: Option<u32>,
}
mod ipvlan {
pub const IFLA_IPVLAN_MODE: u16 = 1;
pub const IFLA_IPVLAN_FLAGS: u16 = 2;
}
impl IpvlanLink {
pub fn new(name: impl Into<String>, parent: impl Into<String>) -> Self {
Self {
name: name.into(),
parent: InterfaceRef::Name(parent.into()),
mode: IpvlanMode::L3,
flags: IpvlanFlags::Bridge,
mtu: None,
}
}
pub fn with_parent_index(name: impl Into<String>, parent_index: u32) -> Self {
Self {
name: name.into(),
parent: InterfaceRef::Index(parent_index),
mode: IpvlanMode::L3,
flags: IpvlanFlags::Bridge,
mtu: None,
}
}
pub fn mode(mut self, mode: IpvlanMode) -> Self {
self.mode = mode;
self
}
pub fn flags(mut self, flags: IpvlanFlags) -> Self {
self.flags = flags;
self
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
}
impl LinkConfig for IpvlanLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"ipvlan"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
Some(&self.parent)
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
let idx = parent_index.expect("IpvlanLink requires parent_index");
builder.append_attr_u32(IflaAttr::Link as u16, idx);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "ipvlan");
let data = builder.nest_start(IflaInfo::Data as u16);
builder.append_attr_u16(ipvlan::IFLA_IPVLAN_MODE, self.mode as u16);
builder.append_attr_u16(ipvlan::IFLA_IPVLAN_FLAGS, self.flags as u16);
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct IfbLink {
name: String,
mtu: Option<u32>,
}
impl IfbLink {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
mtu: None,
}
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
}
impl LinkConfig for IfbLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"ifb"
}
fn write_to(&self, builder: &mut MessageBuilder, _parent_index: Option<u32>) {
write_simple_link(builder, &self.name, "ifb", self.mtu, None);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct MacvtapLink {
name: String,
parent: InterfaceRef,
mode: MacvlanMode,
mtu: Option<u32>,
address: Option<[u8; 6]>,
}
impl MacvtapLink {
pub fn new(name: impl Into<String>, parent: impl Into<String>) -> Self {
Self {
name: name.into(),
parent: InterfaceRef::Name(parent.into()),
mode: MacvlanMode::Bridge,
mtu: None,
address: None,
}
}
pub fn with_parent_index(name: impl Into<String>, parent_index: u32) -> Self {
Self {
name: name.into(),
parent: InterfaceRef::Index(parent_index),
mode: MacvlanMode::Bridge,
mtu: None,
address: None,
}
}
pub fn mode(mut self, mode: MacvlanMode) -> Self {
self.mode = mode;
self
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn address(mut self, addr: [u8; 6]) -> Self {
self.address = Some(addr);
self
}
}
impl LinkConfig for MacvtapLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"macvtap"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
Some(&self.parent)
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
let idx = parent_index.expect("MacvtapLink requires parent_index");
builder.append_attr_u32(IflaAttr::Link as u16, idx);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(ref addr) = self.address {
builder.append_attr(IflaAttr::Address as u16, addr);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "macvtap");
let data = builder.nest_start(IflaInfo::Data as u16);
builder.append_attr_u32(macvlan::IFLA_MACVLAN_MODE, self.mode as u32);
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct GeneveLink {
name: String,
vni: u32,
mtu: Option<u32>,
remote: Option<Ipv4Addr>,
remote6: Option<std::net::Ipv6Addr>,
ttl: Option<u8>,
ttl_inherit: bool,
tos: Option<u8>,
df: Option<GeneveDf>,
label: Option<u32>,
port: Option<u16>,
collect_metadata: bool,
udp_csum: Option<bool>,
udp6_zero_csum_tx: Option<bool>,
udp6_zero_csum_rx: Option<bool>,
inner_proto_inherit: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum GeneveDf {
Unset = 0,
Set = 1,
Inherit = 2,
}
mod geneve {
pub const IFLA_GENEVE_ID: u16 = 1;
pub const IFLA_GENEVE_REMOTE: u16 = 2;
pub const IFLA_GENEVE_TTL: u16 = 3;
pub const IFLA_GENEVE_TOS: u16 = 4;
pub const IFLA_GENEVE_PORT: u16 = 5;
pub const IFLA_GENEVE_COLLECT_METADATA: u16 = 6;
pub const IFLA_GENEVE_REMOTE6: u16 = 7;
pub const IFLA_GENEVE_UDP_CSUM: u16 = 8;
pub const IFLA_GENEVE_UDP_ZERO_CSUM6_TX: u16 = 9;
pub const IFLA_GENEVE_UDP_ZERO_CSUM6_RX: u16 = 10;
pub const IFLA_GENEVE_LABEL: u16 = 11;
pub const IFLA_GENEVE_TTL_INHERIT: u16 = 12;
pub const IFLA_GENEVE_DF: u16 = 13;
pub const IFLA_GENEVE_INNER_PROTO_INHERIT: u16 = 14;
}
impl GeneveLink {
pub fn new(name: impl Into<String>, vni: u32) -> Self {
Self {
name: name.into(),
vni,
mtu: None,
remote: None,
remote6: None,
ttl: None,
ttl_inherit: false,
tos: None,
df: None,
label: None,
port: None,
collect_metadata: false,
udp_csum: None,
udp6_zero_csum_tx: None,
udp6_zero_csum_rx: None,
inner_proto_inherit: false,
}
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn remote(mut self, addr: Ipv4Addr) -> Self {
self.remote = Some(addr);
self.remote6 = None;
self
}
pub fn remote6(mut self, addr: std::net::Ipv6Addr) -> Self {
self.remote6 = Some(addr);
self.remote = None;
self
}
pub fn ttl(mut self, ttl: u8) -> Self {
self.ttl = Some(ttl);
self.ttl_inherit = false;
self
}
pub fn ttl_inherit(mut self) -> Self {
self.ttl_inherit = true;
self.ttl = None;
self
}
pub fn tos(mut self, tos: u8) -> Self {
self.tos = Some(tos);
self
}
pub fn df(mut self, df: GeneveDf) -> Self {
self.df = Some(df);
self
}
pub fn label(mut self, label: u32) -> Self {
self.label = Some(label);
self
}
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
pub fn collect_metadata(mut self) -> Self {
self.collect_metadata = true;
self
}
pub fn udp_csum(mut self, enabled: bool) -> Self {
self.udp_csum = Some(enabled);
self
}
pub fn udp6_zero_csum_tx(mut self, enabled: bool) -> Self {
self.udp6_zero_csum_tx = Some(enabled);
self
}
pub fn udp6_zero_csum_rx(mut self, enabled: bool) -> Self {
self.udp6_zero_csum_rx = Some(enabled);
self
}
pub fn inner_proto_inherit(mut self) -> Self {
self.inner_proto_inherit = true;
self
}
}
impl LinkConfig for GeneveLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"geneve"
}
fn write_to(&self, builder: &mut MessageBuilder, _parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "geneve");
let data = builder.nest_start(IflaInfo::Data as u16);
builder.append_attr_u32(geneve::IFLA_GENEVE_ID, self.vni);
if let Some(addr) = self.remote {
builder.append_attr(geneve::IFLA_GENEVE_REMOTE, &addr.octets());
} else if let Some(addr) = self.remote6 {
builder.append_attr(geneve::IFLA_GENEVE_REMOTE6, &addr.octets());
}
if self.ttl_inherit {
builder.append_attr_u8(geneve::IFLA_GENEVE_TTL_INHERIT, 1);
} else if let Some(ttl) = self.ttl {
builder.append_attr_u8(geneve::IFLA_GENEVE_TTL, ttl);
}
if let Some(tos) = self.tos {
builder.append_attr_u8(geneve::IFLA_GENEVE_TOS, tos);
}
if let Some(df) = self.df {
builder.append_attr_u8(geneve::IFLA_GENEVE_DF, df as u8);
}
if let Some(label) = self.label {
builder.append_attr_u32(geneve::IFLA_GENEVE_LABEL, label);
}
if let Some(port) = self.port {
builder.append_attr_u16_be(geneve::IFLA_GENEVE_PORT, port);
}
if self.collect_metadata {
builder.append_attr_empty(geneve::IFLA_GENEVE_COLLECT_METADATA);
}
if let Some(enabled) = self.udp_csum {
builder.append_attr_u8(geneve::IFLA_GENEVE_UDP_CSUM, if enabled { 1 } else { 0 });
}
if let Some(enabled) = self.udp6_zero_csum_tx {
builder.append_attr_u8(
geneve::IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
if enabled { 1 } else { 0 },
);
}
if let Some(enabled) = self.udp6_zero_csum_rx {
builder.append_attr_u8(
geneve::IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
if enabled { 1 } else { 0 },
);
}
if self.inner_proto_inherit {
builder.append_attr_empty(geneve::IFLA_GENEVE_INNER_PROTO_INHERIT);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct BareudpLink {
name: String,
port: u16,
ethertype: u16,
srcport_min: Option<u16>,
multiproto_mode: bool,
mtu: Option<u32>,
}
mod bareudp {
pub const IFLA_BAREUDP_PORT: u16 = 1;
pub const IFLA_BAREUDP_ETHERTYPE: u16 = 2;
pub const IFLA_BAREUDP_SRCPORT_MIN: u16 = 3;
pub const IFLA_BAREUDP_MULTIPROTO_MODE: u16 = 4;
}
impl BareudpLink {
pub fn new(name: impl Into<String>, port: u16, ethertype: u16) -> Self {
Self {
name: name.into(),
port,
ethertype,
srcport_min: None,
multiproto_mode: false,
mtu: None,
}
}
pub fn srcport_min(mut self, port: u16) -> Self {
self.srcport_min = Some(port);
self
}
pub fn multiproto_mode(mut self) -> Self {
self.multiproto_mode = true;
self
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
}
impl LinkConfig for BareudpLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"bareudp"
}
fn write_to(&self, builder: &mut MessageBuilder, _parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "bareudp");
let data = builder.nest_start(IflaInfo::Data as u16);
builder.append_attr_u16_be(bareudp::IFLA_BAREUDP_PORT, self.port);
builder.append_attr_u16_be(bareudp::IFLA_BAREUDP_ETHERTYPE, self.ethertype);
if let Some(srcport) = self.srcport_min {
builder.append_attr_u16(bareudp::IFLA_BAREUDP_SRCPORT_MIN, srcport);
}
if self.multiproto_mode {
builder.append_attr_empty(bareudp::IFLA_BAREUDP_MULTIPROTO_MODE);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct NetkitLink {
name: String,
peer_name: String,
mode: Option<NetkitMode>,
policy: Option<NetkitPolicy>,
peer_policy: Option<NetkitPolicy>,
scrub: Option<NetkitScrub>,
peer_scrub: Option<NetkitScrub>,
mtu: Option<u32>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum NetkitMode {
L2 = 0,
L3 = 1,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum NetkitPolicy {
Forward = 0,
Blackhole = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum NetkitScrub {
None = 0,
Default = 1,
}
mod netkit {
pub const IFLA_NETKIT_PEER_INFO: u16 = 1;
pub const IFLA_NETKIT_MODE: u16 = 4;
pub const IFLA_NETKIT_POLICY: u16 = 2;
pub const IFLA_NETKIT_PEER_POLICY: u16 = 3;
pub const IFLA_NETKIT_SCRUB: u16 = 5;
pub const IFLA_NETKIT_PEER_SCRUB: u16 = 6;
}
impl NetkitLink {
pub fn new(name: impl Into<String>, peer_name: impl Into<String>) -> Self {
Self {
name: name.into(),
peer_name: peer_name.into(),
mode: None,
policy: None,
peer_policy: None,
scrub: None,
peer_scrub: None,
mtu: None,
}
}
pub fn mode(mut self, mode: NetkitMode) -> Self {
self.mode = Some(mode);
self
}
pub fn policy(mut self, policy: NetkitPolicy) -> Self {
self.policy = Some(policy);
self
}
pub fn peer_policy(mut self, policy: NetkitPolicy) -> Self {
self.peer_policy = Some(policy);
self
}
pub fn scrub(mut self, scrub: NetkitScrub) -> Self {
self.scrub = Some(scrub);
self
}
pub fn peer_scrub(mut self, scrub: NetkitScrub) -> Self {
self.peer_scrub = Some(scrub);
self
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
}
impl LinkConfig for NetkitLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"netkit"
}
fn peer_name(&self) -> Option<&str> {
Some(&self.peer_name)
}
fn write_to(&self, builder: &mut MessageBuilder, _parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "netkit");
let data = builder.nest_start(IflaInfo::Data as u16);
if let Some(mode) = self.mode {
builder.append_attr_u32(netkit::IFLA_NETKIT_MODE, mode as u32);
}
if let Some(policy) = self.policy {
builder.append_attr_u32(netkit::IFLA_NETKIT_POLICY, policy as u32);
}
if let Some(policy) = self.peer_policy {
builder.append_attr_u32(netkit::IFLA_NETKIT_PEER_POLICY, policy as u32);
}
if let Some(scrub) = self.scrub {
builder.append_attr_u32(netkit::IFLA_NETKIT_SCRUB, scrub as u32);
}
if let Some(scrub) = self.peer_scrub {
builder.append_attr_u32(netkit::IFLA_NETKIT_PEER_SCRUB, scrub as u32);
}
let peer_info = builder.nest_start(netkit::IFLA_NETKIT_PEER_INFO);
let peer_ifinfo = IfInfoMsg::new();
builder.append(&peer_ifinfo);
builder.append_attr_str(IflaAttr::Ifname as u16, &self.peer_name);
builder.nest_end(peer_info);
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct NlmonLink {
name: String,
}
impl NlmonLink {
pub fn new(name: impl Into<String>) -> Self {
Self { name: name.into() }
}
}
impl LinkConfig for NlmonLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"nlmon"
}
fn write_to(&self, builder: &mut MessageBuilder, _parent_index: Option<u32>) {
write_simple_link(builder, &self.name, "nlmon", None, None);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct VirtWifiLink {
name: String,
link: InterfaceRef,
}
impl VirtWifiLink {
pub fn new(name: impl Into<String>, link: impl Into<String>) -> Self {
Self {
name: name.into(),
link: InterfaceRef::Name(link.into()),
}
}
pub fn with_link_index(name: impl Into<String>, link_index: u32) -> Self {
Self {
name: name.into(),
link: InterfaceRef::Index(link_index),
}
}
}
impl LinkConfig for VirtWifiLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"virt_wifi"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
Some(&self.link)
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
let idx = parent_index.expect("VirtWifiLink requires link index");
builder.append_attr_u32(IflaAttr::Link as u16, idx);
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "virt_wifi");
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct VtiLink {
name: String,
local: Option<Ipv4Addr>,
remote: Option<Ipv4Addr>,
ikey: Option<u32>,
okey: Option<u32>,
link: Option<InterfaceRef>,
}
#[allow(dead_code)]
mod vti {
pub const IFLA_VTI_LINK: u16 = 1;
pub const IFLA_VTI_IKEY: u16 = 2;
pub const IFLA_VTI_OKEY: u16 = 3;
pub const IFLA_VTI_LOCAL: u16 = 4;
pub const IFLA_VTI_REMOTE: u16 = 5;
pub const IFLA_VTI_FWMARK: u16 = 6;
}
impl VtiLink {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
local: None,
remote: None,
ikey: None,
okey: None,
link: None,
}
}
pub fn local(mut self, addr: Ipv4Addr) -> Self {
self.local = Some(addr);
self
}
pub fn remote(mut self, addr: Ipv4Addr) -> Self {
self.remote = Some(addr);
self
}
pub fn ikey(mut self, key: u32) -> Self {
self.ikey = Some(key);
self
}
pub fn okey(mut self, key: u32) -> Self {
self.okey = Some(key);
self
}
pub fn link(mut self, link: impl Into<String>) -> Self {
self.link = Some(InterfaceRef::Name(link.into()));
self
}
pub fn link_index(mut self, index: u32) -> Self {
self.link = Some(InterfaceRef::Index(index));
self
}
}
impl LinkConfig for VtiLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"vti"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
self.link.as_ref()
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(idx) = parent_index {
builder.append_attr_u32(IflaAttr::Link as u16, idx);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "vti");
let data = builder.nest_start(IflaInfo::Data as u16);
if let Some(local) = self.local {
builder.append_attr(vti::IFLA_VTI_LOCAL, &local.octets());
}
if let Some(remote) = self.remote {
builder.append_attr(vti::IFLA_VTI_REMOTE, &remote.octets());
}
if let Some(ikey) = self.ikey {
builder.append_attr_u32_be(vti::IFLA_VTI_IKEY, ikey);
}
if let Some(okey) = self.okey {
builder.append_attr_u32_be(vti::IFLA_VTI_OKEY, okey);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct Vti6Link {
name: String,
local: Option<std::net::Ipv6Addr>,
remote: Option<std::net::Ipv6Addr>,
ikey: Option<u32>,
okey: Option<u32>,
link: Option<InterfaceRef>,
}
impl Vti6Link {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
local: None,
remote: None,
ikey: None,
okey: None,
link: None,
}
}
pub fn local(mut self, addr: std::net::Ipv6Addr) -> Self {
self.local = Some(addr);
self
}
pub fn remote(mut self, addr: std::net::Ipv6Addr) -> Self {
self.remote = Some(addr);
self
}
pub fn ikey(mut self, key: u32) -> Self {
self.ikey = Some(key);
self
}
pub fn okey(mut self, key: u32) -> Self {
self.okey = Some(key);
self
}
pub fn link(mut self, link: impl Into<String>) -> Self {
self.link = Some(InterfaceRef::Name(link.into()));
self
}
pub fn link_index(mut self, index: u32) -> Self {
self.link = Some(InterfaceRef::Index(index));
self
}
}
impl LinkConfig for Vti6Link {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"vti6"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
self.link.as_ref()
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(idx) = parent_index {
builder.append_attr_u32(IflaAttr::Link as u16, idx);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "vti6");
let data = builder.nest_start(IflaInfo::Data as u16);
if let Some(local) = self.local {
builder.append_attr(vti::IFLA_VTI_LOCAL, &local.octets());
}
if let Some(remote) = self.remote {
builder.append_attr(vti::IFLA_VTI_REMOTE, &remote.octets());
}
if let Some(ikey) = self.ikey {
builder.append_attr_u32_be(vti::IFLA_VTI_IKEY, ikey);
}
if let Some(okey) = self.okey {
builder.append_attr_u32_be(vti::IFLA_VTI_OKEY, okey);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct Ip6GreLink {
name: String,
local: Option<std::net::Ipv6Addr>,
remote: Option<std::net::Ipv6Addr>,
ttl: Option<u8>,
encap_limit: Option<u8>,
flowinfo: Option<u32>,
flags: Option<u32>,
link: Option<InterfaceRef>,
}
#[allow(dead_code)]
mod gre_attr {
pub const IFLA_GRE_LINK: u16 = 1;
pub const IFLA_GRE_IFLAGS: u16 = 2;
pub const IFLA_GRE_OFLAGS: u16 = 3;
pub const IFLA_GRE_IKEY: u16 = 4;
pub const IFLA_GRE_OKEY: u16 = 5;
pub const IFLA_GRE_LOCAL: u16 = 6;
pub const IFLA_GRE_REMOTE: u16 = 7;
pub const IFLA_GRE_TTL: u16 = 8;
pub const IFLA_GRE_TOS: u16 = 9;
pub const IFLA_GRE_PMTUDISC: u16 = 10;
pub const IFLA_GRE_ENCAP_LIMIT: u16 = 11;
pub const IFLA_GRE_FLOWINFO: u16 = 12;
pub const IFLA_GRE_FLAGS: u16 = 13;
pub const IFLA_GRE_ENCAP_TYPE: u16 = 14;
pub const IFLA_GRE_ENCAP_FLAGS: u16 = 15;
pub const IFLA_GRE_ENCAP_SPORT: u16 = 16;
pub const IFLA_GRE_ENCAP_DPORT: u16 = 17;
pub const IFLA_GRE_COLLECT_METADATA: u16 = 18;
pub const IFLA_GRE_IGNORE_DF: u16 = 19;
pub const IFLA_GRE_FWMARK: u16 = 20;
pub const GRE_KEY: u16 = 0x2000;
}
#[allow(dead_code)]
mod iptun_attr {
pub const IFLA_IPTUN_LINK: u16 = 1;
pub const IFLA_IPTUN_LOCAL: u16 = 2;
pub const IFLA_IPTUN_REMOTE: u16 = 3;
pub const IFLA_IPTUN_TTL: u16 = 4;
pub const IFLA_IPTUN_TOS: u16 = 5;
pub const IFLA_IPTUN_ENCAP_LIMIT: u16 = 6;
pub const IFLA_IPTUN_FLOWINFO: u16 = 7;
pub const IFLA_IPTUN_FLAGS: u16 = 8;
pub const IFLA_IPTUN_PROTO: u16 = 9;
pub const IFLA_IPTUN_PMTUDISC: u16 = 10;
pub const IFLA_IPTUN_ENCAP_TYPE: u16 = 15;
pub const IFLA_IPTUN_ENCAP_FLAGS: u16 = 16;
pub const IFLA_IPTUN_ENCAP_SPORT: u16 = 17;
pub const IFLA_IPTUN_ENCAP_DPORT: u16 = 18;
pub const IFLA_IPTUN_COLLECT_METADATA: u16 = 19;
pub const IFLA_IPTUN_FWMARK: u16 = 20;
pub const SIT_ISATAP: u16 = 0x0001;
}
impl Ip6GreLink {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
local: None,
remote: None,
ttl: None,
encap_limit: None,
flowinfo: None,
flags: None,
link: None,
}
}
pub fn local(mut self, addr: std::net::Ipv6Addr) -> Self {
self.local = Some(addr);
self
}
pub fn remote(mut self, addr: std::net::Ipv6Addr) -> Self {
self.remote = Some(addr);
self
}
pub fn ttl(mut self, ttl: u8) -> Self {
self.ttl = Some(ttl);
self
}
pub fn encap_limit(mut self, limit: u8) -> Self {
self.encap_limit = Some(limit);
self
}
pub fn flowinfo(mut self, flowinfo: u32) -> Self {
self.flowinfo = Some(flowinfo);
self
}
pub fn link(mut self, link: impl Into<String>) -> Self {
self.link = Some(InterfaceRef::Name(link.into()));
self
}
pub fn link_index(mut self, index: u32) -> Self {
self.link = Some(InterfaceRef::Index(index));
self
}
}
impl LinkConfig for Ip6GreLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"ip6gre"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
self.link.as_ref()
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "ip6gre");
let data = builder.nest_start(IflaInfo::Data as u16);
if let Some(idx) = parent_index {
builder.append_attr_u32(gre_attr::IFLA_GRE_LINK, idx);
}
if let Some(local) = self.local {
builder.append_attr(gre_attr::IFLA_GRE_LOCAL, &local.octets());
}
if let Some(remote) = self.remote {
builder.append_attr(gre_attr::IFLA_GRE_REMOTE, &remote.octets());
}
if let Some(ttl) = self.ttl {
builder.append_attr_u8(gre_attr::IFLA_GRE_TTL, ttl);
}
if let Some(limit) = self.encap_limit {
builder.append_attr_u8(gre_attr::IFLA_GRE_ENCAP_LIMIT, limit);
}
if let Some(flowinfo) = self.flowinfo {
builder.append_attr_u32_be(gre_attr::IFLA_GRE_FLOWINFO, flowinfo);
}
if let Some(flags) = self.flags {
builder.append_attr_u32(gre_attr::IFLA_GRE_FLAGS, flags);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct Ip6GretapLink {
name: String,
local: Option<std::net::Ipv6Addr>,
remote: Option<std::net::Ipv6Addr>,
ttl: Option<u8>,
encap_limit: Option<u8>,
flowinfo: Option<u32>,
link: Option<InterfaceRef>,
}
impl Ip6GretapLink {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
local: None,
remote: None,
ttl: None,
encap_limit: None,
flowinfo: None,
link: None,
}
}
pub fn local(mut self, addr: std::net::Ipv6Addr) -> Self {
self.local = Some(addr);
self
}
pub fn remote(mut self, addr: std::net::Ipv6Addr) -> Self {
self.remote = Some(addr);
self
}
pub fn ttl(mut self, ttl: u8) -> Self {
self.ttl = Some(ttl);
self
}
pub fn encap_limit(mut self, limit: u8) -> Self {
self.encap_limit = Some(limit);
self
}
pub fn flowinfo(mut self, flowinfo: u32) -> Self {
self.flowinfo = Some(flowinfo);
self
}
pub fn link(mut self, link: impl Into<String>) -> Self {
self.link = Some(InterfaceRef::Name(link.into()));
self
}
pub fn link_index(mut self, index: u32) -> Self {
self.link = Some(InterfaceRef::Index(index));
self
}
}
impl LinkConfig for Ip6GretapLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"ip6gretap"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
self.link.as_ref()
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "ip6gretap");
let data = builder.nest_start(IflaInfo::Data as u16);
if let Some(idx) = parent_index {
builder.append_attr_u32(gre_attr::IFLA_GRE_LINK, idx);
}
if let Some(local) = self.local {
builder.append_attr(gre_attr::IFLA_GRE_LOCAL, &local.octets());
}
if let Some(remote) = self.remote {
builder.append_attr(gre_attr::IFLA_GRE_REMOTE, &remote.octets());
}
if let Some(ttl) = self.ttl {
builder.append_attr_u8(gre_attr::IFLA_GRE_TTL, ttl);
}
if let Some(limit) = self.encap_limit {
builder.append_attr_u8(gre_attr::IFLA_GRE_ENCAP_LIMIT, limit);
}
if let Some(flowinfo) = self.flowinfo {
builder.append_attr_u32_be(gre_attr::IFLA_GRE_FLOWINFO, flowinfo);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
#[non_exhaustive]
pub enum BondMode {
BalanceRr = 0,
ActiveBackup = 1,
BalanceXor = 2,
Broadcast = 3,
Lacp = 4,
BalanceTlb = 5,
BalanceAlb = 6,
}
impl TryFrom<u8> for BondMode {
type Error = super::Error;
fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
match value {
0 => Ok(Self::BalanceRr),
1 => Ok(Self::ActiveBackup),
2 => Ok(Self::BalanceXor),
3 => Ok(Self::Broadcast),
4 => Ok(Self::Lacp),
5 => Ok(Self::BalanceTlb),
6 => Ok(Self::BalanceAlb),
_ => Err(super::Error::InvalidAttribute(format!(
"unknown bond mode: {value}"
))),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
#[non_exhaustive]
pub enum XmitHashPolicy {
Layer2 = 0,
Layer34 = 1,
Layer23 = 2,
Encap23 = 3,
Encap34 = 4,
VlanSrcMac = 5,
}
impl TryFrom<u8> for XmitHashPolicy {
type Error = super::Error;
fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
match value {
0 => Ok(Self::Layer2),
1 => Ok(Self::Layer34),
2 => Ok(Self::Layer23),
3 => Ok(Self::Encap23),
4 => Ok(Self::Encap34),
5 => Ok(Self::VlanSrcMac),
_ => Err(super::Error::InvalidAttribute(format!(
"unknown xmit hash policy: {value}"
))),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
#[non_exhaustive]
pub enum LacpRate {
Slow = 0,
Fast = 1,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
#[non_exhaustive]
pub enum PrimaryReselect {
Always = 0,
Better = 1,
Failure = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
#[non_exhaustive]
pub enum FailOverMac {
None = 0,
Active = 1,
Follow = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
#[non_exhaustive]
pub enum ArpValidate {
None = 0,
Active = 1,
Backup = 2,
All = 3,
FilterActive = 4,
FilterBackup = 5,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
#[non_exhaustive]
pub enum AdSelect {
Stable = 0,
Bandwidth = 1,
Count = 2,
}
#[allow(dead_code)]
mod bond_attr {
pub const IFLA_BOND_MODE: u16 = 1;
pub const IFLA_BOND_ACTIVE_SLAVE: u16 = 2;
pub const IFLA_BOND_MIIMON: u16 = 3;
pub const IFLA_BOND_UPDELAY: u16 = 4;
pub const IFLA_BOND_DOWNDELAY: u16 = 5;
pub const IFLA_BOND_USE_CARRIER: u16 = 6;
pub const IFLA_BOND_ARP_INTERVAL: u16 = 7;
pub const IFLA_BOND_ARP_IP_TARGET: u16 = 8;
pub const IFLA_BOND_ARP_VALIDATE: u16 = 9;
pub const IFLA_BOND_ARP_ALL_TARGETS: u16 = 10;
pub const IFLA_BOND_PRIMARY: u16 = 11;
pub const IFLA_BOND_PRIMARY_RESELECT: u16 = 12;
pub const IFLA_BOND_FAIL_OVER_MAC: u16 = 13;
pub const IFLA_BOND_XMIT_HASH_POLICY: u16 = 14;
pub const IFLA_BOND_RESEND_IGMP: u16 = 15;
pub const IFLA_BOND_NUM_PEER_NOTIF: u16 = 16;
pub const IFLA_BOND_ALL_SLAVES_ACTIVE: u16 = 17;
pub const IFLA_BOND_MIN_LINKS: u16 = 18;
pub const IFLA_BOND_LP_INTERVAL: u16 = 19;
pub const IFLA_BOND_PACKETS_PER_SLAVE: u16 = 20;
pub const IFLA_BOND_AD_LACP_RATE: u16 = 21;
pub const IFLA_BOND_AD_SELECT: u16 = 22;
pub const IFLA_BOND_AD_INFO: u16 = 23;
pub const IFLA_BOND_AD_ACTOR_SYS_PRIO: u16 = 24;
pub const IFLA_BOND_AD_USER_PORT_KEY: u16 = 25;
pub const IFLA_BOND_AD_ACTOR_SYSTEM: u16 = 26;
pub const IFLA_BOND_TLB_DYNAMIC_LB: u16 = 27;
pub const IFLA_BOND_PEER_NOTIF_DELAY: u16 = 28;
pub const IFLA_BOND_AD_LACP_ACTIVE: u16 = 29;
pub const IFLA_BOND_MISSED_MAX: u16 = 30;
pub const IFLA_BOND_NS_IP6_TARGET: u16 = 31;
pub const IFLA_BOND_COUPLED_CONTROL: u16 = 32;
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct BondLink {
name: String,
mode: BondMode,
mtu: Option<u32>,
address: Option<[u8; 6]>,
miimon: Option<u32>,
updelay: Option<u32>,
downdelay: Option<u32>,
use_carrier: Option<bool>,
arp_interval: Option<u32>,
arp_ip_targets: Vec<Ipv4Addr>,
arp_validate: Option<ArpValidate>,
arp_all_targets: Option<u32>,
primary_reselect: Option<PrimaryReselect>,
fail_over_mac: Option<FailOverMac>,
xmit_hash_policy: Option<XmitHashPolicy>,
min_links: Option<u32>,
packets_per_slave: Option<u32>,
lacp_rate: Option<LacpRate>,
ad_select: Option<AdSelect>,
ad_actor_sys_prio: Option<u16>,
ad_user_port_key: Option<u16>,
ad_actor_system: Option<[u8; 6]>,
lacp_active: Option<bool>,
all_slaves_active: Option<bool>,
resend_igmp: Option<u32>,
num_peer_notif: Option<u8>,
lp_interval: Option<u32>,
tlb_dynamic_lb: Option<bool>,
peer_notif_delay: Option<u32>,
missed_max: Option<u8>,
coupled_control: Option<bool>,
}
impl BondLink {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
mode: BondMode::BalanceRr,
mtu: None,
address: None,
miimon: None,
updelay: None,
downdelay: None,
use_carrier: None,
arp_interval: None,
arp_ip_targets: Vec::new(),
arp_validate: None,
arp_all_targets: None,
primary_reselect: None,
fail_over_mac: None,
xmit_hash_policy: None,
min_links: None,
packets_per_slave: None,
lacp_rate: None,
ad_select: None,
ad_actor_sys_prio: None,
ad_user_port_key: None,
ad_actor_system: None,
lacp_active: None,
all_slaves_active: None,
resend_igmp: None,
num_peer_notif: None,
lp_interval: None,
tlb_dynamic_lb: None,
peer_notif_delay: None,
missed_max: None,
coupled_control: None,
}
}
pub fn mode(mut self, mode: BondMode) -> Self {
self.mode = mode;
self
}
pub fn miimon(mut self, ms: u32) -> Self {
self.miimon = Some(ms);
self
}
pub fn updelay(mut self, ms: u32) -> Self {
self.updelay = Some(ms);
self
}
pub fn downdelay(mut self, ms: u32) -> Self {
self.downdelay = Some(ms);
self
}
pub fn use_carrier(mut self, enabled: bool) -> Self {
self.use_carrier = Some(enabled);
self
}
pub fn min_links(mut self, n: u32) -> Self {
self.min_links = Some(n);
self
}
pub fn xmit_hash_policy(mut self, policy: XmitHashPolicy) -> Self {
self.xmit_hash_policy = Some(policy);
self
}
pub fn lacp_rate(mut self, rate: LacpRate) -> Self {
self.lacp_rate = Some(rate);
self
}
pub fn ad_select(mut self, select: AdSelect) -> Self {
self.ad_select = Some(select);
self
}
pub fn arp_interval(mut self, ms: u32) -> Self {
self.arp_interval = Some(ms);
self
}
pub fn arp_ip_target(mut self, addr: Ipv4Addr) -> Self {
self.arp_ip_targets.push(addr);
self
}
pub fn arp_validate(mut self, validate: ArpValidate) -> Self {
self.arp_validate = Some(validate);
self
}
pub fn primary_reselect(mut self, policy: PrimaryReselect) -> Self {
self.primary_reselect = Some(policy);
self
}
pub fn fail_over_mac(mut self, policy: FailOverMac) -> Self {
self.fail_over_mac = Some(policy);
self
}
pub fn all_slaves_active(mut self, enabled: bool) -> Self {
self.all_slaves_active = Some(enabled);
self
}
pub fn tlb_dynamic_lb(mut self, enabled: bool) -> Self {
self.tlb_dynamic_lb = Some(enabled);
self
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn address(mut self, address: [u8; 6]) -> Self {
self.address = Some(address);
self
}
pub fn ad_actor_sys_prio(mut self, prio: u16) -> Self {
self.ad_actor_sys_prio = Some(prio);
self
}
pub fn ad_user_port_key(mut self, key: u16) -> Self {
self.ad_user_port_key = Some(key);
self
}
pub fn ad_actor_system(mut self, mac: [u8; 6]) -> Self {
self.ad_actor_system = Some(mac);
self
}
pub fn lacp_active(mut self, enabled: bool) -> Self {
self.lacp_active = Some(enabled);
self
}
pub fn num_peer_notif(mut self, n: u8) -> Self {
self.num_peer_notif = Some(n);
self
}
pub fn resend_igmp(mut self, count: u32) -> Self {
self.resend_igmp = Some(count);
self
}
pub fn lp_interval(mut self, ms: u32) -> Self {
self.lp_interval = Some(ms);
self
}
pub fn packets_per_slave(mut self, n: u32) -> Self {
self.packets_per_slave = Some(n);
self
}
pub fn peer_notif_delay(mut self, ms: u32) -> Self {
self.peer_notif_delay = Some(ms);
self
}
pub fn missed_max(mut self, n: u8) -> Self {
self.missed_max = Some(n);
self
}
pub fn coupled_control(mut self, enabled: bool) -> Self {
self.coupled_control = Some(enabled);
self
}
}
impl LinkConfig for BondLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"bond"
}
fn write_to(&self, builder: &mut MessageBuilder, _parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(ref addr) = self.address {
builder.append_attr(IflaAttr::Address as u16, addr);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "bond");
let data = builder.nest_start(IflaInfo::Data as u16);
builder.append_attr_u8(bond_attr::IFLA_BOND_MODE, self.mode as u8);
if let Some(v) = self.miimon {
builder.append_attr_u32(bond_attr::IFLA_BOND_MIIMON, v);
}
if let Some(v) = self.updelay {
builder.append_attr_u32(bond_attr::IFLA_BOND_UPDELAY, v);
}
if let Some(v) = self.downdelay {
builder.append_attr_u32(bond_attr::IFLA_BOND_DOWNDELAY, v);
}
if let Some(v) = self.use_carrier {
builder.append_attr_u8(bond_attr::IFLA_BOND_USE_CARRIER, v as u8);
}
if let Some(v) = self.arp_interval {
builder.append_attr_u32(bond_attr::IFLA_BOND_ARP_INTERVAL, v);
}
if let Some(v) = self.arp_validate {
builder.append_attr_u32(bond_attr::IFLA_BOND_ARP_VALIDATE, v as u32);
}
if let Some(v) = self.arp_all_targets {
builder.append_attr_u32(bond_attr::IFLA_BOND_ARP_ALL_TARGETS, v);
}
if let Some(v) = self.primary_reselect {
builder.append_attr_u8(bond_attr::IFLA_BOND_PRIMARY_RESELECT, v as u8);
}
if let Some(v) = self.fail_over_mac {
builder.append_attr_u8(bond_attr::IFLA_BOND_FAIL_OVER_MAC, v as u8);
}
if let Some(v) = self.xmit_hash_policy {
builder.append_attr_u8(bond_attr::IFLA_BOND_XMIT_HASH_POLICY, v as u8);
}
if let Some(v) = self.resend_igmp {
builder.append_attr_u32(bond_attr::IFLA_BOND_RESEND_IGMP, v);
}
if let Some(v) = self.num_peer_notif {
builder.append_attr_u8(bond_attr::IFLA_BOND_NUM_PEER_NOTIF, v);
}
if let Some(v) = self.all_slaves_active {
builder.append_attr_u8(bond_attr::IFLA_BOND_ALL_SLAVES_ACTIVE, v as u8);
}
if let Some(v) = self.min_links {
builder.append_attr_u32(bond_attr::IFLA_BOND_MIN_LINKS, v);
}
if let Some(v) = self.lp_interval {
builder.append_attr_u32(bond_attr::IFLA_BOND_LP_INTERVAL, v);
}
if let Some(v) = self.packets_per_slave {
builder.append_attr_u32(bond_attr::IFLA_BOND_PACKETS_PER_SLAVE, v);
}
if let Some(v) = self.lacp_rate {
builder.append_attr_u8(bond_attr::IFLA_BOND_AD_LACP_RATE, v as u8);
}
if let Some(v) = self.ad_select {
builder.append_attr_u8(bond_attr::IFLA_BOND_AD_SELECT, v as u8);
}
if let Some(v) = self.ad_actor_sys_prio {
builder.append_attr_u16(bond_attr::IFLA_BOND_AD_ACTOR_SYS_PRIO, v);
}
if let Some(v) = self.ad_user_port_key {
builder.append_attr_u16(bond_attr::IFLA_BOND_AD_USER_PORT_KEY, v);
}
if let Some(ref mac) = self.ad_actor_system {
builder.append_attr(bond_attr::IFLA_BOND_AD_ACTOR_SYSTEM, mac);
}
if let Some(v) = self.tlb_dynamic_lb {
builder.append_attr_u8(bond_attr::IFLA_BOND_TLB_DYNAMIC_LB, v as u8);
}
if let Some(v) = self.peer_notif_delay {
builder.append_attr_u32(bond_attr::IFLA_BOND_PEER_NOTIF_DELAY, v);
}
if let Some(v) = self.lacp_active {
builder.append_attr_u8(bond_attr::IFLA_BOND_AD_LACP_ACTIVE, v as u8);
}
if let Some(v) = self.missed_max {
builder.append_attr_u8(bond_attr::IFLA_BOND_MISSED_MAX, v);
}
if let Some(v) = self.coupled_control {
builder.append_attr_u8(bond_attr::IFLA_BOND_COUPLED_CONTROL, v as u8);
}
if !self.arp_ip_targets.is_empty() {
let targets = builder.nest_start(bond_attr::IFLA_BOND_ARP_IP_TARGET);
for (i, addr) in self.arp_ip_targets.iter().enumerate() {
builder.append_attr(i as u16, &addr.octets());
}
builder.nest_end(targets);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
mod vrf_attr {
pub const IFLA_VRF_TABLE: u16 = 1;
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct VrfLink {
name: String,
table: u32,
mtu: Option<u32>,
}
impl VrfLink {
pub fn new(name: &str, table: u32) -> Self {
Self {
name: name.to_string(),
table,
mtu: None,
}
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
}
impl LinkConfig for VrfLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"vrf"
}
fn write_to(&self, builder: &mut MessageBuilder, _parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "vrf");
let data = builder.nest_start(IflaInfo::Data as u16);
builder.append_attr_u32(vrf_attr::IFLA_VRF_TABLE, self.table);
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct GreLink {
name: String,
local: Option<Ipv4Addr>,
remote: Option<Ipv4Addr>,
ttl: Option<u8>,
tos: Option<u8>,
ikey: Option<u32>,
okey: Option<u32>,
pmtudisc: Option<bool>,
ignore_df: Option<bool>,
fwmark: Option<u32>,
mtu: Option<u32>,
link: Option<InterfaceRef>,
}
impl GreLink {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
local: None,
remote: None,
ttl: None,
tos: None,
ikey: None,
okey: None,
pmtudisc: None,
ignore_df: None,
fwmark: None,
mtu: None,
link: None,
}
}
pub fn local(mut self, addr: Ipv4Addr) -> Self {
self.local = Some(addr);
self
}
pub fn remote(mut self, addr: Ipv4Addr) -> Self {
self.remote = Some(addr);
self
}
pub fn ttl(mut self, ttl: u8) -> Self {
self.ttl = Some(ttl);
self
}
pub fn tos(mut self, tos: u8) -> Self {
self.tos = Some(tos);
self
}
pub fn ikey(mut self, key: u32) -> Self {
self.ikey = Some(key);
self
}
pub fn okey(mut self, key: u32) -> Self {
self.okey = Some(key);
self
}
pub fn key(self, key: u32) -> Self {
self.ikey(key).okey(key)
}
pub fn pmtudisc(mut self, enabled: bool) -> Self {
self.pmtudisc = Some(enabled);
self
}
pub fn ignore_df(mut self, enabled: bool) -> Self {
self.ignore_df = Some(enabled);
self
}
pub fn fwmark(mut self, mark: u32) -> Self {
self.fwmark = Some(mark);
self
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn link(mut self, iface: impl Into<String>) -> Self {
self.link = Some(InterfaceRef::Name(iface.into()));
self
}
pub fn link_index(mut self, index: u32) -> Self {
self.link = Some(InterfaceRef::Index(index));
self
}
}
impl LinkConfig for GreLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"gre"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
self.link.as_ref()
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(idx) = parent_index {
builder.append_attr_u32(IflaAttr::Link as u16, idx);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "gre");
let data = builder.nest_start(IflaInfo::Data as u16);
if let Some(addr) = self.local {
builder.append_attr(gre_attr::IFLA_GRE_LOCAL, &addr.octets());
}
if let Some(addr) = self.remote {
builder.append_attr(gre_attr::IFLA_GRE_REMOTE, &addr.octets());
}
if let Some(ttl) = self.ttl {
builder.append_attr_u8(gre_attr::IFLA_GRE_TTL, ttl);
}
if let Some(tos) = self.tos {
builder.append_attr_u8(gre_attr::IFLA_GRE_TOS, tos);
}
if let Some(key) = self.ikey {
builder.append_attr_u16(gre_attr::IFLA_GRE_IFLAGS, gre_attr::GRE_KEY);
builder.append_attr_u32(gre_attr::IFLA_GRE_IKEY, key);
}
if let Some(key) = self.okey {
builder.append_attr_u16(gre_attr::IFLA_GRE_OFLAGS, gre_attr::GRE_KEY);
builder.append_attr_u32(gre_attr::IFLA_GRE_OKEY, key);
}
if let Some(pmtu) = self.pmtudisc {
builder.append_attr_u8(gre_attr::IFLA_GRE_PMTUDISC, pmtu as u8);
}
if let Some(ignore) = self.ignore_df {
builder.append_attr_u8(gre_attr::IFLA_GRE_IGNORE_DF, ignore as u8);
}
if let Some(mark) = self.fwmark {
builder.append_attr_u32(gre_attr::IFLA_GRE_FWMARK, mark);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct GretapLink {
name: String,
local: Option<Ipv4Addr>,
remote: Option<Ipv4Addr>,
ttl: Option<u8>,
tos: Option<u8>,
ikey: Option<u32>,
okey: Option<u32>,
pmtudisc: Option<bool>,
fwmark: Option<u32>,
mtu: Option<u32>,
link: Option<InterfaceRef>,
}
impl GretapLink {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
local: None,
remote: None,
ttl: None,
tos: None,
ikey: None,
okey: None,
pmtudisc: None,
fwmark: None,
mtu: None,
link: None,
}
}
pub fn local(mut self, addr: Ipv4Addr) -> Self {
self.local = Some(addr);
self
}
pub fn remote(mut self, addr: Ipv4Addr) -> Self {
self.remote = Some(addr);
self
}
pub fn ttl(mut self, ttl: u8) -> Self {
self.ttl = Some(ttl);
self
}
pub fn tos(mut self, tos: u8) -> Self {
self.tos = Some(tos);
self
}
pub fn ikey(mut self, key: u32) -> Self {
self.ikey = Some(key);
self
}
pub fn okey(mut self, key: u32) -> Self {
self.okey = Some(key);
self
}
pub fn key(self, key: u32) -> Self {
self.ikey(key).okey(key)
}
pub fn pmtudisc(mut self, enabled: bool) -> Self {
self.pmtudisc = Some(enabled);
self
}
pub fn fwmark(mut self, mark: u32) -> Self {
self.fwmark = Some(mark);
self
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn link(mut self, iface: impl Into<String>) -> Self {
self.link = Some(InterfaceRef::Name(iface.into()));
self
}
pub fn link_index(mut self, index: u32) -> Self {
self.link = Some(InterfaceRef::Index(index));
self
}
}
impl LinkConfig for GretapLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"gretap"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
self.link.as_ref()
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(idx) = parent_index {
builder.append_attr_u32(IflaAttr::Link as u16, idx);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "gretap");
let data = builder.nest_start(IflaInfo::Data as u16);
if let Some(addr) = self.local {
builder.append_attr(gre_attr::IFLA_GRE_LOCAL, &addr.octets());
}
if let Some(addr) = self.remote {
builder.append_attr(gre_attr::IFLA_GRE_REMOTE, &addr.octets());
}
if let Some(ttl) = self.ttl {
builder.append_attr_u8(gre_attr::IFLA_GRE_TTL, ttl);
}
if let Some(tos) = self.tos {
builder.append_attr_u8(gre_attr::IFLA_GRE_TOS, tos);
}
if let Some(key) = self.ikey {
builder.append_attr_u16(gre_attr::IFLA_GRE_IFLAGS, gre_attr::GRE_KEY);
builder.append_attr_u32(gre_attr::IFLA_GRE_IKEY, key);
}
if let Some(key) = self.okey {
builder.append_attr_u16(gre_attr::IFLA_GRE_OFLAGS, gre_attr::GRE_KEY);
builder.append_attr_u32(gre_attr::IFLA_GRE_OKEY, key);
}
if let Some(pmtu) = self.pmtudisc {
builder.append_attr_u8(gre_attr::IFLA_GRE_PMTUDISC, pmtu as u8);
}
if let Some(mark) = self.fwmark {
builder.append_attr_u32(gre_attr::IFLA_GRE_FWMARK, mark);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct IpipLink {
name: String,
local: Option<Ipv4Addr>,
remote: Option<Ipv4Addr>,
ttl: Option<u8>,
tos: Option<u8>,
pmtudisc: Option<bool>,
fwmark: Option<u32>,
mtu: Option<u32>,
link: Option<InterfaceRef>,
}
impl IpipLink {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
local: None,
remote: None,
ttl: None,
tos: None,
pmtudisc: None,
fwmark: None,
mtu: None,
link: None,
}
}
pub fn local(mut self, addr: Ipv4Addr) -> Self {
self.local = Some(addr);
self
}
pub fn remote(mut self, addr: Ipv4Addr) -> Self {
self.remote = Some(addr);
self
}
pub fn ttl(mut self, ttl: u8) -> Self {
self.ttl = Some(ttl);
self
}
pub fn tos(mut self, tos: u8) -> Self {
self.tos = Some(tos);
self
}
pub fn pmtudisc(mut self, enabled: bool) -> Self {
self.pmtudisc = Some(enabled);
self
}
pub fn fwmark(mut self, mark: u32) -> Self {
self.fwmark = Some(mark);
self
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn link(mut self, iface: impl Into<String>) -> Self {
self.link = Some(InterfaceRef::Name(iface.into()));
self
}
pub fn link_index(mut self, index: u32) -> Self {
self.link = Some(InterfaceRef::Index(index));
self
}
}
impl LinkConfig for IpipLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"ipip"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
self.link.as_ref()
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(idx) = parent_index {
builder.append_attr_u32(IflaAttr::Link as u16, idx);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "ipip");
let data = builder.nest_start(IflaInfo::Data as u16);
if let Some(addr) = self.local {
builder.append_attr(iptun_attr::IFLA_IPTUN_LOCAL, &addr.octets());
}
if let Some(addr) = self.remote {
builder.append_attr(iptun_attr::IFLA_IPTUN_REMOTE, &addr.octets());
}
if let Some(ttl) = self.ttl {
builder.append_attr_u8(iptun_attr::IFLA_IPTUN_TTL, ttl);
}
if let Some(tos) = self.tos {
builder.append_attr_u8(iptun_attr::IFLA_IPTUN_TOS, tos);
}
if let Some(pmtu) = self.pmtudisc {
builder.append_attr_u8(iptun_attr::IFLA_IPTUN_PMTUDISC, pmtu as u8);
}
if let Some(mark) = self.fwmark {
builder.append_attr_u32(iptun_attr::IFLA_IPTUN_FWMARK, mark);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct SitLink {
name: String,
local: Option<Ipv4Addr>,
remote: Option<Ipv4Addr>,
ttl: Option<u8>,
tos: Option<u8>,
pmtudisc: Option<bool>,
fwmark: Option<u32>,
isatap: bool,
mtu: Option<u32>,
link: Option<InterfaceRef>,
}
impl SitLink {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
local: None,
remote: None,
ttl: None,
tos: None,
pmtudisc: None,
fwmark: None,
isatap: false,
mtu: None,
link: None,
}
}
pub fn local(mut self, addr: Ipv4Addr) -> Self {
self.local = Some(addr);
self
}
pub fn remote(mut self, addr: Ipv4Addr) -> Self {
self.remote = Some(addr);
self
}
pub fn ttl(mut self, ttl: u8) -> Self {
self.ttl = Some(ttl);
self
}
pub fn tos(mut self, tos: u8) -> Self {
self.tos = Some(tos);
self
}
pub fn pmtudisc(mut self, enabled: bool) -> Self {
self.pmtudisc = Some(enabled);
self
}
pub fn fwmark(mut self, mark: u32) -> Self {
self.fwmark = Some(mark);
self
}
pub fn isatap(mut self) -> Self {
self.isatap = true;
self
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn link(mut self, iface: impl Into<String>) -> Self {
self.link = Some(InterfaceRef::Name(iface.into()));
self
}
pub fn link_index(mut self, index: u32) -> Self {
self.link = Some(InterfaceRef::Index(index));
self
}
}
impl LinkConfig for SitLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"sit"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
self.link.as_ref()
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(idx) = parent_index {
builder.append_attr_u32(IflaAttr::Link as u16, idx);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "sit");
let data = builder.nest_start(IflaInfo::Data as u16);
if let Some(addr) = self.local {
builder.append_attr(iptun_attr::IFLA_IPTUN_LOCAL, &addr.octets());
}
if let Some(addr) = self.remote {
builder.append_attr(iptun_attr::IFLA_IPTUN_REMOTE, &addr.octets());
}
if let Some(ttl) = self.ttl {
builder.append_attr_u8(iptun_attr::IFLA_IPTUN_TTL, ttl);
}
if let Some(tos) = self.tos {
builder.append_attr_u8(iptun_attr::IFLA_IPTUN_TOS, tos);
}
if let Some(pmtu) = self.pmtudisc {
builder.append_attr_u8(iptun_attr::IFLA_IPTUN_PMTUDISC, pmtu as u8);
}
if let Some(mark) = self.fwmark {
builder.append_attr_u32(iptun_attr::IFLA_IPTUN_FWMARK, mark);
}
if self.isatap {
builder.append_attr_u16(iptun_attr::IFLA_IPTUN_FLAGS, iptun_attr::SIT_ISATAP);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
#[derive(Debug, Clone)]
#[must_use = "builders do nothing unless used"]
pub struct WireguardLink {
name: String,
mtu: Option<u32>,
}
impl WireguardLink {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
mtu: None,
}
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
}
impl LinkConfig for WireguardLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"wireguard"
}
fn write_to(&self, builder: &mut MessageBuilder, _parent_index: Option<u32>) {
write_simple_link(builder, &self.name, "wireguard", self.mtu, None);
}
}
mod macsec {
pub const IFLA_MACSEC_SCI: u16 = 1;
pub const IFLA_MACSEC_PORT: u16 = 2;
pub const IFLA_MACSEC_WINDOW: u16 = 5;
pub const IFLA_MACSEC_ENCODING_SA: u16 = 6;
pub const IFLA_MACSEC_ENCRYPT: u16 = 7;
pub const IFLA_MACSEC_PROTECT: u16 = 8;
pub const IFLA_MACSEC_INC_SCI: u16 = 9;
pub const IFLA_MACSEC_ES: u16 = 10;
pub const IFLA_MACSEC_SCB: u16 = 11;
pub const IFLA_MACSEC_REPLAY_PROTECT: u16 = 12;
}
pub struct MacsecLink {
name: String,
parent: InterfaceRef,
mtu: Option<u32>,
sci: Option<u64>,
port: Option<u16>,
encrypt: Option<bool>,
protect: Option<bool>,
inc_sci: Option<bool>,
end_station: Option<bool>,
scb: Option<bool>,
replay_protect: Option<bool>,
replay_window: Option<u32>,
encoding_sa: Option<u8>,
}
impl MacsecLink {
pub fn new(name: impl Into<String>, parent: impl Into<String>) -> Self {
Self {
name: name.into(),
parent: InterfaceRef::Name(parent.into()),
mtu: None,
sci: None,
port: None,
encrypt: None,
protect: None,
inc_sci: None,
end_station: None,
scb: None,
replay_protect: None,
replay_window: None,
encoding_sa: None,
}
}
pub fn with_parent_index(name: impl Into<String>, parent_index: u32) -> Self {
Self {
name: name.into(),
parent: InterfaceRef::Index(parent_index),
mtu: None,
sci: None,
port: None,
encrypt: None,
protect: None,
inc_sci: None,
end_station: None,
scb: None,
replay_protect: None,
replay_window: None,
encoding_sa: None,
}
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn sci(mut self, sci: u64) -> Self {
self.sci = Some(sci);
self
}
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
pub fn encrypt(mut self, enabled: bool) -> Self {
self.encrypt = Some(enabled);
self
}
pub fn protect(mut self, enabled: bool) -> Self {
self.protect = Some(enabled);
self
}
pub fn include_sci(mut self, enabled: bool) -> Self {
self.inc_sci = Some(enabled);
self
}
pub fn end_station(mut self, enabled: bool) -> Self {
self.end_station = Some(enabled);
self
}
pub fn scb(mut self, enabled: bool) -> Self {
self.scb = Some(enabled);
self
}
pub fn replay_protect(mut self, enabled: bool) -> Self {
self.replay_protect = Some(enabled);
self
}
pub fn replay_window(mut self, window: u32) -> Self {
self.replay_window = Some(window);
self
}
pub fn encoding_sa(mut self, an: u8) -> Self {
self.encoding_sa = Some(an);
self
}
}
impl LinkConfig for MacsecLink {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> &str {
"macsec"
}
fn parent_ref(&self) -> Option<&InterfaceRef> {
Some(&self.parent)
}
fn write_to(&self, builder: &mut MessageBuilder, parent_index: Option<u32>) {
write_ifname(builder, &self.name);
let idx = parent_index.expect("MacsecLink requires parent_index");
builder.append_attr_u32(IflaAttr::Link as u16, idx);
if let Some(mtu) = self.mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, "macsec");
let data = builder.nest_start(IflaInfo::Data as u16);
if let Some(sci) = self.sci {
builder.append_attr_u64(macsec::IFLA_MACSEC_SCI, sci);
}
if let Some(port) = self.port {
builder.append_attr_u16(macsec::IFLA_MACSEC_PORT, port);
}
if let Some(window) = self.replay_window {
builder.append_attr_u32(macsec::IFLA_MACSEC_WINDOW, window);
}
if let Some(encoding_sa) = self.encoding_sa {
builder.append_attr_u8(macsec::IFLA_MACSEC_ENCODING_SA, encoding_sa);
}
if let Some(v) = self.encrypt {
builder.append_attr_u8(macsec::IFLA_MACSEC_ENCRYPT, v as u8);
}
if let Some(v) = self.protect {
builder.append_attr_u8(macsec::IFLA_MACSEC_PROTECT, v as u8);
}
if let Some(v) = self.inc_sci {
builder.append_attr_u8(macsec::IFLA_MACSEC_INC_SCI, v as u8);
}
if let Some(v) = self.end_station {
builder.append_attr_u8(macsec::IFLA_MACSEC_ES, v as u8);
}
if let Some(v) = self.scb {
builder.append_attr_u8(macsec::IFLA_MACSEC_SCB, v as u8);
}
if let Some(v) = self.replay_protect {
builder.append_attr_u8(macsec::IFLA_MACSEC_REPLAY_PROTECT, v as u8);
}
builder.nest_end(data);
builder.nest_end(linkinfo);
}
}
fn write_ifname(builder: &mut MessageBuilder, name: &str) {
builder.append_attr_str(IflaAttr::Ifname as u16, name);
}
fn write_simple_link(
builder: &mut MessageBuilder,
name: &str,
kind: &str,
mtu: Option<u32>,
address: Option<&[u8; 6]>,
) {
write_ifname(builder, name);
if let Some(mtu) = mtu {
builder.append_attr_u32(IflaAttr::Mtu as u16, mtu);
}
if let Some(addr) = address {
builder.append_attr(IflaAttr::Address as u16, addr);
}
let linkinfo = builder.nest_start(IflaAttr::Linkinfo as u16);
builder.append_attr_str(IflaInfo::Kind as u16, kind);
builder.nest_end(linkinfo);
}
impl Connection<Route> {
pub async fn add_link<L: LinkConfig>(&self, config: L) -> Result<()> {
use super::message::{NLM_F_ACK, NLM_F_REQUEST};
crate::util::ifname::validate(config.name()).map_err(super::error::Error::Interface)?;
if let Some(peer) = config.peer_name() {
crate::util::ifname::validate(peer).map_err(super::error::Error::Interface)?;
}
let parent_index = match config.parent_ref() {
Some(iface) => Some(self.resolve_interface(iface).await?),
None => None,
};
let mut builder = MessageBuilder::new(
NlMsgType::RTM_NEWLINK,
NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL,
);
let ifinfo = IfInfoMsg::new();
builder.append(&ifinfo);
let link_name = config.name().to_string();
let link_kind = config.kind().to_string();
config.write_to(&mut builder, parent_index);
self.send_ack(builder)
.await
.map_err(|e| e.with_context(format!("add_link({link_name}, kind={link_kind})")))
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "set_link_master"))]
pub async fn set_link_master(
&self,
iface: impl Into<InterfaceRef>,
master: impl Into<InterfaceRef>,
) -> Result<()> {
let ifindex = self.resolve_interface(&iface.into()).await?;
let master_index = self.resolve_interface(&master.into()).await?;
self.set_link_master_by_index(ifindex, master_index).await
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "set_link_master_by_index"))]
pub async fn set_link_master_by_index(&self, ifindex: u32, master_index: u32) -> Result<()> {
use super::connection::ack_request;
let ifinfo = IfInfoMsg::new().with_index(ifindex as i32);
let mut builder = ack_request(NlMsgType::RTM_SETLINK);
builder.append(&ifinfo);
builder.append_attr_u32(IflaAttr::Master as u16, master_index);
self.send_ack(builder)
.await
.map_err(|e| e.with_context("set_link_master"))
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "enslave"))]
pub async fn enslave(
&self,
member: impl Into<InterfaceRef>,
master: impl Into<InterfaceRef>,
) -> Result<()> {
let member = member.into();
let master = master.into();
let member_idx = self.resolve_interface(&member).await?;
let master_idx = self.resolve_interface(&master).await?;
self.set_link_down_by_index(member_idx).await?;
self.set_link_master_by_index(member_idx, master_idx)
.await?;
self.set_link_up_by_index(member_idx).await
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "enslave_by_index"))]
pub async fn enslave_by_index(&self, member_index: u32, master_index: u32) -> Result<()> {
self.set_link_down_by_index(member_index).await?;
self.set_link_master_by_index(member_index, master_index)
.await?;
self.set_link_up_by_index(member_index).await
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "set_link_nomaster"))]
pub async fn set_link_nomaster(&self, iface: impl Into<InterfaceRef>) -> Result<()> {
let ifindex = self.resolve_interface(&iface.into()).await?;
self.set_link_nomaster_by_index(ifindex).await
}
#[tracing::instrument(
level = "debug",
skip_all,
fields(method = "set_link_nomaster_by_index")
)]
pub async fn set_link_nomaster_by_index(&self, ifindex: u32) -> Result<()> {
use super::connection::ack_request;
let ifinfo = IfInfoMsg::new().with_index(ifindex as i32);
let mut builder = ack_request(NlMsgType::RTM_SETLINK);
builder.append(&ifinfo);
builder.append_attr_u32(IflaAttr::Master as u16, 0);
self.send_ack(builder)
.await
.map_err(|e| e.with_context("set_link_nomaster"))
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "set_link_name"))]
pub async fn set_link_name(
&self,
iface: impl Into<InterfaceRef>,
new_name: &str,
) -> Result<()> {
let ifindex = self.resolve_interface(&iface.into()).await?;
self.set_link_name_by_index(ifindex, new_name).await
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "set_link_name_by_index"))]
pub async fn set_link_name_by_index(&self, ifindex: u32, new_name: &str) -> Result<()> {
use super::connection::ack_request;
crate::util::ifname::validate(new_name).map_err(super::error::Error::Interface)?;
let ifinfo = IfInfoMsg::new().with_index(ifindex as i32);
let mut builder = ack_request(NlMsgType::RTM_SETLINK);
builder.append(&ifinfo);
builder.append_attr_str(IflaAttr::Ifname as u16, new_name);
self.send_ack(builder)
.await
.map_err(|e| e.with_context("set_link_name"))
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "set_link_address"))]
pub async fn set_link_address(
&self,
iface: impl Into<InterfaceRef>,
address: [u8; 6],
) -> Result<()> {
let ifindex = self.resolve_interface(&iface.into()).await?;
self.set_link_address_by_index(ifindex, address).await
}
#[tracing::instrument(
level = "debug",
skip_all,
fields(method = "set_link_address_by_index")
)]
pub async fn set_link_address_by_index(&self, ifindex: u32, address: [u8; 6]) -> Result<()> {
use super::connection::ack_request;
let ifinfo = IfInfoMsg::new().with_index(ifindex as i32);
let mut builder = ack_request(NlMsgType::RTM_SETLINK);
builder.append(&ifinfo);
builder.append_attr(IflaAttr::Address as u16, &address);
self.send_ack(builder)
.await
.map_err(|e| e.with_context("set_link_address"))
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "set_link_netns_pid"))]
pub async fn set_link_netns_pid(&self, iface: impl Into<InterfaceRef>, pid: u32) -> Result<()> {
let ifindex = self.resolve_interface(&iface.into()).await?;
self.set_link_netns_pid_by_index(ifindex, pid).await
}
#[tracing::instrument(
level = "debug",
skip_all,
fields(method = "set_link_netns_pid_by_index")
)]
pub async fn set_link_netns_pid_by_index(&self, ifindex: u32, pid: u32) -> Result<()> {
use super::connection::ack_request;
let ifinfo = IfInfoMsg::new().with_index(ifindex as i32);
let mut builder = ack_request(NlMsgType::RTM_SETLINK);
builder.append(&ifinfo);
builder.append_attr_u32(IflaAttr::NetNsPid as u16, pid);
self.send_ack(builder)
.await
.map_err(|e| e.with_context("set_link_netns"))
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "set_link_netns_fd"))]
pub async fn set_link_netns_fd(&self, iface: impl Into<InterfaceRef>, fd: i32) -> Result<()> {
let ifindex = self.resolve_interface(&iface.into()).await?;
self.set_link_netns_fd_by_index(ifindex, fd).await
}
#[tracing::instrument(
level = "debug",
skip_all,
fields(method = "set_link_netns_fd_by_index")
)]
pub async fn set_link_netns_fd_by_index(&self, ifindex: u32, fd: i32) -> Result<()> {
use super::connection::ack_request;
let ifinfo = IfInfoMsg::new().with_index(ifindex as i32);
let mut builder = ack_request(NlMsgType::RTM_SETLINK);
builder.append(&ifinfo);
builder.append_attr_u32(IflaAttr::NetNsFd as u16, fd as u32);
self.send_ack(builder)
.await
.map_err(|e| e.with_context("set_link_netns"))
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "set_link_netns"))]
pub async fn set_link_netns(
&self,
iface: impl Into<InterfaceRef>,
ns_name: &str,
) -> Result<()> {
let ns_fd = super::namespace::open(ns_name)?;
let ifindex = self.resolve_interface(&iface.into()).await?;
self.set_link_netns_fd_by_index(ifindex, ns_fd.as_raw_fd())
.await
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "set_link_netns_by_index"))]
pub async fn set_link_netns_by_index(&self, ifindex: u32, ns_name: &str) -> Result<()> {
let ns_fd = super::namespace::open(ns_name)?;
self.set_link_netns_fd_by_index(ifindex, ns_fd.as_raw_fd())
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bond_mode_try_from() {
assert!(matches!(BondMode::try_from(0u8), Ok(BondMode::BalanceRr)));
assert!(matches!(
BondMode::try_from(1u8),
Ok(BondMode::ActiveBackup)
));
assert!(matches!(BondMode::try_from(2u8), Ok(BondMode::BalanceXor)));
assert!(matches!(BondMode::try_from(3u8), Ok(BondMode::Broadcast)));
assert!(matches!(BondMode::try_from(4u8), Ok(BondMode::Lacp)));
assert!(matches!(BondMode::try_from(5u8), Ok(BondMode::BalanceTlb)));
assert!(matches!(BondMode::try_from(6u8), Ok(BondMode::BalanceAlb)));
assert!(BondMode::try_from(7u8).is_err());
assert!(BondMode::try_from(255u8).is_err());
}
#[test]
fn test_xmit_hash_policy_try_from() {
assert!(matches!(
XmitHashPolicy::try_from(0u8),
Ok(XmitHashPolicy::Layer2)
));
assert!(matches!(
XmitHashPolicy::try_from(1u8),
Ok(XmitHashPolicy::Layer34)
));
assert!(matches!(
XmitHashPolicy::try_from(2u8),
Ok(XmitHashPolicy::Layer23)
));
assert!(matches!(
XmitHashPolicy::try_from(3u8),
Ok(XmitHashPolicy::Encap23)
));
assert!(matches!(
XmitHashPolicy::try_from(4u8),
Ok(XmitHashPolicy::Encap34)
));
assert!(matches!(
XmitHashPolicy::try_from(5u8),
Ok(XmitHashPolicy::VlanSrcMac)
));
assert!(XmitHashPolicy::try_from(6u8).is_err());
assert!(XmitHashPolicy::try_from(255u8).is_err());
}
#[test]
fn test_bond_mode_debug_format() {
assert_eq!(format!("{:?}", BondMode::BalanceRr), "BalanceRr");
assert_eq!(format!("{:?}", BondMode::Lacp), "Lacp");
assert_eq!(format!("{:?}", BondMode::BalanceAlb), "BalanceAlb");
}
#[test]
fn test_xmit_hash_policy_debug_format() {
assert_eq!(format!("{:?}", XmitHashPolicy::Layer2), "Layer2");
assert_eq!(format!("{:?}", XmitHashPolicy::Layer34), "Layer34");
assert_eq!(format!("{:?}", XmitHashPolicy::VlanSrcMac), "VlanSrcMac");
}
}