use crate::{DecodeError, Emitable, Parseable};
use super::{LinkBuffer, LinkHeader, LinkNla};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct LinkMessage {
header: LinkHeader,
nlas: Vec<LinkNla>,
}
impl LinkMessage {
pub fn new() -> Self {
LinkMessage::from_parts(LinkHeader::new(), vec![])
}
pub fn into_parts(self) -> (LinkHeader, Vec<LinkNla>) {
(self.header, self.nlas)
}
pub fn header_mut(&mut self) -> &mut LinkHeader {
&mut self.header
}
pub fn header(&self) -> &LinkHeader {
&self.header
}
pub fn nlas(&self) -> &[LinkNla] {
self.nlas.as_slice()
}
pub fn nlas_mut(&mut self) -> &mut Vec<LinkNla> {
&mut self.nlas
}
pub fn append_nla(&mut self, nla: LinkNla) {
self.nlas.push(nla)
}
pub fn from_parts(header: LinkHeader, nlas: Vec<LinkNla>) -> Self {
LinkMessage { header, nlas }
}
}
impl Emitable for LinkMessage {
fn buffer_len(&self) -> usize {
self.header.buffer_len() + self.nlas.as_slice().buffer_len()
}
fn emit(&self, buffer: &mut [u8]) {
self.header.emit(buffer);
self.nlas
.as_slice()
.emit(&mut buffer[self.header.buffer_len()..]);
}
}
impl<'buffer, T: AsRef<[u8]> + 'buffer> Parseable<LinkMessage> for LinkBuffer<&'buffer T> {
fn parse(&self) -> Result<LinkMessage, DecodeError> {
let header = self.parse()?;
let parsed_nlas: Vec<Result<LinkNla, DecodeError>> = self.parse()?;
let (valid_nlas, parse_errors): (Vec<_>, Vec<_>) =
parsed_nlas.into_iter().partition(Result::is_ok);
let nlas = valid_nlas.into_iter().map(Result::unwrap).collect();
for parse_result in parse_errors {
warn!(
"Failed to parse a Netlink Link message attribute: {}",
parse_result.unwrap_err()
);
}
Ok(LinkMessage { header, nlas })
}
}
impl<'buffer, T: AsRef<[u8]> + 'buffer> Parseable<Vec<Result<LinkNla, DecodeError>>>
for LinkBuffer<&'buffer T>
{
fn parse(&self) -> Result<Vec<Result<LinkNla, DecodeError>>, DecodeError> {
let mut nlas = vec![];
for nla_buf in self.nlas() {
nlas.push(nla_buf.and_then(|nla_buf| nla_buf.parse()));
}
Ok(nlas)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::constants::*;
use crate::rtnl::link::*;
#[rustfmt::skip]
static HEADER: [u8; 96] = [
0x00, 0x00, 0x04, 0x03, 0x01, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0x00, 0x03, 0x00, 0x6c, 0x6f, 0x00, 0x00, 0x08, 0x00, 0x0d, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x28, 0x00, 0xff, 0xff, 0x00, 0x00, 0x08, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, ];
#[test]
fn packet_header_read() {
let packet = LinkBuffer::new(&HEADER[0..16]);
assert_eq!(packet.address_family(), 0);
assert_eq!(packet.reserved_1(), 0);
assert_eq!(packet.link_layer_type(), LinkLayerType::Loopback);
assert_eq!(packet.link_index(), 1);
assert_eq!(
packet.flags(),
LinkFlags::from(IFF_UP | IFF_LOOPBACK | IFF_RUNNING)
);
assert!(packet.flags().is_running());
assert!(packet.flags().is_loopback());
assert!(packet.flags().is_up());
assert_eq!(packet.change_mask(), LinkFlags::new());
}
#[test]
fn packet_header_build() {
let mut buf = vec![0xff; 16];
{
let mut packet = LinkBuffer::new(&mut buf);
packet.set_address_family(0);
packet.set_reserved_1(0);
packet.set_link_layer_type(LinkLayerType::Loopback);
packet.set_link_index(1);
let mut flags = LinkFlags::new();
flags.set_up();
flags.set_loopback();
flags.set_running();
packet.set_flags(flags);
packet.set_change_mask(LinkFlags::new());
}
assert_eq!(&buf[..], &HEADER[0..16]);
}
#[test]
fn packet_nlas_read() {
let packet = LinkBuffer::new(&HEADER[..]);
assert_eq!(packet.nlas().count(), 10);
let mut nlas = packet.nlas();
let nla = nlas.next().unwrap().unwrap();
nla.check_buffer_length().unwrap();
assert_eq!(nla.length(), 7);
assert_eq!(nla.kind(), 3);
assert_eq!(nla.value(), &[0x6c, 0x6f, 0x00]);
let parsed: LinkNla = nla.parse().unwrap();
assert_eq!(parsed, LinkNla::IfName(String::from("lo")));
let nla = nlas.next().unwrap().unwrap();
nla.check_buffer_length().unwrap();
assert_eq!(nla.length(), 8);
assert_eq!(nla.kind(), 13);
assert_eq!(nla.value(), &[0xe8, 0x03, 0x00, 0x00]);
let parsed: LinkNla = nla.parse().unwrap();
assert_eq!(parsed, LinkNla::TxQueueLen(1000));
let nla = nlas.next().unwrap().unwrap();
nla.check_buffer_length().unwrap();
assert_eq!(nla.length(), 5);
assert_eq!(nla.kind(), 16);
assert_eq!(nla.value(), &[0x00]);
let parsed: LinkNla = nla.parse().unwrap();
assert_eq!(parsed, LinkNla::OperState(LinkState::Unknown));
let nla = nlas.next().unwrap().unwrap();
nla.check_buffer_length().unwrap();
assert_eq!(nla.length(), 5);
assert_eq!(nla.kind(), 17);
assert_eq!(nla.value(), &[0x00]);
let parsed: LinkNla = nla.parse().unwrap();
assert_eq!(parsed, LinkNla::LinkMode(0));
let nla = nlas.next().unwrap().unwrap();
nla.check_buffer_length().unwrap();
assert_eq!(nla.length(), 8);
assert_eq!(nla.kind(), 4);
assert_eq!(nla.value(), &[0x00, 0x00, 0x01, 0x00]);
let parsed: LinkNla = nla.parse().unwrap();
assert_eq!(parsed, LinkNla::Mtu(65_536));
let nla = nlas.next().unwrap().unwrap();
nla.check_buffer_length().unwrap();
assert_eq!(nla.length(), 8);
assert_eq!(nla.kind(), 27);
assert_eq!(nla.value(), &[0x00, 0x00, 0x00, 0x00]);
let parsed: LinkNla = nla.parse().unwrap();
assert_eq!(parsed, LinkNla::Group(0));
let nla = nlas.next().unwrap().unwrap();
nla.check_buffer_length().unwrap();
assert_eq!(nla.length(), 8);
assert_eq!(nla.kind(), 30);
assert_eq!(nla.value(), &[0x00, 0x00, 0x00, 0x00]);
let parsed: LinkNla = nla.parse().unwrap();
assert_eq!(parsed, LinkNla::Promiscuity(0));
let nla = nlas.next().unwrap().unwrap();
nla.check_buffer_length().unwrap();
assert_eq!(nla.length(), 8);
assert_eq!(nla.kind(), 31);
assert_eq!(nla.value(), &[0x01, 0x00, 0x00, 0x00]);
let parsed: LinkNla = nla.parse().unwrap();
assert_eq!(parsed, LinkNla::NumTxQueues(1));
}
#[test]
fn emit() {
let mut header = LinkHeader::new();
header
.set_link_layer_type(LinkLayerType::Loopback)
.set_index(1)
.set_flags(LinkFlags::from(
IFF_UP | IFF_LOOPBACK | IFF_RUNNING | IFF_LOWER_UP,
));
let nlas = vec![
LinkNla::IfName("lo".into()),
LinkNla::TxQueueLen(1000),
LinkNla::OperState(LinkState::Unknown),
LinkNla::LinkMode(0),
LinkNla::Mtu(0x1_0000),
LinkNla::Group(0),
LinkNla::Promiscuity(0),
LinkNla::NumTxQueues(1),
LinkNla::GsoMaxSegs(0xffff),
LinkNla::GsoMaxSize(0x1_0000),
];
let packet = LinkMessage::from_parts(header, nlas);
let mut buf = vec![0; 96];
assert_eq!(packet.buffer_len(), 96);
packet.emit(&mut buf[..]);
}
}