use core::net::Ipv4Addr;
use crate::field::Field;
const OSPFV3_HELLO_FIXED_LEN: usize = 20;
const OSPFV3_OPTIONS_MASK: u32 = 0x00ff_ffff;
const OSPFV3_HELLO_DEFAULT_HELLO_INTERVAL: u16 = 10;
const OSPFV3_HELLO_DEFAULT_DEAD_INTERVAL: u16 = 40;
#[derive(Debug, Clone)]
pub struct Ospfv3Hello {
interface_id: Field<u32>,
router_priority: Field<u8>,
options: Field<u32>,
hello_interval: Field<u16>,
router_dead_interval: Field<u16>,
designated_router: Field<Ipv4Addr>,
backup_designated_router: Field<Ipv4Addr>,
neighbors: Vec<Ipv4Addr>,
}
impl Ospfv3Hello {
pub fn new() -> Self {
Self {
interface_id: Field::defaulted(0),
router_priority: Field::defaulted(0),
options: Field::defaulted(0),
hello_interval: Field::defaulted(OSPFV3_HELLO_DEFAULT_HELLO_INTERVAL),
router_dead_interval: Field::defaulted(OSPFV3_HELLO_DEFAULT_DEAD_INTERVAL),
designated_router: Field::unset(),
backup_designated_router: Field::unset(),
neighbors: Vec::new(),
}
}
pub fn interface_id(mut self, interface_id: u32) -> Self {
self.interface_id.set_user(interface_id);
self
}
pub fn router_priority(mut self, router_priority: u8) -> Self {
self.router_priority.set_user(router_priority);
self
}
pub fn options(mut self, options: u32) -> Self {
self.options.set_user(options);
self
}
pub fn hello_interval(mut self, hello_interval: u16) -> Self {
self.hello_interval.set_user(hello_interval);
self
}
pub fn router_dead_interval(mut self, router_dead_interval: u16) -> Self {
self.router_dead_interval.set_user(router_dead_interval);
self
}
pub fn designated_router(mut self, designated_router: impl Into<Ipv4Addr>) -> Self {
self.designated_router.set_user(designated_router.into());
self
}
pub fn backup_designated_router(
mut self,
backup_designated_router: impl Into<Ipv4Addr>,
) -> Self {
self.backup_designated_router
.set_user(backup_designated_router.into());
self
}
pub fn neighbor(mut self, neighbor: impl Into<Ipv4Addr>) -> Self {
self.neighbors.push(neighbor.into());
self
}
pub fn neighbors<I, A>(mut self, neighbors: I) -> Self
where
I: IntoIterator<Item = A>,
A: Into<Ipv4Addr>,
{
self.neighbors.extend(neighbors.into_iter().map(Into::into));
self
}
pub fn interface_id_value(&self) -> u32 {
self.interface_id.value().copied().unwrap_or(0)
}
pub fn router_priority_value(&self) -> u8 {
self.router_priority.value().copied().unwrap_or(0)
}
pub fn options_value(&self) -> u32 {
self.options.value().copied().unwrap_or(0) & OSPFV3_OPTIONS_MASK
}
pub fn hello_interval_value(&self) -> u16 {
self.hello_interval
.value()
.copied()
.unwrap_or(OSPFV3_HELLO_DEFAULT_HELLO_INTERVAL)
}
pub fn router_dead_interval_value(&self) -> u16 {
self.router_dead_interval
.value()
.copied()
.unwrap_or(OSPFV3_HELLO_DEFAULT_DEAD_INTERVAL)
}
pub fn designated_router_value(&self) -> Ipv4Addr {
self.designated_router
.value()
.copied()
.unwrap_or(Ipv4Addr::UNSPECIFIED)
}
pub fn backup_designated_router_value(&self) -> Ipv4Addr {
self.backup_designated_router
.value()
.copied()
.unwrap_or(Ipv4Addr::UNSPECIFIED)
}
pub fn neighbors_value(&self) -> &[Ipv4Addr] {
&self.neighbors
}
pub(crate) fn encoded_len(&self) -> usize {
OSPFV3_HELLO_FIXED_LEN + self.neighbors.len() * 4
}
pub(crate) fn encode(&self, out: &mut Vec<u8>) {
out.extend_from_slice(&self.interface_id_value().to_be_bytes());
out.push(self.router_priority_value());
let options = self.options_value();
out.push(((options >> 16) & 0xff) as u8);
out.push(((options >> 8) & 0xff) as u8);
out.push((options & 0xff) as u8);
out.extend_from_slice(&self.hello_interval_value().to_be_bytes());
out.extend_from_slice(&self.router_dead_interval_value().to_be_bytes());
out.extend_from_slice(&self.designated_router_value().octets());
out.extend_from_slice(&self.backup_designated_router_value().octets());
for neighbor in &self.neighbors {
out.extend_from_slice(&neighbor.octets());
}
}
}
impl Default for Ospfv3Hello {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::packet::{NetworkLayer, Packet};
use crate::protocols::ip::v6::Ipv6;
use crate::protocols::ospf::{Ospfv3, OSPFV3_HEADER_LEN, OSPFV3_TYPE_HELLO};
use core::net::Ipv6Addr;
#[test]
fn ospfv3_hello_body_compiles_and_round_trips_with_two_neighbors() {
let hello = Ospfv3Hello::new()
.interface_id(0x0000_0005)
.router_priority(1)
.options(0x00ff_0013)
.hello_interval(10)
.router_dead_interval(40)
.designated_router(Ipv4Addr::new(192, 0, 2, 1))
.backup_designated_router(Ipv4Addr::new(192, 0, 2, 2))
.neighbor(Ipv4Addr::new(192, 0, 2, 3))
.neighbor(Ipv4Addr::new(192, 0, 2, 4));
assert_eq!(hello.options_value(), 0x00ff_0013);
let mut body = Vec::new();
hello.encode(&mut body);
assert_eq!(hello.encoded_len(), OSPFV3_HELLO_FIXED_LEN + 2 * 4);
assert_eq!(body.len(), hello.encoded_len());
let expected: Vec<u8> = vec![
0x00, 0x00, 0x00, 0x05, 0x01, 0xff, 0x00, 0x13, 0x00, 0x0a, 0x00, 0x28, 192, 0, 2, 1, 192, 0, 2, 2, 192, 0, 2, 3, 192, 0, 2, 4,
];
assert_eq!(body, expected);
let src: Ipv6Addr = "2001:db8::1".parse().unwrap();
let dst: Ipv6Addr = "2001:db8::2".parse().unwrap();
let bytes = (Ipv6::new().src(src).dst(dst)
/ Ospfv3::hello()
.router_id([192, 0, 2, 1])
.area_id([0, 0, 0, 0])
.with_hello(|h| *h = hello.clone()))
.compile()
.expect("Ipv6 / Ospfv3 Hello compiles");
let decoded = Packet::decode_from_l3(NetworkLayer::Ipv6, bytes.as_bytes())
.expect("the default registry decodes the OSPFv3 Hello over IPv6");
let ospfv3 = decoded
.layer::<Ospfv3>()
.expect("the decoded packet exposes a typed Ospfv3 layer");
assert_eq!(ospfv3.packet_type_value(), OSPFV3_TYPE_HELLO);
let ospfv3_start = bytes.as_bytes().len() - (OSPFV3_HEADER_LEN + expected.len());
let body_start = ospfv3_start + OSPFV3_HEADER_LEN;
assert_eq!(&bytes.as_bytes()[body_start..], expected.as_slice());
let recompiled = decoded
.compile()
.expect("the decoded OSPFv3 Hello re-compiles");
assert_eq!(recompiled.as_bytes(), bytes.as_bytes());
}
}