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