use crate::field::Field;
use crate::protocols::ospf::constants::{OSPF_OPTIONS_E, OSPF_OPTIONS_O};
use crate::protocols::ospf::lsa::{encode_lsa_headers, OspfLsaHeader};
const OSPF_DD_FIXED_LEN: usize = 8;
pub const OSPF_DD_FLAG_MS: u8 = 0x01;
pub const OSPF_DD_FLAG_M: u8 = 0x02;
pub const OSPF_DD_FLAG_I: u8 = 0x04;
#[derive(Debug, Clone)]
pub struct OspfDatabaseDescription {
interface_mtu: Field<u16>,
options: Field<u8>,
flags: Field<u8>,
dd_sequence_number: Field<u32>,
lsa_headers: Vec<OspfLsaHeader>,
}
impl OspfDatabaseDescription {
pub fn new() -> Self {
Self {
interface_mtu: Field::defaulted(0),
options: Field::defaulted(0),
flags: Field::defaulted(0),
dd_sequence_number: Field::defaulted(0),
lsa_headers: Vec::new(),
}
}
pub(crate) fn from_decoded_parts(
interface_mtu: u16,
options: u8,
flags: u8,
dd_sequence_number: u32,
lsa_headers: Vec<OspfLsaHeader>,
) -> Self {
Self {
interface_mtu: Field::user(interface_mtu),
options: Field::user(options),
flags: Field::user(flags),
dd_sequence_number: Field::user(dd_sequence_number),
lsa_headers,
}
}
pub fn interface_mtu(mut self, interface_mtu: u16) -> Self {
self.interface_mtu.set_user(interface_mtu);
self
}
pub fn options(mut self, options: u8) -> Self {
self.options.set_user(options);
self
}
pub fn external_capable(mut self, external_capable: bool) -> Self {
self.set_options_bit(OSPF_OPTIONS_E, external_capable);
self
}
pub fn opaque_capable(mut self, opaque_capable: bool) -> Self {
self.set_options_bit(OSPF_OPTIONS_O, opaque_capable);
self
}
fn set_options_bit(&mut self, bit: u8, set: bool) {
let mut options = self.options_value();
if set {
options |= bit;
} else {
options &= !bit;
}
self.options.set_user(options);
}
pub fn flags(mut self, flags: u8) -> Self {
self.flags.set_user(flags);
self
}
pub fn dd_sequence_number(mut self, dd_sequence_number: u32) -> Self {
self.dd_sequence_number.set_user(dd_sequence_number);
self
}
pub fn init(mut self, init: bool) -> Self {
self.set_flag_bit(OSPF_DD_FLAG_I, init);
self
}
pub fn more(mut self, more: bool) -> Self {
self.set_flag_bit(OSPF_DD_FLAG_M, more);
self
}
pub fn master(mut self, master: bool) -> Self {
self.set_flag_bit(OSPF_DD_FLAG_MS, master);
self
}
fn set_flag_bit(&mut self, bit: u8, set: bool) {
let mut flags = self.flags_value();
if set {
flags |= bit;
} else {
flags &= !bit;
}
self.flags.set_user(flags);
}
pub fn lsa_header(mut self, header: OspfLsaHeader) -> Self {
self.lsa_headers.push(header);
self
}
pub fn lsa_headers<I>(mut self, headers: I) -> Self
where
I: IntoIterator<Item = OspfLsaHeader>,
{
self.lsa_headers.extend(headers);
self
}
pub fn interface_mtu_value(&self) -> u16 {
self.interface_mtu.value().copied().unwrap_or(0)
}
pub fn options_value(&self) -> u8 {
self.options.value().copied().unwrap_or(0)
}
pub fn flags_value(&self) -> u8 {
self.flags.value().copied().unwrap_or(0)
}
pub fn init_value(&self) -> bool {
self.flags_value() & OSPF_DD_FLAG_I != 0
}
pub fn more_value(&self) -> bool {
self.flags_value() & OSPF_DD_FLAG_M != 0
}
pub fn master_value(&self) -> bool {
self.flags_value() & OSPF_DD_FLAG_MS != 0
}
pub fn is_init(&self) -> bool {
self.init_value()
}
pub fn is_more(&self) -> bool {
self.more_value()
}
pub fn is_master(&self) -> bool {
self.master_value()
}
pub fn dd_flags_summary(&self) -> String {
let flags = self.flags_value();
let mut labels: Vec<&str> = Vec::new();
if flags & OSPF_DD_FLAG_I != 0 {
labels.push("I");
}
if flags & OSPF_DD_FLAG_M != 0 {
labels.push("M");
}
if flags & OSPF_DD_FLAG_MS != 0 {
labels.push("MS");
}
labels.join("|")
}
pub fn dd_sequence_number_value(&self) -> u32 {
self.dd_sequence_number.value().copied().unwrap_or(0)
}
pub fn lsa_headers_value(&self) -> &[OspfLsaHeader] {
&self.lsa_headers
}
pub(crate) fn encoded_len(&self) -> usize {
OSPF_DD_FIXED_LEN
+ self.lsa_headers.len() * crate::protocols::ospf::lsa::OSPF_LSA_HEADER_LEN
}
pub(crate) fn encode(&self, out: &mut Vec<u8>) {
out.extend_from_slice(&self.interface_mtu_value().to_be_bytes());
out.push(self.options_value());
out.push(self.flags_value());
out.extend_from_slice(&self.dd_sequence_number_value().to_be_bytes());
encode_lsa_headers(&self.lsa_headers, out);
}
}
impl Default for OspfDatabaseDescription {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::net::Ipv4Addr;
#[test]
fn ospf_database_description_body_compiles_with_two_lsa_headers() {
use crate::packet::{Layer, Packet};
use crate::protocols::ospf::lsa::{OspfLsaHeader, OSPF_LSA_NETWORK, OSPF_LSA_ROUTER};
use crate::protocols::ospf::{Ospfv2, OSPF_HEADER_LEN, OSPF_TYPE_DATABASE_DESCRIPTION};
let dd = OspfDatabaseDescription::new()
.interface_mtu(1500)
.options(0x02)
.dd_sequence_number(0x0000_1a2b)
.more(true)
.master(true)
.lsa_header(
OspfLsaHeader::new()
.ls_type(OSPF_LSA_ROUTER)
.link_state_id(Ipv4Addr::new(192, 0, 2, 1))
.advertising_router(Ipv4Addr::new(192, 0, 2, 1))
.ls_sequence_number(0x8000_0001),
)
.lsa_header(
OspfLsaHeader::new()
.ls_type(OSPF_LSA_NETWORK)
.link_state_id(Ipv4Addr::new(192, 0, 2, 2))
.advertising_router(Ipv4Addr::new(198, 51, 100, 7))
.ls_sequence_number(0x8000_0002),
);
assert_eq!(dd.flags_value(), OSPF_DD_FLAG_M | OSPF_DD_FLAG_MS);
assert!(dd.more_value());
assert!(dd.master_value());
assert!(!dd.init_value());
let mut body = Vec::new();
dd.encode(&mut body);
assert_eq!(
dd.encoded_len(),
OSPF_DD_FIXED_LEN + 2 * crate::protocols::ospf::lsa::OSPF_LSA_HEADER_LEN
);
assert_eq!(body.len(), dd.encoded_len());
assert_eq!(&body[0..2], &1500u16.to_be_bytes()); assert_eq!(body[2], 0x02); assert_eq!(body[3], OSPF_DD_FLAG_M | OSPF_DD_FLAG_MS); assert_eq!(&body[4..8], &0x0000_1a2bu32.to_be_bytes());
let mut expected_headers = Vec::new();
encode_lsa_headers(dd.lsa_headers_value(), &mut expected_headers);
assert_eq!(&body[OSPF_DD_FIXED_LEN..], expected_headers.as_slice());
assert_eq!(expected_headers.len(), 2 * 20);
let ospf = Ospfv2::database_description().with_database_description(|d| {
*d = dd.clone();
});
let bytes = Packet::from_layer(ospf)
.compile()
.expect("DatabaseDescription 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_DATABASE_DESCRIPTION);
assert_eq!(&bytes[OSPF_HEADER_LEN..], body.as_slice());
let layer = Ospfv2::database_description().with_database_description(|d| *d = dd);
assert_eq!(layer.encoded_len(), total);
}
#[test]
fn ospf_dd_flags_summary_and_accessors_agree_for_init_master() {
let dd = OspfDatabaseDescription::new().init(true).master(true);
assert_eq!(dd.flags_value(), OSPF_DD_FLAG_I | OSPF_DD_FLAG_MS);
assert!(dd.is_init());
assert!(!dd.is_more());
assert!(dd.is_master());
assert_eq!(dd.is_init(), dd.flags_value() & OSPF_DD_FLAG_I != 0);
assert_eq!(dd.is_more(), dd.flags_value() & OSPF_DD_FLAG_M != 0);
assert_eq!(dd.is_master(), dd.flags_value() & OSPF_DD_FLAG_MS != 0);
assert_eq!(dd.dd_flags_summary(), "I|MS");
assert_eq!(OspfDatabaseDescription::new().dd_flags_summary(), "");
}
}