use std::net::IpAddr;
use anyhow::Result;
use derive_builder::Builder;
use crate::types::message::{Attribute, NeighborMessage, RouteAttrs};
use super::vec_to_addr;
#[derive(Default, Builder)]
#[builder(default, build_fn(validate = "Self::validate"))]
pub struct Neighbor {
pub link_index: u32,
pub family: Option<u8>,
pub state: u16,
pub ip_addr: Option<IpAddr>,
pub mac_addr: Option<Vec<u8>>,
pub neigh_type: u8,
pub flags: u8,
}
impl From<&[u8]> for Neighbor {
fn from(buf: &[u8]) -> Self {
let neigh_msg: NeighborMessage = bincode::deserialize(buf).unwrap();
let rt_attrs = RouteAttrs::from(&buf[neigh_msg.len()..]);
let mut neighbor = Self {
link_index: neigh_msg.index,
family: Some(neigh_msg.family),
state: neigh_msg.state,
neigh_type: neigh_msg.neigh_type,
flags: neigh_msg.flags,
..Default::default()
};
for attr in rt_attrs {
match attr.header.rta_type {
libc::NDA_DST => {
neighbor.ip_addr = Some(vec_to_addr(&attr.payload).unwrap());
}
libc::NDA_LLADDR => {
neighbor.mac_addr = Some(attr.payload.to_vec());
}
_ => {}
}
}
neighbor
}
}
impl NeighborBuilder {
fn validate(&self) -> Result<(), String> {
if self.ip_addr.is_none() {
return Err("IP address is required".to_string());
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::{
parse_mac,
types::message::{Payload, RouteAttr, RouteAttrHeader},
};
use super::*;
#[test]
fn test_neighbor_builder_default_returns_error() {
let neighbor = NeighborBuilder::default().build();
assert!(neighbor.is_err());
}
#[test]
fn test_neighbor_builder_arp() {
let _ = NeighborBuilder::default()
.link_index(5)
.state(128)
.ip_addr(Some(IpAddr::V4("10.244.1.0".parse().unwrap())))
.mac_addr(Some(vec![0x02, 0x12, 0x34, 0x56, 0x78, 0x9A]))
.neigh_type(1)
.build()
.unwrap();
}
#[test]
fn test_neighbor_build_fdb() {
let _ = NeighborBuilder::default()
.link_index(5)
.state(128)
.ip_addr(Some(IpAddr::V4("10.244.1.0".parse().unwrap())))
.mac_addr(Some(vec![0x02, 0x12, 0x34, 0x56, 0x78, 0x9A]))
.family(Some(7))
.flags(2)
.build()
.unwrap();
}
#[test]
fn test_from_bytes() {
let mac_bytes = parse_mac("aa:bb:cc:dd:00:01").unwrap();
let neigh_msg = NeighborMessage {
family: libc::AF_INET as u8,
index: 5,
state: 128,
neigh_type: 1,
..Default::default()
};
let mut rt_attrs = RouteAttrs::default();
rt_attrs.push(RouteAttr {
header: RouteAttrHeader {
rta_type: libc::NDA_DST,
rta_len: 8,
},
payload: Payload::from(&[10, 244, 1, 0][..]),
attributes: None,
});
rt_attrs.push(RouteAttr {
header: RouteAttrHeader {
rta_type: libc::NDA_LLADDR,
rta_len: 10,
},
payload: Payload::from(mac_bytes.as_slice()),
attributes: None,
});
let mut buf = NeighborMessage::serialize(&neigh_msg).unwrap();
buf.extend_from_slice(RouteAttrs::serialize(&rt_attrs).unwrap().as_slice());
let neighbor = Neighbor::from(&buf[..]);
assert_eq!(neighbor.link_index, neigh_msg.index);
}
}