use std::{marker::PhantomData, os::fd::RawFd};
use crate::packet_route::{
link::{
InfoData, InfoKind, InfoPortData, InfoPortKind, LinkAttribute,
LinkFlags, LinkHeader, LinkInfo, LinkMessage,
},
AddressFamily,
};
#[derive(Debug)]
pub struct LinkUnspec;
impl LinkUnspec {
pub fn new_with_index(index: u32) -> LinkMessageBuilder<Self> {
LinkMessageBuilder::<LinkUnspec>::default().index(index)
}
pub fn new_with_name(name: &str) -> LinkMessageBuilder<Self> {
LinkMessageBuilder::<LinkUnspec>::default().name(name.to_string())
}
}
#[derive(Debug)]
pub struct LinkMessageBuilder<T> {
pub(crate) header: LinkHeader,
pub(crate) info_kind: Option<InfoKind>,
pub(crate) info_data: Option<InfoData>,
pub(crate) port_kind: Option<InfoPortKind>,
pub(crate) port_data: Option<InfoPortData>,
pub(crate) extra_attriutes: Vec<LinkAttribute>,
_phantom: PhantomData<T>,
}
impl<T> Default for LinkMessageBuilder<T> {
fn default() -> Self {
Self {
header: Default::default(),
info_kind: None,
info_data: Default::default(),
extra_attriutes: Default::default(),
port_kind: None,
port_data: None,
_phantom: Default::default(),
}
}
}
impl<T> LinkMessageBuilder<T> {
pub fn new_with_info_kind(info_kind: InfoKind) -> Self {
Self {
info_kind: Some(info_kind),
..Default::default()
}
}
pub fn set_header(self, header: LinkHeader) -> Self {
let mut ret = self;
ret.header = header;
ret
}
pub fn append_extra_attribute(self, link_attr: LinkAttribute) -> Self {
let mut ret = self;
ret.extra_attriutes.push(link_attr);
ret
}
pub fn set_info_data(self, info_data: InfoData) -> Self {
let mut ret = self;
ret.info_data = Some(info_data);
ret
}
pub fn up(self) -> Self {
let mut ret = self;
ret.header.flags |= LinkFlags::Up;
ret.header.change_mask |= LinkFlags::Up;
ret
}
pub fn down(self) -> Self {
let mut ret = self;
ret.header.flags.remove(LinkFlags::Up);
ret.header.change_mask |= LinkFlags::Up;
ret
}
pub fn promiscuous(self, enable: bool) -> Self {
let mut ret = self;
if enable {
ret.header.flags |= LinkFlags::Promisc;
} else {
ret.header.flags.remove(LinkFlags::Promisc);
}
ret.header.change_mask |= LinkFlags::Promisc;
ret
}
pub fn arp(self, enable: bool) -> Self {
let mut ret = self;
if enable {
ret.header.flags.remove(LinkFlags::Noarp);
} else {
ret.header.flags |= LinkFlags::Noarp;
}
ret.header.change_mask |= LinkFlags::Noarp;
ret
}
pub fn name(self, name: String) -> Self {
self.append_extra_attribute(LinkAttribute::IfName(name))
}
pub fn mtu(self, mtu: u32) -> Self {
self.append_extra_attribute(LinkAttribute::Mtu(mtu))
}
pub fn index(self, index: u32) -> Self {
let mut ret = self;
ret.header.index = index;
ret
}
pub fn interface_family(self, family: AddressFamily) -> Self {
let mut ret = self;
ret.header.interface_family = family;
ret
}
pub fn address(self, address: Vec<u8>) -> Self {
self.append_extra_attribute(LinkAttribute::Address(address))
}
pub fn setns_by_pid(self, pid: u32) -> Self {
self.append_extra_attribute(LinkAttribute::NetNsPid(pid))
}
pub fn setns_by_fd(self, fd: RawFd) -> Self {
self.append_extra_attribute(LinkAttribute::NetNsFd(fd))
}
pub fn link(self, index: u32) -> Self {
self.append_extra_attribute(LinkAttribute::Link(index))
}
pub fn controller(self, ctrl_index: u32) -> Self {
self.append_extra_attribute(LinkAttribute::Controller(ctrl_index))
}
pub fn nocontroller(self) -> Self {
self.append_extra_attribute(LinkAttribute::Controller(0))
}
pub fn set_port_kind(self, port_kind: InfoPortKind) -> Self {
let mut ret = self;
ret.port_kind = Some(port_kind);
ret
}
pub fn set_port_data(self, port_data: InfoPortData) -> Self {
let mut ret = self;
ret.port_data = Some(port_data);
ret
}
pub fn build(self) -> LinkMessage {
let mut message = LinkMessage::default();
message.header = self.header;
if !self.extra_attriutes.is_empty() {
message.attributes = self.extra_attriutes;
}
let mut link_infos: Vec<LinkInfo> = Vec::new();
if let Some(info_kind) = self.info_kind {
link_infos.push(LinkInfo::Kind(info_kind));
}
if let Some(info_data) = self.info_data {
link_infos.push(LinkInfo::Data(info_data));
}
if let Some(port_kind) = self.port_kind {
link_infos.push(LinkInfo::PortKind(port_kind));
}
if let Some(port_data) = self.port_data {
link_infos.push(LinkInfo::PortData(port_data));
}
if !link_infos.is_empty() {
message.attributes.push(LinkAttribute::LinkInfo(link_infos));
}
message
}
}
impl LinkMessageBuilder<LinkUnspec> {
pub fn new() -> Self {
Self::default()
}
}