1use crate::models::*;
4use num_enum::{FromPrimitive, IntoPrimitive};
5use std::collections::HashMap;
6use std::net::{Ipv4Addr, Ipv6Addr};
7
8#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, FromPrimitive, IntoPrimitive)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11#[repr(u16)]
12pub enum NlriType {
13 #[num_enum(default)]
14 Reserved = 0,
15 Node = 1,
16 Link = 2,
17 Ipv4TopologyPrefix = 3,
18 Ipv6TopologyPrefix = 4,
19 SrPolicyCandidatePath = 5,
20 Srv6Sid = 6,
21 StubLink = 7,
22}
23
24#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, FromPrimitive, IntoPrimitive)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27#[repr(u8)]
28pub enum ProtocolId {
29 #[num_enum(default)]
30 Reserved = 0,
31 IsisL1 = 1,
32 IsisL2 = 2,
33 Ospfv2 = 3,
34 Direct = 4,
35 Static = 5,
36 Ospfv3 = 6,
37 Bgp = 7,
38 RsvpTe = 8,
39 SegmentRouting = 9,
40}
41
42#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, FromPrimitive, IntoPrimitive)]
44#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
45#[repr(u16)]
46pub enum NodeDescriptorType {
47 #[num_enum(default)]
48 Reserved = 0,
49 AutonomousSystem = 512,
50 BgpLsIdentifier = 513,
51 OspfAreaId = 514,
52 IgpRouterId = 515,
53}
54
55#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, FromPrimitive, IntoPrimitive)]
57#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
58#[repr(u16)]
59pub enum LinkDescriptorType {
60 #[num_enum(default)]
61 Reserved = 0,
62 LinkLocalRemoteIdentifiers = 258,
63 Ipv4InterfaceAddress = 259,
64 Ipv4NeighborAddress = 260,
65 Ipv6InterfaceAddress = 261,
66 Ipv6NeighborAddress = 262,
67 MultiTopologyId = 263,
68}
69
70#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, FromPrimitive, IntoPrimitive)]
72#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
73#[repr(u16)]
74pub enum PrefixDescriptorType {
75 #[num_enum(default)]
76 Reserved = 0,
77 MultiTopologyId = 263,
78 OspfRouteType = 264,
79 IpReachabilityInformation = 265,
80}
81
82#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, FromPrimitive, IntoPrimitive)]
84#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
85#[repr(u16)]
86pub enum NodeAttributeType {
87 #[num_enum(default)]
88 Reserved = 0,
89 NodeFlagBits = 1024,
90 OpaqueNodeAttribute = 1025,
91 NodeName = 1026,
92 IsisAreaIdentifier = 1027,
93 Ipv4RouterIdOfLocalNode = 1028,
94 Ipv6RouterIdOfLocalNode = 1029,
95 SrCapabilities = 1034,
96 SrAlgorithm = 1035,
97 SrLocalBlock = 1036,
98 SrmsPreference = 1037,
99}
100
101#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, FromPrimitive, IntoPrimitive)]
103#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
104#[repr(u16)]
105pub enum LinkAttributeType {
106 #[num_enum(default)]
107 Reserved = 0,
108 Ipv4RouterIdOfLocalNode = 1028,
109 Ipv6RouterIdOfLocalNode = 1029,
110 Ipv4RouterIdOfRemoteNode = 1030,
111 Ipv6RouterIdOfRemoteNode = 1031,
112 AdministrativeGroup = 1088,
113 MaximumLinkBandwidth = 1089,
114 MaxReservableLinkBandwidth = 1090,
115 UnreservedBandwidth = 1091,
116 TeDefaultMetric = 1092,
117 LinkProtectionType = 1093,
118 MplsProtocolMask = 1094,
119 IgpMetric = 1095,
120 SharedRiskLinkGroups = 1096,
121 OpaqueLinkAttribute = 1097,
122 LinkName = 1098,
123 SrAdjacencySid = 1099,
124 SrLanAdjacencySid = 1100,
125 PeerNodeSid = 1101,
126 PeerAdjacencySid = 1102,
127 PeerSetSid = 1103,
128 UnidirectionalLinkDelay = 1114,
130 MinMaxUnidirectionalLinkDelay = 1115,
132 UnidirectionalDelayVariation = 1116,
134 UnidirectionalLinkLoss = 1117,
136 UnidirectionalResidualBandwidth = 1118,
138 UnidirectionalAvailableBandwidth = 1119,
140 UnidirectionalUtilizedBandwidth = 1120,
142 L2BundleMemberAttributes = 1172,
144 ApplicationSpecificLinkAttributes = 1122,
146}
147
148#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, FromPrimitive, IntoPrimitive)]
150#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
151#[repr(u16)]
152pub enum PrefixAttributeType {
153 #[num_enum(default)]
154 Reserved = 0,
155 IgpFlags = 1152,
156 IgpRouteTag = 1153,
157 IgpExtendedRouteTag = 1154,
158 PrefixMetric = 1155,
159 OspfForwardingAddress = 1156,
160 OpaquePrefixAttribute = 1157,
161 PrefixSid = 1158,
162 RangeSid = 1159,
163 SidLabelIndex = 1161,
164 SidLabelBinding = 1162,
165 Srv6LocatorTlv = 1163,
166 PrefixAttributeFlags = 1170,
168 SourceRouterIdentifier = 1171,
170 SourceOspfRouterId = 1174,
172}
173
174#[derive(Debug, PartialEq, Clone, Eq)]
176#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
177pub struct Tlv {
178 pub tlv_type: u16,
179 pub value: Vec<u8>,
180}
181
182impl Tlv {
183 pub fn new(tlv_type: u16, value: Vec<u8>) -> Self {
184 Self { tlv_type, value }
185 }
186}
187
188#[derive(Debug, PartialEq, Clone, Eq)]
190#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
191#[derive(Default)]
192pub struct NodeDescriptor {
193 pub autonomous_system: Option<u32>,
194 pub bgp_ls_identifier: Option<u32>,
195 pub ospf_area_id: Option<u32>,
196 pub igp_router_id: Option<Vec<u8>>,
197 pub unknown_tlvs: Vec<Tlv>,
198}
199
200#[derive(Debug, PartialEq, Clone, Eq)]
202#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
203#[derive(Default)]
204pub struct LinkDescriptor {
205 pub link_local_remote_identifiers: Option<(u32, u32)>,
206 pub ipv4_interface_address: Option<Ipv4Addr>,
207 pub ipv4_neighbor_address: Option<Ipv4Addr>,
208 pub ipv6_interface_address: Option<Ipv6Addr>,
209 pub ipv6_neighbor_address: Option<Ipv6Addr>,
210 pub multi_topology_id: Option<u16>,
211 pub unknown_tlvs: Vec<Tlv>,
212}
213
214#[derive(Debug, PartialEq, Clone, Eq)]
216#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
217#[derive(Default)]
218pub struct PrefixDescriptor {
219 pub multi_topology_id: Option<u16>,
220 pub ospf_route_type: Option<u8>,
221 pub ip_reachability_information: Option<NetworkPrefix>,
222 pub unknown_tlvs: Vec<Tlv>,
223}
224
225#[derive(Debug, PartialEq, Clone, Eq)]
227#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
228pub struct LinkStateNlri {
229 pub nlri_type: NlriType,
230 pub protocol_id: ProtocolId,
231 pub identifier: u64,
232 pub local_node_descriptors: NodeDescriptor,
233 pub remote_node_descriptors: Option<NodeDescriptor>,
234 pub link_descriptors: Option<LinkDescriptor>,
235 pub prefix_descriptors: Option<PrefixDescriptor>,
236}
237
238impl LinkStateNlri {
239 pub fn new_node_nlri(
240 protocol_id: ProtocolId,
241 identifier: u64,
242 local_node_descriptors: NodeDescriptor,
243 ) -> Self {
244 Self {
245 nlri_type: NlriType::Node,
246 protocol_id,
247 identifier,
248 local_node_descriptors,
249 remote_node_descriptors: None,
250 link_descriptors: None,
251 prefix_descriptors: None,
252 }
253 }
254
255 pub fn new_link_nlri(
256 protocol_id: ProtocolId,
257 identifier: u64,
258 local_node_descriptors: NodeDescriptor,
259 remote_node_descriptors: NodeDescriptor,
260 link_descriptors: LinkDescriptor,
261 ) -> Self {
262 Self {
263 nlri_type: NlriType::Link,
264 protocol_id,
265 identifier,
266 local_node_descriptors,
267 remote_node_descriptors: Some(remote_node_descriptors),
268 link_descriptors: Some(link_descriptors),
269 prefix_descriptors: None,
270 }
271 }
272
273 pub fn new_prefix_nlri(
274 nlri_type: NlriType, protocol_id: ProtocolId,
276 identifier: u64,
277 local_node_descriptors: NodeDescriptor,
278 prefix_descriptors: PrefixDescriptor,
279 ) -> Self {
280 Self {
281 nlri_type,
282 protocol_id,
283 identifier,
284 local_node_descriptors,
285 remote_node_descriptors: None,
286 link_descriptors: None,
287 prefix_descriptors: Some(prefix_descriptors),
288 }
289 }
290}
291
292#[derive(Debug, PartialEq, Clone, Eq)]
294#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
295#[derive(Default)]
296pub struct LinkStateAttribute {
297 pub node_attributes: HashMap<NodeAttributeType, Vec<u8>>,
298 pub link_attributes: HashMap<LinkAttributeType, Vec<u8>>,
299 pub prefix_attributes: HashMap<PrefixAttributeType, Vec<u8>>,
300 pub unknown_attributes: Vec<Tlv>,
301}
302
303impl LinkStateAttribute {
304 pub fn new() -> Self {
305 Self::default()
306 }
307
308 pub fn add_node_attribute(&mut self, attr_type: NodeAttributeType, value: Vec<u8>) {
309 self.node_attributes.insert(attr_type, value);
310 }
311
312 pub fn add_link_attribute(&mut self, attr_type: LinkAttributeType, value: Vec<u8>) {
313 self.link_attributes.insert(attr_type, value);
314 }
315
316 pub fn add_prefix_attribute(&mut self, attr_type: PrefixAttributeType, value: Vec<u8>) {
317 self.prefix_attributes.insert(attr_type, value);
318 }
319
320 pub fn add_unknown_attribute(&mut self, tlv: Tlv) {
321 self.unknown_attributes.push(tlv);
322 }
323
324 pub fn get_node_name(&self) -> Option<String> {
325 self.node_attributes
326 .get(&NodeAttributeType::NodeName)
327 .and_then(|bytes| String::from_utf8(bytes.clone()).ok())
328 }
329
330 pub fn get_link_name(&self) -> Option<String> {
331 self.link_attributes
332 .get(&LinkAttributeType::LinkName)
333 .and_then(|bytes| String::from_utf8(bytes.clone()).ok())
334 }
335
336 pub fn get_node_flags(&self) -> Option<u8> {
337 self.node_attributes
338 .get(&NodeAttributeType::NodeFlagBits)
339 .and_then(|bytes| bytes.first().copied())
340 }
341
342 pub fn get_administrative_group(&self) -> Option<u32> {
343 self.link_attributes
344 .get(&LinkAttributeType::AdministrativeGroup)
345 .and_then(|bytes| {
346 if bytes.len() >= 4 {
347 Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
348 } else {
349 None
350 }
351 })
352 }
353
354 pub fn get_maximum_link_bandwidth(&self) -> Option<f32> {
355 self.link_attributes
356 .get(&LinkAttributeType::MaximumLinkBandwidth)
357 .and_then(|bytes| {
358 if bytes.len() >= 4 {
359 Some(f32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
360 } else {
361 None
362 }
363 })
364 }
365
366 pub fn get_igp_metric(&self) -> Option<u32> {
367 self.link_attributes
368 .get(&LinkAttributeType::IgpMetric)
369 .and_then(|bytes| match bytes.len() {
370 1 => Some(bytes[0] as u32),
371 2 => Some(u16::from_be_bytes([bytes[0], bytes[1]]) as u32),
372 3 => Some(
373 (u32::from(bytes[0]) << 16) + (u32::from(bytes[1]) << 8) + u32::from(bytes[2]),
374 ),
375 _ => None,
376 })
377 }
378
379 pub fn get_prefix_metric(&self) -> Option<u32> {
380 self.prefix_attributes
381 .get(&PrefixAttributeType::PrefixMetric)
382 .and_then(|bytes| {
383 if bytes.len() >= 4 {
384 Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
385 } else {
386 None
387 }
388 })
389 }
390
391 pub fn get_unidirectional_link_delay(&self) -> Option<u32> {
393 self.link_attributes
394 .get(&LinkAttributeType::UnidirectionalLinkDelay)
395 .and_then(|bytes| {
396 if bytes.len() >= 4 {
397 Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) & 0x00FFFFFF)
398 } else {
399 None
400 }
401 })
402 }
403
404 pub fn get_min_max_unidirectional_link_delay(&self) -> Option<(u32, u32)> {
407 self.link_attributes
408 .get(&LinkAttributeType::MinMaxUnidirectionalLinkDelay)
409 .and_then(|bytes| {
410 if bytes.len() >= 8 {
411 let min_delay =
412 u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) & 0x00FFFFFF;
413 let max_delay =
414 u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) & 0x00FFFFFF;
415 Some((min_delay, max_delay))
416 } else {
417 None
418 }
419 })
420 }
421
422 pub fn get_unidirectional_delay_variation(&self) -> Option<u32> {
424 self.link_attributes
425 .get(&LinkAttributeType::UnidirectionalDelayVariation)
426 .and_then(|bytes| {
427 if bytes.len() >= 4 {
428 Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) & 0x00FFFFFF)
429 } else {
430 None
431 }
432 })
433 }
434
435 pub fn get_unidirectional_link_loss(&self) -> Option<f32> {
438 self.link_attributes
439 .get(&LinkAttributeType::UnidirectionalLinkLoss)
440 .and_then(|bytes| {
441 if bytes.len() >= 4 {
442 let raw_value =
443 u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) & 0x00FFFFFF;
444 Some(raw_value as f32 * 0.000003)
445 } else {
446 None
447 }
448 })
449 }
450
451 pub fn get_unidirectional_residual_bandwidth(&self) -> Option<f32> {
453 self.link_attributes
454 .get(&LinkAttributeType::UnidirectionalResidualBandwidth)
455 .and_then(|bytes| {
456 if bytes.len() >= 4 {
457 Some(f32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
458 } else {
459 None
460 }
461 })
462 }
463
464 pub fn get_unidirectional_available_bandwidth(&self) -> Option<f32> {
466 self.link_attributes
467 .get(&LinkAttributeType::UnidirectionalAvailableBandwidth)
468 .and_then(|bytes| {
469 if bytes.len() >= 4 {
470 Some(f32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
471 } else {
472 None
473 }
474 })
475 }
476
477 pub fn get_unidirectional_utilized_bandwidth(&self) -> Option<f32> {
479 self.link_attributes
480 .get(&LinkAttributeType::UnidirectionalUtilizedBandwidth)
481 .and_then(|bytes| {
482 if bytes.len() >= 4 {
483 Some(f32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
484 } else {
485 None
486 }
487 })
488 }
489}
490
491#[cfg(test)]
492mod tests {
493 use super::*;
494 use std::str::FromStr;
495
496 #[test]
497 fn test_nlri_type_conversion() {
498 assert_eq!(NlriType::Node as u16, 1);
499 assert_eq!(NlriType::Link as u16, 2);
500 assert_eq!(NlriType::Ipv4TopologyPrefix as u16, 3);
501 assert_eq!(NlriType::Ipv6TopologyPrefix as u16, 4);
502 }
503
504 #[test]
505 fn test_protocol_id_conversion() {
506 assert_eq!(ProtocolId::IsisL1 as u8, 1);
507 assert_eq!(ProtocolId::Ospfv2 as u8, 3);
508 assert_eq!(ProtocolId::Ospfv3 as u8, 6);
509 }
510
511 #[test]
512 fn test_node_nlri_creation() {
513 let node_desc = NodeDescriptor {
514 autonomous_system: Some(65001),
515 igp_router_id: Some(vec![192, 168, 1, 1]),
516 ..Default::default()
517 };
518
519 let nlri = LinkStateNlri::new_node_nlri(ProtocolId::Ospfv2, 123456, node_desc);
520
521 assert_eq!(nlri.nlri_type, NlriType::Node);
522 assert_eq!(nlri.protocol_id, ProtocolId::Ospfv2);
523 assert_eq!(nlri.identifier, 123456);
524 assert_eq!(nlri.local_node_descriptors.autonomous_system, Some(65001));
525 assert!(nlri.remote_node_descriptors.is_none());
526 assert!(nlri.link_descriptors.is_none());
527 assert!(nlri.prefix_descriptors.is_none());
528 }
529
530 #[test]
531 fn test_link_nlri_creation() {
532 let local_desc = NodeDescriptor::default();
533 let remote_desc = NodeDescriptor::default();
534 let link_desc = LinkDescriptor::default();
535
536 let nlri = LinkStateNlri::new_link_nlri(
537 ProtocolId::IsisL1,
538 789012,
539 local_desc,
540 remote_desc,
541 link_desc,
542 );
543
544 assert_eq!(nlri.nlri_type, NlriType::Link);
545 assert_eq!(nlri.protocol_id, ProtocolId::IsisL1);
546 assert_eq!(nlri.identifier, 789012);
547 assert!(nlri.remote_node_descriptors.is_some());
548 assert!(nlri.link_descriptors.is_some());
549 assert!(nlri.prefix_descriptors.is_none());
550 }
551
552 #[test]
553 fn test_prefix_nlri_creation() {
554 let local_desc = NodeDescriptor::default();
555 let prefix_desc = PrefixDescriptor {
556 ip_reachability_information: Some(NetworkPrefix::from_str("192.168.1.0/24").unwrap()),
557 ..Default::default()
558 };
559
560 let nlri = LinkStateNlri::new_prefix_nlri(
561 NlriType::Ipv4TopologyPrefix,
562 ProtocolId::Ospfv2,
563 345678,
564 local_desc,
565 prefix_desc,
566 );
567
568 assert_eq!(nlri.nlri_type, NlriType::Ipv4TopologyPrefix);
569 assert_eq!(nlri.protocol_id, ProtocolId::Ospfv2);
570 assert_eq!(nlri.identifier, 345678);
571 assert!(nlri.remote_node_descriptors.is_none());
572 assert!(nlri.link_descriptors.is_none());
573 assert!(nlri.prefix_descriptors.is_some());
574 }
575
576 #[test]
577 fn test_link_state_attribute() {
578 let mut attr = LinkStateAttribute::new();
579
580 attr.add_node_attribute(NodeAttributeType::NodeName, b"router1".to_vec());
582 assert_eq!(attr.get_node_name(), Some("router1".to_string()));
583
584 attr.add_link_attribute(
586 LinkAttributeType::AdministrativeGroup,
587 vec![0x00, 0x00, 0x00, 0xFF],
588 );
589 assert_eq!(attr.get_administrative_group(), Some(255));
590
591 attr.add_link_attribute(LinkAttributeType::IgpMetric, vec![0x01, 0x00]);
593 assert_eq!(attr.get_igp_metric(), Some(256));
594
595 attr.add_prefix_attribute(
597 PrefixAttributeType::PrefixMetric,
598 vec![0x00, 0x00, 0x03, 0xE8],
599 );
600 assert_eq!(attr.get_prefix_metric(), Some(1000));
601 }
602
603 #[test]
604 fn test_tlv_creation() {
605 let tlv = Tlv::new(1024, vec![0x01, 0x02, 0x03]);
606 assert_eq!(tlv.tlv_type, 1024);
607 assert_eq!(tlv.value, vec![0x01, 0x02, 0x03]);
608 }
609
610 #[test]
611 #[cfg(feature = "serde")]
612 fn test_serde_serialization() {
613 let mut attr = LinkStateAttribute::new();
614 attr.add_node_attribute(NodeAttributeType::NodeName, b"test".to_vec());
615
616 let serialized = serde_json::to_string(&attr).unwrap();
617 let deserialized: LinkStateAttribute = serde_json::from_str(&serialized).unwrap();
618
619 assert_eq!(attr, deserialized);
620 }
621}