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 pub fn length(&self) -> u16 {
188 self.value.len() as u16
189 }
190}
191
192#[derive(Debug, PartialEq, Clone, Eq)]
194#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
195#[derive(Default)]
196pub struct NodeDescriptor {
197 pub autonomous_system: Option<u32>,
198 pub bgp_ls_identifier: Option<u32>,
199 pub ospf_area_id: Option<u32>,
200 pub igp_router_id: Option<Vec<u8>>,
201 pub unknown_tlvs: Vec<Tlv>,
202}
203
204#[derive(Debug, PartialEq, Clone, Eq)]
206#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
207#[derive(Default)]
208pub struct LinkDescriptor {
209 pub link_local_remote_identifiers: Option<(u32, u32)>,
210 pub ipv4_interface_address: Option<Ipv4Addr>,
211 pub ipv4_neighbor_address: Option<Ipv4Addr>,
212 pub ipv6_interface_address: Option<Ipv6Addr>,
213 pub ipv6_neighbor_address: Option<Ipv6Addr>,
214 pub multi_topology_id: Option<u16>,
215 pub unknown_tlvs: Vec<Tlv>,
216}
217
218#[derive(Debug, PartialEq, Clone, Eq)]
220#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
221#[derive(Default)]
222pub struct PrefixDescriptor {
223 pub multi_topology_id: Option<u16>,
224 pub ospf_route_type: Option<u8>,
225 pub ip_reachability_information: Option<NetworkPrefix>,
226 pub unknown_tlvs: Vec<Tlv>,
227}
228
229#[derive(Debug, PartialEq, Clone, Eq)]
231#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
232pub struct LinkStateNlri {
233 pub nlri_type: NlriType,
234 pub protocol_id: ProtocolId,
235 pub identifier: u64,
236 pub local_node_descriptors: NodeDescriptor,
237 pub remote_node_descriptors: Option<NodeDescriptor>,
238 pub link_descriptors: Option<LinkDescriptor>,
239 pub prefix_descriptors: Option<PrefixDescriptor>,
240}
241
242impl LinkStateNlri {
243 pub fn new_node_nlri(
244 protocol_id: ProtocolId,
245 identifier: u64,
246 local_node_descriptors: NodeDescriptor,
247 ) -> Self {
248 Self {
249 nlri_type: NlriType::Node,
250 protocol_id,
251 identifier,
252 local_node_descriptors,
253 remote_node_descriptors: None,
254 link_descriptors: None,
255 prefix_descriptors: None,
256 }
257 }
258
259 pub fn new_link_nlri(
260 protocol_id: ProtocolId,
261 identifier: u64,
262 local_node_descriptors: NodeDescriptor,
263 remote_node_descriptors: NodeDescriptor,
264 link_descriptors: LinkDescriptor,
265 ) -> Self {
266 Self {
267 nlri_type: NlriType::Link,
268 protocol_id,
269 identifier,
270 local_node_descriptors,
271 remote_node_descriptors: Some(remote_node_descriptors),
272 link_descriptors: Some(link_descriptors),
273 prefix_descriptors: None,
274 }
275 }
276
277 pub fn new_prefix_nlri(
278 nlri_type: NlriType, protocol_id: ProtocolId,
280 identifier: u64,
281 local_node_descriptors: NodeDescriptor,
282 prefix_descriptors: PrefixDescriptor,
283 ) -> Self {
284 Self {
285 nlri_type,
286 protocol_id,
287 identifier,
288 local_node_descriptors,
289 remote_node_descriptors: None,
290 link_descriptors: None,
291 prefix_descriptors: Some(prefix_descriptors),
292 }
293 }
294}
295
296#[derive(Debug, PartialEq, Clone, Eq)]
298#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
299#[derive(Default)]
300pub struct LinkStateAttribute {
301 pub node_attributes: HashMap<NodeAttributeType, Vec<u8>>,
302 pub link_attributes: HashMap<LinkAttributeType, Vec<u8>>,
303 pub prefix_attributes: HashMap<PrefixAttributeType, Vec<u8>>,
304 pub unknown_attributes: Vec<Tlv>,
305}
306
307impl LinkStateAttribute {
308 pub fn new() -> Self {
309 Self::default()
310 }
311
312 pub fn add_node_attribute(&mut self, attr_type: NodeAttributeType, value: Vec<u8>) {
313 self.node_attributes.insert(attr_type, value);
314 }
315
316 pub fn add_link_attribute(&mut self, attr_type: LinkAttributeType, value: Vec<u8>) {
317 self.link_attributes.insert(attr_type, value);
318 }
319
320 pub fn add_prefix_attribute(&mut self, attr_type: PrefixAttributeType, value: Vec<u8>) {
321 self.prefix_attributes.insert(attr_type, value);
322 }
323
324 pub fn add_unknown_attribute(&mut self, tlv: Tlv) {
325 self.unknown_attributes.push(tlv);
326 }
327
328 pub fn get_node_name(&self) -> Option<String> {
329 self.node_attributes
330 .get(&NodeAttributeType::NodeName)
331 .and_then(|bytes| String::from_utf8(bytes.clone()).ok())
332 }
333
334 pub fn get_link_name(&self) -> Option<String> {
335 self.link_attributes
336 .get(&LinkAttributeType::LinkName)
337 .and_then(|bytes| String::from_utf8(bytes.clone()).ok())
338 }
339
340 pub fn get_node_flags(&self) -> Option<u8> {
341 self.node_attributes
342 .get(&NodeAttributeType::NodeFlagBits)
343 .and_then(|bytes| bytes.first().copied())
344 }
345
346 pub fn get_administrative_group(&self) -> Option<u32> {
347 self.link_attributes
348 .get(&LinkAttributeType::AdministrativeGroup)
349 .and_then(|bytes| {
350 if bytes.len() >= 4 {
351 Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
352 } else {
353 None
354 }
355 })
356 }
357
358 pub fn get_maximum_link_bandwidth(&self) -> Option<f32> {
359 self.link_attributes
360 .get(&LinkAttributeType::MaximumLinkBandwidth)
361 .and_then(|bytes| {
362 if bytes.len() >= 4 {
363 Some(f32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
364 } else {
365 None
366 }
367 })
368 }
369
370 pub fn get_igp_metric(&self) -> Option<u32> {
371 self.link_attributes
372 .get(&LinkAttributeType::IgpMetric)
373 .and_then(|bytes| match bytes.len() {
374 1 => Some(bytes[0] as u32),
375 2 => Some(u16::from_be_bytes([bytes[0], bytes[1]]) as u32),
376 3 => Some(
377 (u32::from(bytes[0]) << 16) + (u32::from(bytes[1]) << 8) + u32::from(bytes[2]),
378 ),
379 _ => None,
380 })
381 }
382
383 pub fn get_prefix_metric(&self) -> Option<u32> {
384 self.prefix_attributes
385 .get(&PrefixAttributeType::PrefixMetric)
386 .and_then(|bytes| {
387 if bytes.len() >= 4 {
388 Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
389 } else {
390 None
391 }
392 })
393 }
394
395 pub fn get_unidirectional_link_delay(&self) -> Option<u32> {
397 self.link_attributes
398 .get(&LinkAttributeType::UnidirectionalLinkDelay)
399 .and_then(|bytes| {
400 if bytes.len() >= 4 {
401 Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) & 0x00FFFFFF)
402 } else {
403 None
404 }
405 })
406 }
407
408 pub fn get_min_max_unidirectional_link_delay(&self) -> Option<(u32, u32)> {
411 self.link_attributes
412 .get(&LinkAttributeType::MinMaxUnidirectionalLinkDelay)
413 .and_then(|bytes| {
414 if bytes.len() >= 8 {
415 let min_delay =
416 u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) & 0x00FFFFFF;
417 let max_delay =
418 u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) & 0x00FFFFFF;
419 Some((min_delay, max_delay))
420 } else {
421 None
422 }
423 })
424 }
425
426 pub fn get_unidirectional_delay_variation(&self) -> Option<u32> {
428 self.link_attributes
429 .get(&LinkAttributeType::UnidirectionalDelayVariation)
430 .and_then(|bytes| {
431 if bytes.len() >= 4 {
432 Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) & 0x00FFFFFF)
433 } else {
434 None
435 }
436 })
437 }
438
439 pub fn get_unidirectional_link_loss(&self) -> Option<f32> {
442 self.link_attributes
443 .get(&LinkAttributeType::UnidirectionalLinkLoss)
444 .and_then(|bytes| {
445 if bytes.len() >= 4 {
446 let raw_value =
447 u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) & 0x00FFFFFF;
448 Some(raw_value as f32 * 0.000003)
449 } else {
450 None
451 }
452 })
453 }
454
455 pub fn get_unidirectional_residual_bandwidth(&self) -> Option<f32> {
457 self.link_attributes
458 .get(&LinkAttributeType::UnidirectionalResidualBandwidth)
459 .and_then(|bytes| {
460 if bytes.len() >= 4 {
461 Some(f32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
462 } else {
463 None
464 }
465 })
466 }
467
468 pub fn get_unidirectional_available_bandwidth(&self) -> Option<f32> {
470 self.link_attributes
471 .get(&LinkAttributeType::UnidirectionalAvailableBandwidth)
472 .and_then(|bytes| {
473 if bytes.len() >= 4 {
474 Some(f32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
475 } else {
476 None
477 }
478 })
479 }
480
481 pub fn get_unidirectional_utilized_bandwidth(&self) -> Option<f32> {
483 self.link_attributes
484 .get(&LinkAttributeType::UnidirectionalUtilizedBandwidth)
485 .and_then(|bytes| {
486 if bytes.len() >= 4 {
487 Some(f32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
488 } else {
489 None
490 }
491 })
492 }
493}
494
495#[cfg(test)]
496mod tests {
497 use super::*;
498 use std::str::FromStr;
499
500 #[test]
501 fn test_nlri_type_conversion() {
502 assert_eq!(NlriType::Node as u16, 1);
503 assert_eq!(NlriType::Link as u16, 2);
504 assert_eq!(NlriType::Ipv4TopologyPrefix as u16, 3);
505 assert_eq!(NlriType::Ipv6TopologyPrefix as u16, 4);
506 }
507
508 #[test]
509 fn test_protocol_id_conversion() {
510 assert_eq!(ProtocolId::IsisL1 as u8, 1);
511 assert_eq!(ProtocolId::Ospfv2 as u8, 3);
512 assert_eq!(ProtocolId::Ospfv3 as u8, 6);
513 }
514
515 #[test]
516 fn test_node_nlri_creation() {
517 let node_desc = NodeDescriptor {
518 autonomous_system: Some(65001),
519 igp_router_id: Some(vec![192, 168, 1, 1]),
520 ..Default::default()
521 };
522
523 let nlri = LinkStateNlri::new_node_nlri(ProtocolId::Ospfv2, 123456, node_desc);
524
525 assert_eq!(nlri.nlri_type, NlriType::Node);
526 assert_eq!(nlri.protocol_id, ProtocolId::Ospfv2);
527 assert_eq!(nlri.identifier, 123456);
528 assert_eq!(nlri.local_node_descriptors.autonomous_system, Some(65001));
529 assert!(nlri.remote_node_descriptors.is_none());
530 assert!(nlri.link_descriptors.is_none());
531 assert!(nlri.prefix_descriptors.is_none());
532 }
533
534 #[test]
535 fn test_link_nlri_creation() {
536 let local_desc = NodeDescriptor::default();
537 let remote_desc = NodeDescriptor::default();
538 let link_desc = LinkDescriptor::default();
539
540 let nlri = LinkStateNlri::new_link_nlri(
541 ProtocolId::IsisL1,
542 789012,
543 local_desc,
544 remote_desc,
545 link_desc,
546 );
547
548 assert_eq!(nlri.nlri_type, NlriType::Link);
549 assert_eq!(nlri.protocol_id, ProtocolId::IsisL1);
550 assert_eq!(nlri.identifier, 789012);
551 assert!(nlri.remote_node_descriptors.is_some());
552 assert!(nlri.link_descriptors.is_some());
553 assert!(nlri.prefix_descriptors.is_none());
554 }
555
556 #[test]
557 fn test_prefix_nlri_creation() {
558 let local_desc = NodeDescriptor::default();
559 let prefix_desc = PrefixDescriptor {
560 ip_reachability_information: Some(NetworkPrefix::from_str("192.168.1.0/24").unwrap()),
561 ..Default::default()
562 };
563
564 let nlri = LinkStateNlri::new_prefix_nlri(
565 NlriType::Ipv4TopologyPrefix,
566 ProtocolId::Ospfv2,
567 345678,
568 local_desc,
569 prefix_desc,
570 );
571
572 assert_eq!(nlri.nlri_type, NlriType::Ipv4TopologyPrefix);
573 assert_eq!(nlri.protocol_id, ProtocolId::Ospfv2);
574 assert_eq!(nlri.identifier, 345678);
575 assert!(nlri.remote_node_descriptors.is_none());
576 assert!(nlri.link_descriptors.is_none());
577 assert!(nlri.prefix_descriptors.is_some());
578 }
579
580 #[test]
581 fn test_link_state_attribute() {
582 let mut attr = LinkStateAttribute::new();
583
584 attr.add_node_attribute(NodeAttributeType::NodeName, b"router1".to_vec());
586 assert_eq!(attr.get_node_name(), Some("router1".to_string()));
587
588 attr.add_link_attribute(
590 LinkAttributeType::AdministrativeGroup,
591 vec![0x00, 0x00, 0x00, 0xFF],
592 );
593 assert_eq!(attr.get_administrative_group(), Some(255));
594
595 attr.add_link_attribute(LinkAttributeType::IgpMetric, vec![0x01, 0x00]);
597 assert_eq!(attr.get_igp_metric(), Some(256));
598
599 attr.add_prefix_attribute(
601 PrefixAttributeType::PrefixMetric,
602 vec![0x00, 0x00, 0x03, 0xE8],
603 );
604 assert_eq!(attr.get_prefix_metric(), Some(1000));
605 }
606
607 #[test]
608 fn test_tlv_creation() {
609 let tlv = Tlv::new(1024, vec![0x01, 0x02, 0x03]);
610 assert_eq!(tlv.tlv_type, 1024);
611 assert_eq!(tlv.value, vec![0x01, 0x02, 0x03]);
612 assert_eq!(tlv.length(), 3);
613 }
614
615 #[test]
616 #[cfg(feature = "serde")]
617 fn test_serde_serialization() {
618 let mut attr = LinkStateAttribute::new();
619 attr.add_node_attribute(NodeAttributeType::NodeName, b"test".to_vec());
620
621 let serialized = serde_json::to_string(&attr).unwrap();
622 let deserialized: LinkStateAttribute = serde_json::from_str(&serialized).unwrap();
623
624 assert_eq!(attr, deserialized);
625 }
626}