use std::net::Ipv4Addr;
const OSPF_LSR_ENTRY_LEN: usize = 12;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OspfLinkStateRequestEntry {
ls_type: u32,
link_state_id: Ipv4Addr,
advertising_router: Ipv4Addr,
}
impl OspfLinkStateRequestEntry {
pub fn new(
ls_type: u32,
link_state_id: impl Into<Ipv4Addr>,
advertising_router: impl Into<Ipv4Addr>,
) -> Self {
Self {
ls_type,
link_state_id: link_state_id.into(),
advertising_router: advertising_router.into(),
}
}
pub fn ls_type_value(&self) -> u32 {
self.ls_type
}
pub fn link_state_id_value(&self) -> Ipv4Addr {
self.link_state_id
}
pub fn advertising_router_value(&self) -> Ipv4Addr {
self.advertising_router
}
fn encode(&self, out: &mut Vec<u8>) {
out.extend_from_slice(&self.ls_type.to_be_bytes());
out.extend_from_slice(&self.link_state_id.octets());
out.extend_from_slice(&self.advertising_router.octets());
}
}
#[derive(Debug, Clone)]
pub struct OspfLinkStateRequest {
entries: Vec<OspfLinkStateRequestEntry>,
}
impl OspfLinkStateRequest {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub(crate) fn from_decoded_parts(entries: Vec<OspfLinkStateRequestEntry>) -> Self {
Self { entries }
}
pub fn request(mut self, entry: OspfLinkStateRequestEntry) -> Self {
self.entries.push(entry);
self
}
pub fn requests<I>(mut self, entries: I) -> Self
where
I: IntoIterator<Item = OspfLinkStateRequestEntry>,
{
self.entries.extend(entries);
self
}
pub fn entries_value(&self) -> &[OspfLinkStateRequestEntry] {
&self.entries
}
pub(crate) fn encoded_len(&self) -> usize {
self.entries.len() * OSPF_LSR_ENTRY_LEN
}
pub(crate) fn encode(&self, out: &mut Vec<u8>) {
for entry in &self.entries {
entry.encode(out);
}
}
}
impl Default for OspfLinkStateRequest {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ospf_link_state_request_body_compiles_with_two_entries() {
use crate::packet::{Layer, Packet};
use crate::protocols::ospf::lsa::{OSPF_LSA_NETWORK, OSPF_LSA_ROUTER};
use crate::protocols::ospf::{Ospfv2, OSPF_HEADER_LEN, OSPF_TYPE_LINK_STATE_REQUEST};
let lsr = OspfLinkStateRequest::new()
.request(OspfLinkStateRequestEntry::new(
u32::from(OSPF_LSA_ROUTER),
Ipv4Addr::new(192, 0, 2, 1),
Ipv4Addr::new(192, 0, 2, 1),
))
.request(OspfLinkStateRequestEntry::new(
u32::from(OSPF_LSA_NETWORK),
Ipv4Addr::new(192, 0, 2, 2),
Ipv4Addr::new(198, 51, 100, 7),
));
let mut body = Vec::new();
lsr.encode(&mut body);
assert_eq!(lsr.encoded_len(), 2 * OSPF_LSR_ENTRY_LEN);
assert_eq!(body.len(), lsr.encoded_len());
assert_eq!(body.len(), 24);
assert_eq!(&body[0..4], &u32::from(OSPF_LSA_ROUTER).to_be_bytes());
assert_eq!(&body[4..8], &Ipv4Addr::new(192, 0, 2, 1).octets());
assert_eq!(&body[8..12], &Ipv4Addr::new(192, 0, 2, 1).octets());
assert_eq!(&body[12..16], &u32::from(OSPF_LSA_NETWORK).to_be_bytes());
assert_eq!(&body[16..20], &Ipv4Addr::new(192, 0, 2, 2).octets());
assert_eq!(&body[20..24], &Ipv4Addr::new(198, 51, 100, 7).octets());
let ospf = Ospfv2::link_state_request().with_link_state_request(|r| {
*r = lsr.clone();
});
let bytes = Packet::from_layer(ospf)
.compile()
.expect("LinkStateRequest compiles");
let total = OSPF_HEADER_LEN + body.len();
assert_eq!(bytes.len(), total);
assert_eq!(&bytes[2..4], &(total as u16).to_be_bytes());
assert_eq!(bytes[1], OSPF_TYPE_LINK_STATE_REQUEST);
assert_eq!(&bytes[OSPF_HEADER_LEN..], body.as_slice());
let layer = Ospfv2::link_state_request().with_link_state_request(|r| *r = lsr);
assert_eq!(layer.encoded_len(), total);
}
}