use crate::netlink::{attr::AttrIter, types::nsid::netnsa};
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct NsIdMessage {
pub(crate) family: u8,
pub(crate) nsid: Option<u32>,
pub(crate) pid: Option<u32>,
pub(crate) fd: Option<i32>,
pub(crate) target_nsid: Option<u32>,
pub(crate) current_nsid: Option<u32>,
}
impl NsIdMessage {
pub fn family(&self) -> u8 {
self.family
}
pub fn nsid(&self) -> Option<u32> {
self.nsid
}
pub fn pid(&self) -> Option<u32> {
self.pid
}
pub fn fd(&self) -> Option<i32> {
self.fd
}
pub fn target_nsid(&self) -> Option<u32> {
self.target_nsid
}
pub fn current_nsid(&self) -> Option<u32> {
self.current_nsid
}
pub fn parse(data: &[u8]) -> Option<Self> {
if data.is_empty() {
return None;
}
let family = data[0];
let attr_data = data.get(4..)?;
let mut msg = NsIdMessage {
family,
..Default::default()
};
for (attr_type, payload) in AttrIter::new(attr_data) {
match attr_type {
x if x == netnsa::NSID && payload.len() >= 4 => {
msg.nsid = Some(u32::from_ne_bytes(payload[..4].try_into().ok()?));
}
x if x == netnsa::PID && payload.len() >= 4 => {
msg.pid = Some(u32::from_ne_bytes(payload[..4].try_into().ok()?));
}
x if x == netnsa::FD && payload.len() >= 4 => {
msg.fd = Some(i32::from_ne_bytes(payload[..4].try_into().ok()?));
}
x if x == netnsa::TARGET_NSID && payload.len() >= 4 => {
msg.target_nsid = Some(u32::from_ne_bytes(payload[..4].try_into().ok()?));
}
x if x == netnsa::CURRENT_NSID && payload.len() >= 4 => {
msg.current_nsid = Some(u32::from_ne_bytes(payload[..4].try_into().ok()?));
}
_ => {}
}
}
Some(msg)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_nsid_message_parsing() {
let data = [
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x42, 0x00, 0x00, 0x00, ];
let msg = NsIdMessage::parse(&data).unwrap();
assert_eq!(msg.family(), 0);
assert_eq!(msg.nsid(), Some(66));
assert_eq!(msg.pid(), None);
}
#[test]
fn test_nsid_message_with_pid() {
let data = [
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0xe8, 0x03, 0x00, 0x00, ];
let msg = NsIdMessage::parse(&data).unwrap();
assert_eq!(msg.nsid(), Some(1));
assert_eq!(msg.pid(), Some(1000));
}
#[test]
fn test_empty_message() {
assert!(NsIdMessage::parse(&[]).is_none());
}
#[test]
fn test_minimal_message() {
let data = [0x00, 0x00, 0x00, 0x00];
let msg = NsIdMessage::parse(&data).unwrap();
assert_eq!(msg.family(), 0);
assert_eq!(msg.nsid(), None);
}
}