1use alloc::{collections::BTreeMap, vec::Vec};
11
12use crate::net::Ipv4Address;
13
14pub const OSPF_PROTOCOL: u8 = 89;
16
17pub const OSPF_VERSION: u8 = 2;
19
20pub const HELLO_INTERVAL: u32 = 10;
22
23pub const DEAD_INTERVAL: u32 = 40;
25
26pub const MAX_LSA_AGE: u16 = 3600;
28
29pub const OSPF_ALL_ROUTERS: Ipv4Address = Ipv4Address([224, 0, 0, 5]);
31
32pub const OSPF_ALL_DR: Ipv4Address = Ipv4Address([224, 0, 0, 6]);
34
35pub const OSPF_INFINITY: u32 = 0xFFFF_FFFF;
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40#[repr(u8)]
41pub enum OspfPacketType {
42 Hello = 1,
43 DatabaseDescription = 2,
44 LinkStateRequest = 3,
45 LinkStateUpdate = 4,
46 LinkStateAck = 5,
47}
48
49impl OspfPacketType {
50 fn from_u8(v: u8) -> Option<Self> {
51 match v {
52 1 => Some(Self::Hello),
53 2 => Some(Self::DatabaseDescription),
54 3 => Some(Self::LinkStateRequest),
55 4 => Some(Self::LinkStateUpdate),
56 5 => Some(Self::LinkStateAck),
57 _ => None,
58 }
59 }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64#[repr(u16)]
65pub enum AuthType {
66 None = 0,
67 SimplePassword = 1,
68 CryptographicMd5 = 2,
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub struct OspfHeader {
74 pub version: u8,
76 pub packet_type: OspfPacketType,
78 pub packet_length: u16,
80 pub router_id: u32,
82 pub area_id: u32,
84 pub checksum: u16,
86 pub auth_type: AuthType,
88}
89
90impl OspfHeader {
91 pub fn new(packet_type: OspfPacketType, router_id: u32, area_id: u32) -> Self {
93 Self {
94 version: OSPF_VERSION,
95 packet_type,
96 packet_length: 0, router_id,
98 area_id,
99 checksum: 0,
100 auth_type: AuthType::None,
101 }
102 }
103}
104
105#[derive(Debug, Clone, PartialEq, Eq)]
107pub struct HelloPacket {
108 pub network_mask: u32,
110 pub hello_interval: u32,
112 pub dead_interval: u32,
114 pub priority: u8,
116 pub options: u8,
118 pub designated_router: u32,
120 pub backup_dr: u32,
122 pub neighbors: Vec<u32>,
124}
125
126impl HelloPacket {
127 pub fn new(network_mask: u32, priority: u8) -> Self {
129 Self {
130 network_mask,
131 hello_interval: HELLO_INTERVAL,
132 dead_interval: DEAD_INTERVAL,
133 priority,
134 options: 0x02, designated_router: 0,
136 backup_dr: 0,
137 neighbors: Vec::new(),
138 }
139 }
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
144pub enum NeighborState {
145 #[default]
147 Down,
148 Init,
150 TwoWay,
152 ExStart,
154 Exchange,
156 Loading,
158 Full,
160}
161
162impl NeighborState {
163 pub fn on_hello_received(self) -> Self {
165 match self {
166 Self::Down => Self::Init,
167 other => other,
168 }
169 }
170
171 pub fn on_two_way_received(self) -> Self {
174 match self {
175 Self::Init => Self::TwoWay,
176 other => other,
177 }
178 }
179
180 pub fn on_adjacency_ok(self) -> Self {
182 match self {
183 Self::TwoWay => Self::ExStart,
184 other => other,
185 }
186 }
187
188 pub fn on_negotiation_done(self) -> Self {
190 match self {
191 Self::ExStart => Self::Exchange,
192 other => other,
193 }
194 }
195
196 pub fn on_exchange_done(self) -> Self {
198 match self {
199 Self::Exchange => Self::Loading,
200 other => other,
201 }
202 }
203
204 pub fn on_loading_done(self) -> Self {
206 match self {
207 Self::Loading => Self::Full,
208 other => other,
209 }
210 }
211
212 pub fn on_kill(self) -> Self {
214 Self::Down
215 }
216
217 pub fn is_adjacent(&self) -> bool {
219 matches!(self, Self::Full)
220 }
221}
222
223#[derive(Debug, Clone, PartialEq, Eq)]
225pub struct OspfNeighbor {
226 pub router_id: u32,
228 pub state: NeighborState,
230 pub address: Ipv4Address,
232 pub priority: u8,
234 pub last_hello: u64,
236 pub designated_router: u32,
238 pub backup_dr: u32,
240}
241
242#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
244#[repr(u8)]
245pub enum LsaType {
246 RouterLsa = 1,
248 NetworkLsa = 2,
250}
251
252impl LsaType {
253 #[allow(dead_code)]
254 fn from_u8(v: u8) -> Option<Self> {
255 match v {
256 1 => Some(Self::RouterLsa),
257 2 => Some(Self::NetworkLsa),
258 _ => None,
259 }
260 }
261}
262
263#[derive(Debug, Clone, Copy, PartialEq, Eq)]
265pub struct LsaHeader {
266 pub ls_age: u16,
268 pub options: u8,
270 pub ls_type: LsaType,
272 pub link_state_id: u32,
274 pub advertising_router: u32,
276 pub seq_number: u32,
278 pub checksum: u16,
280 pub length: u16,
282}
283
284impl LsaHeader {
285 pub fn new(ls_type: LsaType, link_state_id: u32, advertising_router: u32) -> Self {
287 Self {
288 ls_age: 0,
289 options: 0x02,
290 ls_type,
291 link_state_id,
292 advertising_router,
293 seq_number: 1,
294 checksum: 0,
295 length: 0,
296 }
297 }
298
299 pub fn is_newer_than(&self, other: &Self) -> bool {
301 self.seq_number > other.seq_number
302 }
303}
304
305#[derive(Debug, Clone, Copy, PartialEq, Eq)]
307#[repr(u8)]
308pub enum RouterLinkType {
309 PointToPoint = 1,
311 Transit = 2,
313 Stub = 3,
315 Virtual = 4,
317}
318
319#[derive(Debug, Clone, Copy, PartialEq, Eq)]
321pub struct RouterLink {
322 pub link_type: RouterLinkType,
324 pub link_id: u32,
326 pub link_data: u32,
328 pub metric: u32,
330}
331
332#[derive(Debug, Clone, PartialEq, Eq)]
334pub struct RouterLsa {
335 pub header: LsaHeader,
337 pub flags: u8,
339 pub links: Vec<RouterLink>,
341}
342
343#[derive(Debug, Clone, PartialEq, Eq)]
345pub struct NetworkLsa {
346 pub header: LsaHeader,
348 pub network_mask: u32,
350 pub attached_routers: Vec<u32>,
352}
353
354#[derive(Debug, Clone, PartialEq, Eq)]
356pub enum Lsa {
357 Router(RouterLsa),
358 Network(NetworkLsa),
359}
360
361impl Lsa {
362 pub fn header(&self) -> &LsaHeader {
364 match self {
365 Lsa::Router(r) => &r.header,
366 Lsa::Network(n) => &n.header,
367 }
368 }
369
370 pub fn header_mut(&mut self) -> &mut LsaHeader {
372 match self {
373 Lsa::Router(r) => &mut r.header,
374 Lsa::Network(n) => &mut n.header,
375 }
376 }
377}
378
379#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
381pub struct LsaKey {
382 pub ls_type: u8,
383 pub link_state_id: u32,
384 pub advertising_router: u32,
385}
386
387#[derive(Debug, Default)]
389pub struct LsDatabase {
390 lsas: BTreeMap<LsaKey, Lsa>,
392}
393
394impl LsDatabase {
395 pub fn new() -> Self {
397 Self {
398 lsas: BTreeMap::new(),
399 }
400 }
401
402 pub fn install(&mut self, lsa: Lsa) -> bool {
405 let key = LsaKey {
406 ls_type: match lsa.header().ls_type {
407 LsaType::RouterLsa => 1,
408 LsaType::NetworkLsa => 2,
409 },
410 link_state_id: lsa.header().link_state_id,
411 advertising_router: lsa.header().advertising_router,
412 };
413
414 if let Some(existing) = self.lsas.get(&key) {
415 if !lsa.header().is_newer_than(existing.header()) {
416 return false;
417 }
418 }
419
420 self.lsas.insert(key, lsa);
421 true
422 }
423
424 pub fn lookup(&self, ls_type: LsaType, link_state_id: u32, router: u32) -> Option<&Lsa> {
426 let key = LsaKey {
427 ls_type: ls_type as u8,
428 link_state_id,
429 advertising_router: router,
430 };
431 self.lsas.get(&key)
432 }
433
434 pub fn all_lsas(&self) -> Vec<&Lsa> {
436 self.lsas.values().collect()
437 }
438
439 pub fn router_lsas(&self) -> Vec<&RouterLsa> {
441 self.lsas
442 .values()
443 .filter_map(|lsa| match lsa {
444 Lsa::Router(r) => Some(r),
445 _ => None,
446 })
447 .collect()
448 }
449
450 pub fn len(&self) -> usize {
452 self.lsas.len()
453 }
454
455 pub fn is_empty(&self) -> bool {
457 self.lsas.is_empty()
458 }
459
460 pub fn age_lsas(&mut self, ticks: u16) {
463 let mut to_remove = Vec::new();
464
465 for (key, lsa) in &mut self.lsas {
466 let header = lsa.header_mut();
467 header.ls_age = header.ls_age.saturating_add(ticks);
468 if header.ls_age >= MAX_LSA_AGE {
469 to_remove.push(*key);
470 }
471 }
472
473 for key in &to_remove {
474 self.lsas.remove(key);
475 }
476 }
477}
478
479#[derive(Debug, Clone, PartialEq, Eq)]
481struct SpfNode {
482 router_id: u32,
484 cost: u32,
486 next_hop: u32,
488}
489
490impl SpfNode {
491 fn new(router_id: u32, cost: u32, next_hop: u32) -> Self {
492 Self {
493 router_id,
494 cost,
495 next_hop,
496 }
497 }
498}
499
500#[derive(Debug, Clone, PartialEq, Eq)]
502pub struct SpfEntry {
503 pub router_id: u32,
505 pub cost: u32,
507 pub next_hop: u32,
509}
510
511pub struct OspfRouter {
513 pub router_id: u32,
515 pub area_id: u32,
517 neighbors: BTreeMap<u32, OspfNeighbor>,
519 lsdb: LsDatabase,
521 current_tick: u64,
523 priority: u8,
525 network_mask: u32,
527}
528
529impl OspfRouter {
530 pub fn new(router_id: u32, area_id: u32, priority: u8, network_mask: u32) -> Self {
532 Self {
533 router_id,
534 area_id,
535 neighbors: BTreeMap::new(),
536 lsdb: LsDatabase::new(),
537 current_tick: 0,
538 priority,
539 network_mask,
540 }
541 }
542
543 pub fn tick(&mut self, ticks: u64) {
545 self.current_tick += ticks;
546 }
547
548 pub fn lsdb(&self) -> &LsDatabase {
550 &self.lsdb
551 }
552
553 pub fn lsdb_mut(&mut self) -> &mut LsDatabase {
555 &mut self.lsdb
556 }
557
558 pub fn neighbor_count(&self) -> usize {
560 self.neighbors.len()
561 }
562
563 pub fn get_neighbor(&self, router_id: u32) -> Option<&OspfNeighbor> {
565 self.neighbors.get(&router_id)
566 }
567
568 pub fn neighbors(&self) -> Vec<&OspfNeighbor> {
570 self.neighbors.values().collect()
571 }
572
573 pub fn process_hello(&mut self, header: &OspfHeader, hello: &HelloPacket, source: Ipv4Address) {
575 let neighbor_id = header.router_id;
576
577 if hello.hello_interval != HELLO_INTERVAL || hello.dead_interval != DEAD_INTERVAL {
579 return; }
581
582 if let Some(neighbor) = self.neighbors.get_mut(&neighbor_id) {
583 neighbor.last_hello = self.current_tick;
585 neighbor.designated_router = hello.designated_router;
586 neighbor.backup_dr = hello.backup_dr;
587
588 if hello.neighbors.contains(&self.router_id) {
590 neighbor.state = neighbor.state.on_two_way_received();
591 } else {
592 neighbor.state = neighbor.state.on_hello_received();
593 }
594 } else {
595 let mut state = NeighborState::Down;
597 state = state.on_hello_received();
598
599 if hello.neighbors.contains(&self.router_id) {
600 state = state.on_two_way_received();
601 }
602
603 let neighbor = OspfNeighbor {
604 router_id: neighbor_id,
605 state,
606 address: source,
607 priority: hello.priority,
608 last_hello: self.current_tick,
609 designated_router: hello.designated_router,
610 backup_dr: hello.backup_dr,
611 };
612 self.neighbors.insert(neighbor_id, neighbor);
613 }
614 }
615
616 pub fn process_dbd(&mut self, header: &OspfHeader, _lsa_headers: &[LsaHeader]) {
618 let neighbor_id = header.router_id;
619
620 if let Some(neighbor) = self.neighbors.get_mut(&neighbor_id) {
621 match neighbor.state {
622 NeighborState::ExStart => {
623 neighbor.state = neighbor.state.on_negotiation_done();
624 }
625 NeighborState::Exchange => {
626 neighbor.state = neighbor.state.on_exchange_done();
627 }
628 NeighborState::Loading => {
629 neighbor.state = neighbor.state.on_loading_done();
630 }
631 _ => {}
632 }
633 }
634 }
635
636 pub fn install_lsa(&mut self, lsa: Lsa) -> bool {
639 self.lsdb.install(lsa)
640 }
641
642 pub fn check_dead_neighbors(&mut self) {
644 let dead_interval = u64::from(DEAD_INTERVAL);
645 let current = self.current_tick;
646 let mut dead_ids = Vec::new();
647
648 for (id, neighbor) in &self.neighbors {
649 if current.saturating_sub(neighbor.last_hello) >= dead_interval {
650 dead_ids.push(*id);
651 }
652 }
653
654 for id in &dead_ids {
655 self.neighbors.remove(id);
656 }
657 }
658
659 pub fn generate_hello(&self) -> HelloPacket {
661 let mut hello = HelloPacket::new(self.network_mask, self.priority);
662
663 let (dr, bdr) = self.elect_dr_bdr();
665 hello.designated_router = dr;
666 hello.backup_dr = bdr;
667
668 for neighbor_id in self.neighbors.keys() {
670 hello.neighbors.push(*neighbor_id);
671 }
672
673 hello
674 }
675
676 fn elect_dr_bdr(&self) -> (u32, u32) {
678 let mut candidates: Vec<(u8, u32)> = Vec::new();
681
682 if self.priority > 0 {
683 candidates.push((self.priority, self.router_id));
684 }
685
686 for neighbor in self.neighbors.values() {
687 if neighbor.priority > 0
688 && (neighbor.state == NeighborState::TwoWay
689 || neighbor.state == NeighborState::Full)
690 {
691 candidates.push((neighbor.priority, neighbor.router_id));
692 }
693 }
694
695 if candidates.is_empty() {
696 return (0, 0);
697 }
698
699 candidates.sort_by(|a, b| b.0.cmp(&a.0).then(b.1.cmp(&a.1)));
701
702 let dr = candidates[0].1;
703 let bdr = if candidates.len() > 1 {
704 candidates[1].1
705 } else {
706 0
707 };
708
709 (dr, bdr)
710 }
711
712 pub fn run_spf(&self) -> Vec<SpfEntry> {
715 let mut result = Vec::new();
716 let mut visited: BTreeMap<u32, SpfEntry> = BTreeMap::new();
717
718 let mut candidates: Vec<SpfNode> = Vec::new();
721
722 candidates.push(SpfNode::new(self.router_id, 0, 0));
724
725 while !candidates.is_empty() {
726 let min_idx = find_min_cost(&candidates);
728 let current = candidates.swap_remove(min_idx);
729
730 if visited.contains_key(¤t.router_id) {
732 continue;
733 }
734
735 let entry = SpfEntry {
737 router_id: current.router_id,
738 cost: current.cost,
739 next_hop: current.next_hop,
740 };
741 visited.insert(current.router_id, entry.clone());
742
743 if current.router_id != self.router_id {
744 result.push(entry);
745 }
746
747 let router_lsas = self.lsdb.router_lsas();
749 for rlsa in &router_lsas {
750 if rlsa.header.advertising_router != current.router_id {
751 continue;
752 }
753
754 for link in &rlsa.links {
755 match link.link_type {
756 RouterLinkType::PointToPoint | RouterLinkType::Transit => {
757 let neighbor_id = link.link_id;
758 if visited.contains_key(&neighbor_id) {
759 continue;
760 }
761
762 let new_cost = current.cost.saturating_add(link.metric);
763
764 let next_hop = if current.router_id == self.router_id {
766 neighbor_id
767 } else {
768 current.next_hop
769 };
770
771 candidates.push(SpfNode::new(neighbor_id, new_cost, next_hop));
772 }
773 RouterLinkType::Stub | RouterLinkType::Virtual => {
774 }
778 }
779 }
780 }
781 }
782
783 result
784 }
785}
786
787fn find_min_cost(candidates: &[SpfNode]) -> usize {
789 let mut min_idx = 0;
790 let mut min_cost = candidates[0].cost;
791
792 for (i, node) in candidates.iter().enumerate().skip(1) {
793 if node.cost < min_cost {
794 min_cost = node.cost;
795 min_idx = i;
796 }
797 }
798
799 min_idx
800}
801
802pub fn serialize_header(header: &OspfHeader) -> Vec<u8> {
804 let mut buf = Vec::with_capacity(24);
805 buf.push(header.version);
806 buf.push(header.packet_type as u8);
807 buf.extend_from_slice(&header.packet_length.to_be_bytes());
808 buf.extend_from_slice(&header.router_id.to_be_bytes());
809 buf.extend_from_slice(&header.area_id.to_be_bytes());
810 buf.extend_from_slice(&header.checksum.to_be_bytes());
811 buf.extend_from_slice(&(header.auth_type as u16).to_be_bytes());
812 buf.extend_from_slice(&[0u8; 8]);
814 buf
815}
816
817pub fn deserialize_header(data: &[u8]) -> Option<OspfHeader> {
819 if data.len() < 24 {
820 return None;
821 }
822
823 let version = data[0];
824 if version != OSPF_VERSION {
825 return None;
826 }
827
828 let packet_type = OspfPacketType::from_u8(data[1])?;
829 let packet_length = u16::from_be_bytes([data[2], data[3]]);
830 let router_id = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
831 let area_id = u32::from_be_bytes([data[8], data[9], data[10], data[11]]);
832 let checksum = u16::from_be_bytes([data[12], data[13]]);
833 let auth_type_val = u16::from_be_bytes([data[14], data[15]]);
834
835 let auth_type = match auth_type_val {
836 0 => AuthType::None,
837 1 => AuthType::SimplePassword,
838 2 => AuthType::CryptographicMd5,
839 _ => return None,
840 };
841
842 Some(OspfHeader {
843 version,
844 packet_type,
845 packet_length,
846 router_id,
847 area_id,
848 checksum,
849 auth_type,
850 })
851}
852
853#[cfg(test)]
854mod tests {
855 use super::*;
856
857 #[test]
858 fn test_neighbor_state_transitions() {
859 let state = NeighborState::Down;
860 assert_eq!(state.on_hello_received(), NeighborState::Init);
861 assert_eq!(
862 state.on_hello_received().on_two_way_received(),
863 NeighborState::TwoWay
864 );
865 assert_eq!(
866 NeighborState::TwoWay.on_adjacency_ok(),
867 NeighborState::ExStart
868 );
869 assert_eq!(
870 NeighborState::ExStart.on_negotiation_done(),
871 NeighborState::Exchange
872 );
873 assert_eq!(
874 NeighborState::Exchange.on_exchange_done(),
875 NeighborState::Loading
876 );
877 assert_eq!(
878 NeighborState::Loading.on_loading_done(),
879 NeighborState::Full
880 );
881 }
882
883 #[test]
884 fn test_neighbor_state_kill() {
885 assert_eq!(NeighborState::Full.on_kill(), NeighborState::Down);
886 assert_eq!(NeighborState::Exchange.on_kill(), NeighborState::Down);
887 }
888
889 #[test]
890 fn test_neighbor_state_is_adjacent() {
891 assert!(!NeighborState::Down.is_adjacent());
892 assert!(!NeighborState::Init.is_adjacent());
893 assert!(!NeighborState::TwoWay.is_adjacent());
894 assert!(NeighborState::Full.is_adjacent());
895 }
896
897 #[test]
898 fn test_lsa_header_newer() {
899 let h1 = LsaHeader {
900 ls_age: 0,
901 options: 0,
902 ls_type: LsaType::RouterLsa,
903 link_state_id: 1,
904 advertising_router: 1,
905 seq_number: 5,
906 checksum: 0,
907 length: 0,
908 };
909
910 let h2 = LsaHeader {
911 seq_number: 10,
912 ..h1
913 };
914
915 assert!(h2.is_newer_than(&h1));
916 assert!(!h1.is_newer_than(&h2));
917 assert!(!h1.is_newer_than(&h1));
918 }
919
920 #[test]
921 fn test_lsdb_install_and_lookup() {
922 let mut db = LsDatabase::new();
923
924 let lsa = Lsa::Router(RouterLsa {
925 header: LsaHeader::new(LsaType::RouterLsa, 1, 1),
926 flags: 0,
927 links: Vec::new(),
928 });
929
930 assert!(db.install(lsa));
931 assert_eq!(db.len(), 1);
932 assert!(db.lookup(LsaType::RouterLsa, 1, 1).is_some());
933 assert!(db.lookup(LsaType::RouterLsa, 2, 1).is_none());
934 }
935
936 #[test]
937 fn test_lsdb_reject_older() {
938 let mut db = LsDatabase::new();
939
940 let mut header = LsaHeader::new(LsaType::RouterLsa, 1, 1);
941 header.seq_number = 10;
942
943 let lsa = Lsa::Router(RouterLsa {
944 header,
945 flags: 0,
946 links: Vec::new(),
947 });
948 assert!(db.install(lsa));
949
950 let mut older_header = LsaHeader::new(LsaType::RouterLsa, 1, 1);
952 older_header.seq_number = 5;
953
954 let older_lsa = Lsa::Router(RouterLsa {
955 header: older_header,
956 flags: 0,
957 links: Vec::new(),
958 });
959 assert!(!db.install(older_lsa));
960 assert_eq!(db.len(), 1);
961 }
962
963 #[test]
964 fn test_lsdb_age() {
965 let mut db = LsDatabase::new();
966
967 let lsa = Lsa::Router(RouterLsa {
968 header: LsaHeader::new(LsaType::RouterLsa, 1, 1),
969 flags: 0,
970 links: Vec::new(),
971 });
972 db.install(lsa);
973
974 db.age_lsas(MAX_LSA_AGE);
975 assert!(db.is_empty());
976 }
977
978 #[test]
979 fn test_ospf_header_serialize_deserialize() {
980 let header = OspfHeader::new(OspfPacketType::Hello, 0x01020304, 0);
981 let bytes = serialize_header(&header);
982 assert_eq!(bytes.len(), 24);
983
984 let decoded = deserialize_header(&bytes).unwrap();
985 assert_eq!(decoded.version, OSPF_VERSION);
986 assert_eq!(decoded.packet_type, OspfPacketType::Hello);
987 assert_eq!(decoded.router_id, 0x01020304);
988 assert_eq!(decoded.area_id, 0);
989 assert_eq!(decoded.auth_type, AuthType::None);
990 }
991
992 #[test]
993 fn test_hello_generation() {
994 let router = OspfRouter::new(1, 0, 1, 0xFFFFFF00);
995 let hello = router.generate_hello();
996
997 assert_eq!(hello.network_mask, 0xFFFFFF00);
998 assert_eq!(hello.hello_interval, HELLO_INTERVAL);
999 assert_eq!(hello.dead_interval, DEAD_INTERVAL);
1000 assert!(hello.neighbors.is_empty());
1001 }
1002
1003 #[test]
1004 fn test_process_hello_new_neighbor() {
1005 let mut router = OspfRouter::new(1, 0, 1, 0xFFFFFF00);
1006
1007 let header = OspfHeader::new(OspfPacketType::Hello, 2, 0);
1008 let mut hello = HelloPacket::new(0xFFFFFF00, 1);
1009 hello.neighbors.push(1); router.process_hello(&header, &hello, Ipv4Address::new(10, 0, 0, 2));
1012 assert_eq!(router.neighbor_count(), 1);
1013
1014 let neighbor = router.get_neighbor(2).unwrap();
1015 assert_eq!(neighbor.state, NeighborState::TwoWay);
1016 }
1017
1018 #[test]
1019 fn test_process_hello_one_way() {
1020 let mut router = OspfRouter::new(1, 0, 1, 0xFFFFFF00);
1021
1022 let header = OspfHeader::new(OspfPacketType::Hello, 2, 0);
1023 let hello = HelloPacket::new(0xFFFFFF00, 1);
1024 router.process_hello(&header, &hello, Ipv4Address::new(10, 0, 0, 2));
1027 let neighbor = router.get_neighbor(2).unwrap();
1028 assert_eq!(neighbor.state, NeighborState::Init);
1029 }
1030
1031 #[test]
1032 fn test_dead_neighbor_removal() {
1033 let mut router = OspfRouter::new(1, 0, 1, 0xFFFFFF00);
1034
1035 let header = OspfHeader::new(OspfPacketType::Hello, 2, 0);
1036 let hello = HelloPacket::new(0xFFFFFF00, 1);
1037 router.process_hello(&header, &hello, Ipv4Address::new(10, 0, 0, 2));
1038 assert_eq!(router.neighbor_count(), 1);
1039
1040 router.tick(u64::from(DEAD_INTERVAL));
1041 router.check_dead_neighbors();
1042 assert_eq!(router.neighbor_count(), 0);
1043 }
1044
1045 #[test]
1046 fn test_dr_election() {
1047 let mut router = OspfRouter::new(1, 0, 1, 0xFFFFFF00);
1048
1049 let header = OspfHeader::new(OspfPacketType::Hello, 2, 0);
1051 let mut hello = HelloPacket::new(0xFFFFFF00, 2); hello.neighbors.push(1);
1053 router.process_hello(&header, &hello, Ipv4Address::new(10, 0, 0, 2));
1054
1055 let generated_hello = router.generate_hello();
1056 assert_eq!(generated_hello.designated_router, 2);
1058 assert_eq!(generated_hello.backup_dr, 1);
1059 }
1060
1061 #[test]
1062 fn test_spf_simple_topology() {
1063 let router = OspfRouter::new(1, 0, 1, 0xFFFFFF00);
1065
1066 let r1_lsa = Lsa::Router(RouterLsa {
1068 header: LsaHeader::new(LsaType::RouterLsa, 1, 1),
1069 flags: 0,
1070 links: alloc::vec![RouterLink {
1071 link_type: RouterLinkType::PointToPoint,
1072 link_id: 2,
1073 link_data: 0x0A000001,
1074 metric: 10,
1075 }],
1076 });
1077
1078 let r2_lsa = Lsa::Router(RouterLsa {
1080 header: LsaHeader::new(LsaType::RouterLsa, 2, 2),
1081 flags: 0,
1082 links: alloc::vec![
1083 RouterLink {
1084 link_type: RouterLinkType::PointToPoint,
1085 link_id: 1,
1086 link_data: 0x0A000002,
1087 metric: 10,
1088 },
1089 RouterLink {
1090 link_type: RouterLinkType::PointToPoint,
1091 link_id: 3,
1092 link_data: 0x0A000002,
1093 metric: 5,
1094 },
1095 ],
1096 });
1097
1098 let r3_lsa = Lsa::Router(RouterLsa {
1100 header: LsaHeader::new(LsaType::RouterLsa, 3, 3),
1101 flags: 0,
1102 links: alloc::vec![RouterLink {
1103 link_type: RouterLinkType::PointToPoint,
1104 link_id: 2,
1105 link_data: 0x0A000003,
1106 metric: 5,
1107 }],
1108 });
1109
1110 let mut test_router = OspfRouter::new(1, 0, 1, 0xFFFFFF00);
1112 test_router.install_lsa(r1_lsa);
1113 test_router.install_lsa(r2_lsa);
1114 test_router.install_lsa(r3_lsa);
1115
1116 let spf_result = test_router.run_spf();
1117
1118 assert_eq!(spf_result.len(), 2);
1120
1121 let r2_entry = spf_result.iter().find(|e| e.router_id == 2).unwrap();
1122 assert_eq!(r2_entry.cost, 10);
1123 assert_eq!(r2_entry.next_hop, 2); let r3_entry = spf_result.iter().find(|e| e.router_id == 3).unwrap();
1126 assert_eq!(r3_entry.cost, 15); assert_eq!(r3_entry.next_hop, 2); }
1129
1130 #[test]
1131 fn test_spf_shortest_path_preferred() {
1132 let mut router = OspfRouter::new(1, 0, 1, 0xFFFFFF00);
1136
1137 let r1_lsa = Lsa::Router(RouterLsa {
1138 header: LsaHeader::new(LsaType::RouterLsa, 1, 1),
1139 flags: 0,
1140 links: alloc::vec![
1141 RouterLink {
1142 link_type: RouterLinkType::PointToPoint,
1143 link_id: 2,
1144 link_data: 0,
1145 metric: 1,
1146 },
1147 RouterLink {
1148 link_type: RouterLinkType::PointToPoint,
1149 link_id: 3,
1150 link_data: 0,
1151 metric: 10,
1152 },
1153 ],
1154 });
1155
1156 let r2_lsa = Lsa::Router(RouterLsa {
1157 header: LsaHeader::new(LsaType::RouterLsa, 2, 2),
1158 flags: 0,
1159 links: alloc::vec![
1160 RouterLink {
1161 link_type: RouterLinkType::PointToPoint,
1162 link_id: 1,
1163 link_data: 0,
1164 metric: 1,
1165 },
1166 RouterLink {
1167 link_type: RouterLinkType::PointToPoint,
1168 link_id: 3,
1169 link_data: 0,
1170 metric: 1,
1171 },
1172 ],
1173 });
1174
1175 let r3_lsa = Lsa::Router(RouterLsa {
1176 header: LsaHeader::new(LsaType::RouterLsa, 3, 3),
1177 flags: 0,
1178 links: alloc::vec![
1179 RouterLink {
1180 link_type: RouterLinkType::PointToPoint,
1181 link_id: 2,
1182 link_data: 0,
1183 metric: 1,
1184 },
1185 RouterLink {
1186 link_type: RouterLinkType::PointToPoint,
1187 link_id: 1,
1188 link_data: 0,
1189 metric: 10,
1190 },
1191 ],
1192 });
1193
1194 router.install_lsa(r1_lsa);
1195 router.install_lsa(r2_lsa);
1196 router.install_lsa(r3_lsa);
1197
1198 let spf_result = router.run_spf();
1199 let r3_entry = spf_result.iter().find(|e| e.router_id == 3).unwrap();
1200 assert_eq!(r3_entry.cost, 2); assert_eq!(r3_entry.next_hop, 2);
1202 }
1203}