1use crate::models::network::{Afi, NetworkPrefix};
19#[cfg(feature = "parser")]
20use bytes::{Buf, Bytes};
21use ipnet::IpNet;
22use smallvec::SmallVec;
23use std::fmt::{Debug, Formatter};
24
25#[derive(PartialEq, Eq, Clone, Copy, Hash)]
27pub struct MplsLabel(u32);
28
29impl MplsLabel {
30 pub const MAX_VALUE: u32 = 0x000F_FFFF;
32
33 pub const IPV4_EXPLICIT_NULL: u32 = 0;
35 pub const IPV6_EXPLICIT_NULL: u32 = 2;
37 pub const IMPLICIT_NULL: u32 = 3;
39
40 pub fn try_new(value: u32) -> Result<Self, MplsLabelError> {
43 if value > Self::MAX_VALUE {
44 return Err(MplsLabelError::LabelValueTooLarge(value));
45 }
46 Ok(Self(value))
47 }
48
49 pub(crate) fn new_masked(value: u32) -> Self {
52 Self(value & Self::MAX_VALUE)
53 }
54
55 pub fn value(&self) -> u32 {
57 self.0
58 }
59
60 pub fn is_reserved(&self) -> bool {
62 self.0 <= 15
63 }
64
65 pub fn is_implicit_null(&self) -> bool {
67 self.0 == Self::IMPLICIT_NULL
68 }
69
70 pub fn is_ipv4_explicit_null(&self) -> bool {
72 self.0 == Self::IPV4_EXPLICIT_NULL
73 }
74
75 pub fn is_ipv6_explicit_null(&self) -> bool {
77 self.0 == Self::IPV6_EXPLICIT_NULL
78 }
79
80 pub fn encode(&self, is_bottom: bool) -> [u8; 3] {
84 let raw = (self.0 << 4) | (if is_bottom { 1 } else { 0 });
85 [(raw >> 16) as u8, (raw >> 8) as u8, raw as u8]
86 }
87
88 pub fn decode(bytes: [u8; 3]) -> (Self, bool) {
93 let raw = ((bytes[0] as u32) << 16) | ((bytes[1] as u32) << 8) | (bytes[2] as u32);
94 let label_value = raw >> 4;
95 let bos = (raw & 0x01) != 0;
96 (Self::new_masked(label_value), bos)
97 }
98}
99
100impl Debug for MplsLabel {
101 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
102 write!(f, "MplsLabel({})", self.0)
103 }
104}
105
106#[cfg(feature = "serde")]
107impl serde::Serialize for MplsLabel {
108 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
109 where
110 S: serde::Serializer,
111 {
112 serializer.serialize_u32(self.0)
113 }
114}
115
116#[cfg(feature = "serde")]
117impl<'de> serde::Deserialize<'de> for MplsLabel {
118 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
119 where
120 D: serde::Deserializer<'de>,
121 {
122 let value = u32::deserialize(deserializer)?;
123 Self::try_new(value).map_err(serde::de::Error::custom)
124 }
125}
126
127#[derive(Debug, Clone, PartialEq, Eq)]
129pub enum MplsLabelError {
130 LabelValueTooLarge(u32),
131}
132
133impl std::fmt::Display for MplsLabelError {
134 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
135 match self {
136 MplsLabelError::LabelValueTooLarge(v) => {
137 write!(
138 f,
139 "MPLS label value {} exceeds maximum 0x{:X}",
140 v,
141 MplsLabel::MAX_VALUE
142 )
143 }
144 }
145 }
146}
147
148impl std::error::Error for MplsLabelError {}
149
150#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
160#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
161pub enum LabeledNlriMode {
162 SingleLabel,
166 #[default]
169 MultiLabel,
170}
171
172#[derive(Debug, Clone, PartialEq, Eq)]
174#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
175pub struct LabeledNlriConfig {
176 pub add_path: bool,
183
184 pub mode: LabeledNlriMode,
186
187 pub max_labels: u8,
191
192 pub peer_max_labels: Option<u8>,
197}
198
199impl LabeledNlriConfig {
200 pub fn try_new(
204 add_path: bool,
205 mode: LabeledNlriMode,
206 max_labels: u8,
207 peer_max_labels: Option<u8>,
208 ) -> Result<Self, LabeledNlriConfigError> {
209 if max_labels == 0 || max_labels > 254 {
210 return Err(LabeledNlriConfigError::InvalidMaxLabels(max_labels));
211 }
212 if let Some(peer) = peer_max_labels {
213 if peer == 0 {
214 return Err(LabeledNlriConfigError::InvalidPeerMaxLabels(peer));
215 }
216 }
217 Ok(Self {
218 add_path,
219 mode,
220 max_labels,
221 peer_max_labels,
222 })
223 }
224}
225
226impl Default for LabeledNlriConfig {
227 fn default() -> Self {
228 Self {
229 add_path: false,
230 mode: LabeledNlriMode::default(),
231 max_labels: 16,
232 peer_max_labels: None,
233 }
234 }
235}
236
237#[derive(Debug, Clone, PartialEq, Eq)]
239pub enum LabeledNlriConfigError {
240 InvalidMaxLabels(u8),
241 InvalidPeerMaxLabels(u8),
242}
243
244impl std::fmt::Display for LabeledNlriConfigError {
245 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
246 match self {
247 LabeledNlriConfigError::InvalidMaxLabels(v) => {
248 write!(f, "max_labels {} is invalid, must be 1-254", v)
249 }
250 LabeledNlriConfigError::InvalidPeerMaxLabels(v) => {
251 write!(f, "peer_max_labels {} is invalid, must be 2-254 or None", v)
252 }
253 }
254 }
255}
256
257impl std::error::Error for LabeledNlriConfigError {}
258
259#[derive(Debug, PartialEq, Clone, Eq)]
261#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
262pub struct LabeledNetworkPrefix {
263 pub prefix: IpNet,
265 pub labels: SmallVec<[MplsLabel; 2]>,
268 pub path_id: Option<u32>,
270}
271
272#[derive(Debug, Clone, PartialEq, Eq)]
274pub enum LabeledNetworkPrefixError {
275 EmptyLabelStack,
276 PrefixLengthOverflow { total_bits: usize, max: usize },
277}
278
279impl std::fmt::Display for LabeledNetworkPrefixError {
280 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
281 match self {
282 LabeledNetworkPrefixError::EmptyLabelStack => {
283 write!(f, "labeled prefix must have at least one label")
284 }
285 LabeledNetworkPrefixError::PrefixLengthOverflow { total_bits, max } => {
286 write!(
287 f,
288 "total NLRI length {} bits exceeds maximum {} bits",
289 total_bits, max
290 )
291 }
292 }
293 }
294}
295
296impl std::error::Error for LabeledNetworkPrefixError {}
297
298impl LabeledNetworkPrefix {
299 pub fn try_new(
302 prefix: IpNet,
303 labels: SmallVec<[MplsLabel; 2]>,
304 path_id: Option<u32>,
305 ) -> Result<Self, LabeledNetworkPrefixError> {
306 if labels.is_empty() {
307 return Err(LabeledNetworkPrefixError::EmptyLabelStack);
308 }
309
310 let label_bits = labels.len().checked_mul(24).ok_or(
313 LabeledNetworkPrefixError::PrefixLengthOverflow {
314 total_bits: usize::MAX,
315 max: 255,
316 },
317 )?;
318 let prefix_bits = prefix.prefix_len() as usize;
319 let total_bits = label_bits.checked_add(prefix_bits).ok_or(
320 LabeledNetworkPrefixError::PrefixLengthOverflow {
321 total_bits: usize::MAX,
322 max: 255,
323 },
324 )?;
325
326 if total_bits > 255 {
327 return Err(LabeledNetworkPrefixError::PrefixLengthOverflow {
328 total_bits,
329 max: 255,
330 });
331 }
332
333 Ok(Self {
334 prefix,
335 labels,
336 path_id,
337 })
338 }
339
340 pub fn top_label(&self) -> Option<&MplsLabel> {
342 self.labels.first()
343 }
344
345 pub fn bottom_label(&self) -> Option<&MplsLabel> {
347 self.labels.last()
348 }
349
350 pub fn has_multiple_labels(&self) -> bool {
352 self.labels.len() > 1
353 }
354
355 pub fn label_count(&self) -> usize {
357 self.labels.len()
358 }
359}
360
361#[derive(Debug, Clone, PartialEq, Eq)]
363pub enum LabeledNlriEncodeError {
364 EmptyLabelStack,
365 TotalBitsOverflow {
366 total_bits: usize,
367 max: usize,
368 },
369 SingleLabelModeWithMultipleLabels {
370 label_count: usize,
371 },
372 LabelCountExceedsPeerLimit {
373 actual: usize,
374 peer_max: u8,
375 },
376 AddPathNotNegotiated,
378}
379
380impl std::fmt::Display for LabeledNlriEncodeError {
381 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
382 match self {
383 LabeledNlriEncodeError::EmptyLabelStack => {
384 write!(f, "cannot encode labeled prefix with empty label stack")
385 }
386 LabeledNlriEncodeError::TotalBitsOverflow { total_bits, max } => {
387 write!(
388 f,
389 "total NLRI length {} bits exceeds maximum {} bits",
390 total_bits, max
391 )
392 }
393 LabeledNlriEncodeError::SingleLabelModeWithMultipleLabels { label_count } => {
394 write!(f, "single-label mode cannot encode {} labels", label_count)
395 }
396 LabeledNlriEncodeError::LabelCountExceedsPeerLimit { actual, peer_max } => {
397 write!(f, "label count {} exceeds peer limit {}", actual, peer_max)
398 }
399 LabeledNlriEncodeError::AddPathNotNegotiated => {
400 write!(f, "ADD-PATH not negotiated but path_id is present")
401 }
402 }
403 }
404}
405
406impl std::error::Error for LabeledNlriEncodeError {}
407
408#[cfg(feature = "parser")]
409pub fn parse_labeled_nlri(
414 input: &mut Bytes,
415 afi: Afi,
416 config: &LabeledNlriConfig,
417) -> Result<Vec<LabeledNetworkPrefix>, crate::error::ParserError> {
418 use crate::error::ParserError;
419
420 let mut result = Vec::new();
421
422 while input.has_remaining() {
423 let path_id = if config.add_path {
425 if input.remaining() < 4 {
426 return Err(ParserError::TruncatedLabeledNlri);
427 }
428 Some(input.get_u32())
429 } else {
430 None
431 };
432
433 if input.remaining() < 1 {
435 return Err(ParserError::TruncatedLabeledNlri);
436 }
437 let total_bits = input.get_u8() as usize;
438
439 if total_bits < 24 {
441 return Err(ParserError::InvalidLabeledNlriLength);
442 }
443
444 let nlri_bytes = total_bits.div_ceil(8);
447 if input.remaining() < nlri_bytes {
448 return Err(ParserError::TruncatedLabeledNlri);
449 }
450
451 let nlri_data = input.copy_to_bytes(nlri_bytes);
453 let mut nlri_input = nlri_data;
454
455 let mut labels: SmallVec<[MplsLabel; 2]> = SmallVec::new();
457
458 match config.mode {
459 LabeledNlriMode::SingleLabel => {
460 if nlri_input.remaining() < 3 {
462 return Err(ParserError::TruncatedLabeledNlri);
463 }
464 let label_bytes = [
465 nlri_input.get_u8(),
466 nlri_input.get_u8(),
467 nlri_input.get_u8(),
468 ];
469 let (label, _bos) = MplsLabel::decode(label_bytes);
471 labels.push(label);
472 }
473
474 LabeledNlriMode::MultiLabel => {
475 loop {
477 if labels.len() >= config.max_labels as usize {
479 return Err(ParserError::MaxLabelStackDepthExceeded);
480 }
481
482 if let Some(peer_max) = config.peer_max_labels {
484 if labels.len() >= peer_max as usize {
485 return Err(ParserError::PeerMaxLabelsExceeded);
486 }
487 }
488
489 if nlri_input.remaining() < 3 {
490 return Err(ParserError::TruncatedLabeledNlri);
491 }
492
493 let label_bytes = [
494 nlri_input.get_u8(),
495 nlri_input.get_u8(),
496 nlri_input.get_u8(),
497 ];
498 let (label, bos) = MplsLabel::decode(label_bytes);
499 labels.push(label);
500
501 if bos {
502 break;
503 }
504 }
505 }
506 }
507
508 let label_bits = labels
510 .len()
511 .checked_mul(24)
512 .ok_or(ParserError::InvalidLabeledNlriLength)?;
513
514 let prefix_bits = total_bits
516 .checked_sub(label_bits)
517 .ok_or(ParserError::InvalidLabeledNlriLength)?;
518
519 let max_prefix_bits = match afi {
521 Afi::Ipv4 => 32,
522 Afi::Ipv6 => 128,
523 _ => return Err(ParserError::InvalidLabeledNlriLength),
524 };
525
526 if prefix_bits > max_prefix_bits {
527 return Err(ParserError::InvalidLabeledNlriLength);
528 }
529
530 let prefix_bytes = prefix_bits.div_ceil(8);
532
533 if nlri_input.remaining() < prefix_bytes {
534 return Err(ParserError::TruncatedPrefix);
535 }
536
537 let prefix_data = nlri_input.copy_to_bytes(prefix_bytes);
538 let prefix = parse_prefix_with_masking(afi, &prefix_data, prefix_bits as u8)?;
539
540 if nlri_input.has_remaining() {
542 return Err(ParserError::InvalidLabeledNlriLength);
543 }
544
545 result.push(LabeledNetworkPrefix {
547 prefix,
548 labels,
549 path_id,
550 });
551 }
552
553 Ok(result)
554}
555
556#[cfg(feature = "parser")]
557fn parse_prefix_with_masking(
561 afi: Afi,
562 data: &[u8],
563 prefix_bits: u8,
564) -> Result<IpNet, crate::error::ParserError> {
565 use crate::error::ParserError;
566 use std::net::{Ipv4Addr, Ipv6Addr};
567
568 let full_bytes = (prefix_bits as usize) / 8;
569 let remainder_bits = prefix_bits % 8;
570
571 match afi {
572 Afi::Ipv4 => {
573 let mut octets = [0u8; 4];
574 let copy_len = data.len().min(4);
575 octets[..copy_len].copy_from_slice(&data[..copy_len]);
576
577 if remainder_bits > 0 && copy_len > full_bytes {
579 let mask = 0xFF << (8 - remainder_bits);
580 octets[full_bytes] &= mask;
581 }
582
583 let addr = Ipv4Addr::from(octets);
584 Ok(IpNet::V4(
585 ipnet::Ipv4Net::new(addr, prefix_bits).map_err(|_| ParserError::InvalidPrefix)?,
586 ))
587 }
588 Afi::Ipv6 => {
589 let mut octets = [0u8; 16];
590 let copy_len = data.len().min(16);
591 octets[..copy_len].copy_from_slice(&data[..copy_len]);
592
593 if remainder_bits > 0 && copy_len > full_bytes {
595 let mask = 0xFF << (8 - remainder_bits);
596 octets[full_bytes] &= mask;
597 }
598
599 let addr = Ipv6Addr::from(octets);
600 Ok(IpNet::V6(
601 ipnet::Ipv6Net::new(addr, prefix_bits).map_err(|_| ParserError::InvalidPrefix)?,
602 ))
603 }
604 _ => Err(ParserError::InvalidLabeledNlriLength),
605 }
606}
607
608#[cfg(feature = "parser")]
609pub fn parse_labeled_withdrawal_nlri(
614 input: &mut Bytes,
615 afi: Afi,
616 config: &LabeledNlriConfig,
617) -> Result<Vec<NetworkPrefix>, crate::error::ParserError> {
618 use crate::error::ParserError;
619
620 let mut result = Vec::new();
621
622 if !input.has_remaining() {
624 return Ok(result);
625 }
626
627 while input.has_remaining() {
628 let path_id = if config.add_path {
630 if input.remaining() < 4 {
631 return Err(ParserError::TruncatedLabeledNlri);
632 }
633 Some(input.get_u32())
634 } else {
635 None
636 };
637
638 if input.remaining() < 1 {
640 return Err(ParserError::TruncatedLabeledNlri);
641 }
642 let total_bits = input.get_u8() as usize;
643
644 if total_bits < 24 {
646 return Err(ParserError::InvalidLabeledNlriLength);
647 }
648
649 let nlri_bytes = total_bits.div_ceil(8);
651 if input.remaining() < nlri_bytes {
652 return Err(ParserError::TruncatedLabeledNlri);
653 }
654
655 let nlri_data = input.copy_to_bytes(nlri_bytes);
656 let mut nlri_input = nlri_data;
657
658 if nlri_input.remaining() < 3 {
661 return Err(ParserError::TruncatedLabeledNlri);
662 }
663 let _compatibility_field = [
664 nlri_input.get_u8(),
665 nlri_input.get_u8(),
666 nlri_input.get_u8(),
667 ];
668
669 let prefix_bits = total_bits
671 .checked_sub(24) .ok_or(ParserError::InvalidLabeledNlriLength)?;
673
674 let max_prefix_bits = match afi {
676 Afi::Ipv4 => 32,
677 Afi::Ipv6 => 128,
678 _ => return Err(ParserError::InvalidLabeledNlriLength),
679 };
680
681 if prefix_bits > max_prefix_bits {
682 return Err(ParserError::InvalidLabeledNlriLength);
683 }
684
685 let prefix_bytes = prefix_bits.div_ceil(8);
687
688 if nlri_input.remaining() < prefix_bytes {
689 return Err(ParserError::TruncatedPrefix);
690 }
691
692 let prefix_data = nlri_input.copy_to_bytes(prefix_bytes);
693 let prefix = parse_prefix_with_masking(afi, &prefix_data, prefix_bits as u8)?;
694
695 if nlri_input.has_remaining() {
697 return Err(ParserError::InvalidLabeledNlriLength);
698 }
699
700 result.push(NetworkPrefix::new(prefix, path_id));
702 }
703
704 Ok(result)
705}
706
707pub fn encode_labeled_prefix(
729 prefix: &LabeledNetworkPrefix,
730 mode: LabeledNlriMode,
731 add_path: bool,
732 peer_max_labels: Option<u8>,
733) -> Result<Vec<u8>, LabeledNlriEncodeError> {
734 if prefix.labels.is_empty() {
736 return Err(LabeledNlriEncodeError::EmptyLabelStack);
737 }
738
739 if prefix.path_id.is_some() && !add_path {
741 return Err(LabeledNlriEncodeError::AddPathNotNegotiated);
742 }
743
744 let mut output = Vec::new();
745
746 if let Some(path_id) = prefix.path_id {
748 output.extend_from_slice(&path_id.to_be_bytes());
749 }
750
751 let label_bits =
753 prefix
754 .labels
755 .len()
756 .checked_mul(24)
757 .ok_or(LabeledNlriEncodeError::TotalBitsOverflow {
758 total_bits: usize::MAX,
759 max: 255,
760 })?;
761 let prefix_bits = prefix.prefix.prefix_len() as usize;
762 let total_bits =
763 label_bits
764 .checked_add(prefix_bits)
765 .ok_or(LabeledNlriEncodeError::TotalBitsOverflow {
766 total_bits: usize::MAX,
767 max: 255,
768 })?;
769
770 if total_bits > 255 {
772 return Err(LabeledNlriEncodeError::TotalBitsOverflow {
773 total_bits,
774 max: 255,
775 });
776 }
777
778 output.push(total_bits as u8);
779
780 match mode {
782 LabeledNlriMode::SingleLabel => {
783 if prefix.labels.len() > 1 {
785 return Err(LabeledNlriEncodeError::SingleLabelModeWithMultipleLabels {
786 label_count: prefix.labels.len(),
787 });
788 }
789 let label = &prefix.labels[0];
790 let encoded = label.encode(true); output.extend_from_slice(&encoded);
792 }
793
794 LabeledNlriMode::MultiLabel => {
795 if let Some(peer_max) = peer_max_labels {
798 if prefix.labels.len() > peer_max as usize {
799 return Err(LabeledNlriEncodeError::LabelCountExceedsPeerLimit {
800 actual: prefix.labels.len(),
801 peer_max,
802 });
803 }
804 }
805
806 for (i, label) in prefix.labels.iter().enumerate() {
807 let is_bottom = i == prefix.labels.len() - 1;
808 let encoded = label.encode(is_bottom);
809 output.extend_from_slice(&encoded);
810 }
811 }
812 }
813
814 let prefix_bytes = prefix_bits.div_ceil(8);
816 let prefix_octets = match prefix.prefix {
817 IpNet::V4(p) => p.addr().octets().to_vec(),
818 IpNet::V6(p) => p.addr().octets().to_vec(),
819 };
820 output.extend_from_slice(&prefix_octets[..prefix_bytes]);
821
822 Ok(output)
823}
824
825pub fn encode_labeled_withdrawal(
829 prefix: &NetworkPrefix,
830) -> Result<Vec<u8>, LabeledNlriEncodeError> {
831 let mut output = Vec::new();
832
833 if let Some(path_id) = prefix.path_id {
835 output.extend_from_slice(&path_id.to_be_bytes());
836 }
837
838 let prefix_bits = prefix.prefix.prefix_len() as usize;
841 let total_bits =
842 24usize
843 .checked_add(prefix_bits)
844 .ok_or(LabeledNlriEncodeError::TotalBitsOverflow {
845 total_bits: prefix_bits.saturating_add(24),
846 max: 255,
847 })?;
848
849 if total_bits > 255 {
851 return Err(LabeledNlriEncodeError::TotalBitsOverflow {
852 total_bits,
853 max: 255,
854 });
855 }
856
857 output.push(total_bits as u8);
858
859 output.extend_from_slice(&[0x80, 0x00, 0x00]);
862
863 let prefix_bytes = prefix_bits.div_ceil(8);
865 let prefix_octets = match prefix.prefix {
866 IpNet::V4(p) => p.addr().octets().to_vec(),
867 IpNet::V6(p) => p.addr().octets().to_vec(),
868 };
869 output.extend_from_slice(&prefix_octets[..prefix_bytes]);
870
871 Ok(output)
872}
873
874#[cfg(test)]
875mod tests {
876 use super::*;
877 use std::str::FromStr;
878
879 #[test]
880 fn test_mpls_label_new() {
881 let label = MplsLabel::try_new(100).unwrap();
882 assert_eq!(label.value(), 100);
883 assert!(!label.is_reserved());
884 }
885
886 #[test]
887 fn test_mpls_label_too_large() {
888 let result = MplsLabel::try_new(0x0010_0000); assert!(result.is_err());
890 }
891
892 #[test]
893 fn test_mpls_label_reserved() {
894 let label = MplsLabel::try_new(0).unwrap();
895 assert!(label.is_reserved());
896 assert!(label.is_ipv4_explicit_null());
897
898 let label = MplsLabel::try_new(2).unwrap();
899 assert!(label.is_reserved());
900 assert!(label.is_ipv6_explicit_null());
901
902 let label = MplsLabel::try_new(3).unwrap();
903 assert!(label.is_reserved());
904 assert!(label.is_implicit_null());
905
906 let label = MplsLabel::try_new(15).unwrap();
907 assert!(label.is_reserved());
908
909 let label = MplsLabel::try_new(16).unwrap();
910 assert!(!label.is_reserved());
911 }
912
913 #[test]
914 fn test_mpls_label_encode_decode() {
915 let label = MplsLabel::try_new(24001).unwrap();
916
917 let encoded = label.encode(true);
919 assert_eq!(encoded, [0x05, 0xDC, 0x11]); let (decoded, bos) = MplsLabel::decode(encoded);
923 assert_eq!(decoded.value(), 24001);
924 assert!(bos);
925
926 let encoded = label.encode(false);
928 assert_eq!(encoded, [0x05, 0xDC, 0x10]); let (decoded, bos) = MplsLabel::decode(encoded);
932 assert_eq!(decoded.value(), 24001);
933 assert!(!bos);
934 }
935
936 #[test]
937 fn test_labeled_network_prefix_new() {
938 let prefix = IpNet::from_str("192.0.2.0/24").unwrap();
939 let labels = SmallVec::from_vec(vec![MplsLabel::try_new(100).unwrap()]);
940
941 let labeled = LabeledNetworkPrefix::try_new(prefix, labels, None).unwrap();
942 assert_eq!(labeled.label_count(), 1);
943 assert!(!labeled.has_multiple_labels());
944 }
945
946 #[test]
947 fn test_labeled_network_prefix_empty_labels() {
948 let prefix = IpNet::from_str("192.0.2.0/24").unwrap();
949 let labels: SmallVec<[MplsLabel; 2]> = SmallVec::new();
950
951 let result = LabeledNetworkPrefix::try_new(prefix, labels, None);
952 assert!(matches!(
953 result,
954 Err(LabeledNetworkPrefixError::EmptyLabelStack)
955 ));
956 }
957
958 #[test]
959 fn test_labeled_nlri_config_validation() {
960 let config = LabeledNlriConfig::try_new(false, LabeledNlriMode::SingleLabel, 16, None);
962 assert!(config.is_ok());
963
964 let result = LabeledNlriConfig::try_new(false, LabeledNlriMode::SingleLabel, 0, None);
966 assert!(matches!(
967 result,
968 Err(LabeledNlriConfigError::InvalidMaxLabels(0))
969 ));
970
971 let result = LabeledNlriConfig::try_new(false, LabeledNlriMode::SingleLabel, 255, None);
973 assert!(matches!(
974 result,
975 Err(LabeledNlriConfigError::InvalidMaxLabels(255))
976 ));
977
978 let result = LabeledNlriConfig::try_new(false, LabeledNlriMode::MultiLabel, 16, Some(0));
980 assert!(matches!(
981 result,
982 Err(LabeledNlriConfigError::InvalidPeerMaxLabels(0))
983 ));
984
985 let result = LabeledNlriConfig::try_new(false, LabeledNlriMode::MultiLabel, 16, Some(1));
987 assert!(result.is_ok());
988 }
989
990 #[test]
991 fn test_encode_labeled_prefix_single_label_mode() {
992 let prefix = IpNet::from_str("192.0.2.0/24").unwrap();
993 let labels = SmallVec::from_vec(vec![MplsLabel::try_new(24001).unwrap()]);
994 let labeled = LabeledNetworkPrefix::try_new(prefix, labels, None).unwrap();
995
996 let result = encode_labeled_prefix(&labeled, LabeledNlriMode::SingleLabel, false, None);
998 assert!(result.is_ok());
999
1000 let encoded = result.unwrap();
1002 assert_eq!(encoded, vec![0x30, 0x05, 0xDC, 0x11, 0xC0, 0x00, 0x02]);
1003 }
1004
1005 #[test]
1006 fn test_encode_labeled_prefix_single_label_mode_multiple_labels() {
1007 let prefix = IpNet::from_str("192.0.2.0/24").unwrap();
1008 let labels = SmallVec::from_vec(vec![
1009 MplsLabel::try_new(24001).unwrap(),
1010 MplsLabel::try_new(24002).unwrap(),
1011 ]);
1012 let labeled = LabeledNetworkPrefix::try_new(prefix, labels, None).unwrap();
1013
1014 let result = encode_labeled_prefix(&labeled, LabeledNlriMode::SingleLabel, false, None);
1016 assert!(matches!(
1017 result,
1018 Err(LabeledNlriEncodeError::SingleLabelModeWithMultipleLabels { label_count: 2 })
1019 ));
1020 }
1021
1022 #[test]
1023 fn test_encode_labeled_prefix_multi_label_mode() {
1024 let prefix = IpNet::from_str("192.0.2.0/24").unwrap();
1025 let labels = SmallVec::from_vec(vec![
1026 MplsLabel::try_new(24001).unwrap(),
1027 MplsLabel::try_new(24002).unwrap(),
1028 ]);
1029 let labeled = LabeledNetworkPrefix::try_new(prefix, labels, None).unwrap();
1030
1031 let result = encode_labeled_prefix(&labeled, LabeledNlriMode::MultiLabel, false, None);
1033 assert!(result.is_ok());
1034
1035 let encoded = result.unwrap();
1039 assert_eq!(
1040 encoded,
1041 vec![0x48, 0x05, 0xDC, 0x10, 0x05, 0xDC, 0x21, 0xC0, 0x00, 0x02]
1042 );
1043 }
1044
1045 #[test]
1046 fn test_encode_labeled_prefix_multi_label_mode_with_path_id() {
1047 let prefix = IpNet::from_str("192.0.2.0/24").unwrap();
1048 let labels = SmallVec::from_vec(vec![
1049 MplsLabel::try_new(24001).unwrap(),
1050 MplsLabel::try_new(24002).unwrap(),
1051 ]);
1052 let labeled = LabeledNetworkPrefix::try_new(prefix, labels, Some(123)).unwrap();
1053
1054 let result = encode_labeled_prefix(&labeled, LabeledNlriMode::MultiLabel, true, None);
1056 assert!(result.is_ok());
1057
1058 let encoded = result.unwrap();
1062 assert_eq!(
1063 encoded,
1064 vec![
1065 0x00, 0x00, 0x00, 0x7B, 0x48, 0x05, 0xDC, 0x10, 0x05, 0xDC, 0x21, 0xC0, 0x00, 0x02
1066 ]
1067 );
1068 }
1069
1070 #[test]
1071 fn test_encode_labeled_withdrawal() {
1072 let prefix = NetworkPrefix::new(IpNet::from_str("192.0.2.0/24").unwrap(), None);
1073
1074 let result = encode_labeled_withdrawal(&prefix);
1075 assert!(result.is_ok());
1076
1077 let encoded = result.unwrap();
1079 assert_eq!(encoded, vec![0x30, 0x80, 0x00, 0x00, 0xC0, 0x00, 0x02]);
1080 }
1081
1082 #[test]
1083 fn test_encode_labeled_withdrawal_with_path_id() {
1084 let prefix = NetworkPrefix::new(IpNet::from_str("192.0.2.0/24").unwrap(), Some(123));
1085
1086 let result = encode_labeled_withdrawal(&prefix);
1087 assert!(result.is_ok());
1088
1089 let encoded = result.unwrap();
1092 assert_eq!(
1093 encoded,
1094 vec![0x00, 0x00, 0x00, 0x7B, 0x30, 0x80, 0x00, 0x00, 0xC0, 0x00, 0x02]
1095 );
1096 }
1097
1098 #[test]
1099 fn test_encode_labeled_prefix_add_path_not_negotiated() {
1100 let prefix = IpNet::from_str("192.0.2.0/24").unwrap();
1101 let labels = SmallVec::from_vec(vec![MplsLabel::try_new(100).unwrap()]);
1102 let labeled = LabeledNetworkPrefix::try_new(prefix, labels, Some(123)).unwrap();
1103
1104 let result = encode_labeled_prefix(&labeled, LabeledNlriMode::SingleLabel, false, None);
1106 assert!(matches!(
1107 result,
1108 Err(LabeledNlriEncodeError::AddPathNotNegotiated)
1109 ));
1110
1111 let result = encode_labeled_prefix(&labeled, LabeledNlriMode::SingleLabel, true, None);
1113 assert!(result.is_ok());
1114 }
1115}