use core::net::Ipv4Addr;
use crate::field::Field;
const OSPF_NETWORK_LSA_MASK_LEN: usize = 4;
const OSPF_NETWORK_LSA_ROUTER_LEN: usize = 4;
#[derive(Debug, Clone)]
pub struct OspfNetworkLsa {
network_mask: Field<Ipv4Addr>,
attached_routers: Vec<Ipv4Addr>,
}
impl OspfNetworkLsa {
pub fn new() -> Self {
Self {
network_mask: Field::unset(),
attached_routers: Vec::new(),
}
}
pub(crate) fn from_decoded_parts(
network_mask: Ipv4Addr,
attached_routers: Vec<Ipv4Addr>,
) -> Self {
Self {
network_mask: Field::user(network_mask),
attached_routers,
}
}
pub fn network_mask(mut self, network_mask: impl Into<Ipv4Addr>) -> Self {
self.network_mask.set_user(network_mask.into());
self
}
pub fn attached_router(mut self, router_id: impl Into<Ipv4Addr>) -> Self {
self.attached_routers.push(router_id.into());
self
}
pub fn attached_routers<I>(mut self, routers: I) -> Self
where
I: IntoIterator<Item = Ipv4Addr>,
{
self.attached_routers.extend(routers);
self
}
pub fn network_mask_value(&self) -> Ipv4Addr {
self.network_mask
.value()
.copied()
.unwrap_or(Ipv4Addr::UNSPECIFIED)
}
pub fn attached_routers_value(&self) -> &[Ipv4Addr] {
&self.attached_routers
}
pub fn summary(&self) -> String {
format!(
"mask={} routers={}",
self.network_mask_value(),
self.attached_routers.len()
)
}
pub(crate) fn encoded_len(&self) -> usize {
OSPF_NETWORK_LSA_MASK_LEN + self.attached_routers.len() * OSPF_NETWORK_LSA_ROUTER_LEN
}
pub(crate) fn encode(&self, out: &mut Vec<u8>) {
out.extend_from_slice(&self.network_mask_value().octets());
for router in &self.attached_routers {
out.extend_from_slice(&router.octets());
}
}
}
impl Default for OspfNetworkLsa {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::checksum::fletcher16_valid;
use crate::protocols::ospf::lsa::{
OspfLsa, OspfLsaBody, OspfLsaHeader, OSPF_LSA_HEADER_LEN, OSPF_LSA_NETWORK,
};
use crate::protocols::ospf::packet::link_state_update::OspfLinkStateUpdate;
#[test]
fn ospf_network_lsa_two_attached_routers_round_trips_in_lsu() {
let network = OspfNetworkLsa::new()
.network_mask(Ipv4Addr::new(255, 255, 255, 0))
.attached_router(Ipv4Addr::new(192, 0, 2, 1))
.attached_router(Ipv4Addr::new(192, 0, 2, 2));
assert_eq!(
network.network_mask_value(),
Ipv4Addr::new(255, 255, 255, 0)
);
assert_eq!(network.attached_routers_value().len(), 2);
let mut body = Vec::new();
network.encode(&mut body);
assert_eq!(body.len(), network.encoded_len());
let expected: Vec<u8> = vec![
255, 255, 255, 0, 192, 0, 2, 1, 192, 0, 2, 2,
];
assert_eq!(body, expected);
assert_eq!(&body[0..4], &[255, 255, 255, 0]);
assert_eq!(&body[4..8], &[192, 0, 2, 1]);
assert_eq!(&body[8..12], &[192, 0, 2, 2]);
let lsa = OspfLsa::new(
OspfLsaHeader::new()
.ls_type(OSPF_LSA_NETWORK)
.link_state_id(Ipv4Addr::new(192, 0, 2, 1))
.advertising_router(Ipv4Addr::new(192, 0, 2, 1))
.ls_sequence_number(0x8000_0001),
OspfLsaBody::Network(network),
);
let lsu = OspfLinkStateUpdate::new().lsa(lsa);
let mut update = Vec::new();
lsu.encode(&mut update);
assert_eq!(&update[0..4], &1u32.to_be_bytes());
let lsa_bytes = &update[4..];
assert_eq!(lsa_bytes.len(), OSPF_LSA_HEADER_LEN + expected.len());
let expected_lsa_len = (OSPF_LSA_HEADER_LEN + expected.len()) as u16;
assert_eq!(&lsa_bytes[18..20], &expected_lsa_len.to_be_bytes());
assert_eq!(&lsa_bytes[OSPF_LSA_HEADER_LEN..], expected.as_slice());
assert!(
fletcher16_valid(lsa_bytes),
"auto-filled Fletcher checksum should validate over the Network-LSA"
);
}
}