1use std::fmt;
2use std::net::{Ipv4Addr, Ipv6Addr};
3
4use crate::error::DecodeError;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub struct Ipv4NlriEntry {
11 pub path_id: u32,
13 pub prefix: Ipv4Prefix,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub struct NlriEntry {
22 pub path_id: u32,
24 pub prefix: Prefix,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
32pub struct Ipv4Prefix {
33 pub addr: Ipv4Addr,
35 pub len: u8,
37}
38
39impl Ipv4Prefix {
40 #[must_use]
47 pub fn new(addr: Ipv4Addr, len: u8) -> Self {
48 let len = len.min(32);
49 let masked = if len == 0 {
50 0
51 } else if len >= 32 {
52 u32::from(addr)
53 } else {
54 u32::from(addr) & !((1u32 << (32 - len)) - 1)
55 };
56 Self {
57 addr: Ipv4Addr::from(masked),
58 len,
59 }
60 }
61}
62
63impl fmt::Display for Ipv4Prefix {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 write!(f, "{}/{}", self.addr, self.len)
66 }
67}
68
69pub fn decode_nlri(mut buf: &[u8]) -> Result<Vec<Ipv4Prefix>, DecodeError> {
79 let mut prefixes = Vec::new();
80
81 while !buf.is_empty() {
82 let field_start = buf;
83 let prefix_len = buf[0];
84 buf = &buf[1..];
85
86 if prefix_len > 32 {
87 let addr_bytes = usize::from(prefix_len.div_ceil(8)).min(buf.len());
89 return Err(DecodeError::InvalidNetworkField {
90 detail: format!("NLRI prefix length {prefix_len} exceeds 32"),
91 data: field_start[..=addr_bytes].to_vec(),
92 });
93 }
94
95 let byte_count = usize::from(prefix_len.div_ceil(8));
96 if buf.len() < byte_count {
97 return Err(DecodeError::InvalidNetworkField {
100 detail: format!(
101 "NLRI truncated: prefix length {prefix_len} requires \
102 {byte_count} bytes, have {}",
103 buf.len()
104 ),
105 data: field_start[..=buf.len()].to_vec(),
106 });
107 }
108
109 let mut octets = [0u8; 4];
110 octets[..byte_count].copy_from_slice(&buf[..byte_count]);
111 buf = &buf[byte_count..];
112
113 prefixes.push(Ipv4Prefix::new(Ipv4Addr::from(octets), prefix_len));
114 }
115
116 Ok(prefixes)
117}
118
119pub fn encode_nlri(prefixes: &[Ipv4Prefix], buf: &mut Vec<u8>) {
121 for prefix in prefixes {
122 buf.push(prefix.len);
123 let byte_count = usize::from(prefix.len.div_ceil(8));
124 let octets = prefix.addr.octets();
125 buf.extend_from_slice(&octets[..byte_count]);
126 }
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
133pub struct Ipv6Prefix {
134 pub addr: Ipv6Addr,
136 pub len: u8,
138}
139
140impl Ipv6Prefix {
141 #[must_use]
148 pub fn new(addr: Ipv6Addr, len: u8) -> Self {
149 let len = len.min(128);
150 let masked = if len == 0 {
151 0u128
152 } else if len >= 128 {
153 u128::from(addr)
154 } else {
155 u128::from(addr) & !((1u128 << (128 - len)) - 1)
156 };
157 Self {
158 addr: Ipv6Addr::from(masked),
159 len,
160 }
161 }
162}
163
164impl fmt::Display for Ipv6Prefix {
165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 write!(f, "{}/{}", self.addr, self.len)
167 }
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
172pub enum Prefix {
173 V4(Ipv4Prefix),
175 V6(Ipv6Prefix),
177}
178
179impl Prefix {
180 #[must_use]
182 pub fn addr_string(&self) -> String {
183 match self {
184 Self::V4(p) => p.addr.to_string(),
185 Self::V6(p) => p.addr.to_string(),
186 }
187 }
188
189 #[must_use]
191 pub fn prefix_len(&self) -> u8 {
192 match self {
193 Self::V4(p) => p.len,
194 Self::V6(p) => p.len,
195 }
196 }
197}
198
199impl fmt::Display for Prefix {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 match self {
202 Self::V4(p) => p.fmt(f),
203 Self::V6(p) => p.fmt(f),
204 }
205 }
206}
207
208pub fn decode_ipv6_nlri(mut buf: &[u8]) -> Result<Vec<Ipv6Prefix>, DecodeError> {
218 let mut prefixes = Vec::new();
219
220 while !buf.is_empty() {
221 let field_start = buf;
222 let prefix_len = buf[0];
223 buf = &buf[1..];
224
225 if prefix_len > 128 {
226 let addr_bytes = usize::from(prefix_len.div_ceil(8)).min(buf.len());
227 return Err(DecodeError::InvalidNetworkField {
228 detail: format!("NLRI prefix length {prefix_len} exceeds 128"),
229 data: field_start[..=addr_bytes].to_vec(),
230 });
231 }
232
233 let byte_count = usize::from(prefix_len.div_ceil(8));
234 if buf.len() < byte_count {
235 return Err(DecodeError::InvalidNetworkField {
236 detail: format!(
237 "NLRI truncated: prefix length {prefix_len} requires \
238 {byte_count} bytes, have {}",
239 buf.len()
240 ),
241 data: field_start[..=buf.len()].to_vec(),
242 });
243 }
244
245 let mut octets = [0u8; 16];
246 octets[..byte_count].copy_from_slice(&buf[..byte_count]);
247 buf = &buf[byte_count..];
248
249 prefixes.push(Ipv6Prefix::new(Ipv6Addr::from(octets), prefix_len));
250 }
251
252 Ok(prefixes)
253}
254
255pub fn encode_ipv6_nlri(prefixes: &[Ipv6Prefix], buf: &mut Vec<u8>) {
257 for prefix in prefixes {
258 buf.push(prefix.len);
259 let byte_count = usize::from(prefix.len.div_ceil(8));
260 let octets = prefix.addr.octets();
261 buf.extend_from_slice(&octets[..byte_count]);
262 }
263}
264
265pub fn decode_nlri_addpath(mut buf: &[u8]) -> Result<Vec<Ipv4NlriEntry>, DecodeError> {
273 let mut entries = Vec::new();
274
275 while !buf.is_empty() {
276 if buf.len() < 5 {
277 return Err(DecodeError::InvalidNetworkField {
278 detail: format!(
279 "Add-Path NLRI truncated: need at least 5 bytes (path_id + prefix_len), have {}",
280 buf.len()
281 ),
282 data: buf.to_vec(),
283 });
284 }
285
286 let path_id = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
287 buf = &buf[4..];
288
289 let field_start = buf;
290 let prefix_len = buf[0];
291 buf = &buf[1..];
292
293 if prefix_len > 32 {
294 let addr_bytes = usize::from(prefix_len.div_ceil(8)).min(buf.len());
295 return Err(DecodeError::InvalidNetworkField {
296 detail: format!("NLRI prefix length {prefix_len} exceeds 32"),
297 data: field_start[..=addr_bytes].to_vec(),
298 });
299 }
300
301 let byte_count = usize::from(prefix_len.div_ceil(8));
302 if buf.len() < byte_count {
303 return Err(DecodeError::InvalidNetworkField {
304 detail: format!(
305 "NLRI truncated: prefix length {prefix_len} requires \
306 {byte_count} bytes, have {}",
307 buf.len()
308 ),
309 data: field_start[..=buf.len()].to_vec(),
310 });
311 }
312
313 let mut octets = [0u8; 4];
314 octets[..byte_count].copy_from_slice(&buf[..byte_count]);
315 buf = &buf[byte_count..];
316
317 entries.push(Ipv4NlriEntry {
318 path_id,
319 prefix: Ipv4Prefix::new(Ipv4Addr::from(octets), prefix_len),
320 });
321 }
322
323 Ok(entries)
324}
325
326pub fn encode_nlri_addpath(entries: &[Ipv4NlriEntry], buf: &mut Vec<u8>) {
328 for entry in entries {
329 buf.extend_from_slice(&entry.path_id.to_be_bytes());
330 buf.push(entry.prefix.len);
331 let byte_count = usize::from(entry.prefix.len.div_ceil(8));
332 let octets = entry.prefix.addr.octets();
333 buf.extend_from_slice(&octets[..byte_count]);
334 }
335}
336
337pub fn decode_ipv6_nlri_addpath(mut buf: &[u8]) -> Result<Vec<NlriEntry>, DecodeError> {
345 let mut entries = Vec::new();
346
347 while !buf.is_empty() {
348 if buf.len() < 5 {
349 return Err(DecodeError::InvalidNetworkField {
350 detail: format!(
351 "Add-Path NLRI truncated: need at least 5 bytes (path_id + prefix_len), have {}",
352 buf.len()
353 ),
354 data: buf.to_vec(),
355 });
356 }
357
358 let path_id = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
359 buf = &buf[4..];
360
361 let field_start = buf;
362 let prefix_len = buf[0];
363 buf = &buf[1..];
364
365 if prefix_len > 128 {
366 let addr_bytes = usize::from(prefix_len.div_ceil(8)).min(buf.len());
367 return Err(DecodeError::InvalidNetworkField {
368 detail: format!("NLRI prefix length {prefix_len} exceeds 128"),
369 data: field_start[..=addr_bytes].to_vec(),
370 });
371 }
372
373 let byte_count = usize::from(prefix_len.div_ceil(8));
374 if buf.len() < byte_count {
375 return Err(DecodeError::InvalidNetworkField {
376 detail: format!(
377 "NLRI truncated: prefix length {prefix_len} requires \
378 {byte_count} bytes, have {}",
379 buf.len()
380 ),
381 data: field_start[..=buf.len()].to_vec(),
382 });
383 }
384
385 let mut octets = [0u8; 16];
386 octets[..byte_count].copy_from_slice(&buf[..byte_count]);
387 buf = &buf[byte_count..];
388
389 entries.push(NlriEntry {
390 path_id,
391 prefix: Prefix::V6(Ipv6Prefix::new(Ipv6Addr::from(octets), prefix_len)),
392 });
393 }
394
395 Ok(entries)
396}
397
398pub fn encode_ipv6_nlri_addpath(entries: &[NlriEntry], buf: &mut Vec<u8>) {
400 for entry in entries {
401 buf.extend_from_slice(&entry.path_id.to_be_bytes());
402 match entry.prefix {
403 Prefix::V6(p) => {
404 buf.push(p.len);
405 let byte_count = usize::from(p.len.div_ceil(8));
406 let octets = p.addr.octets();
407 buf.extend_from_slice(&octets[..byte_count]);
408 }
409 Prefix::V4(p) => {
410 buf.push(p.len);
411 let byte_count = usize::from(p.len.div_ceil(8));
412 let octets = p.addr.octets();
413 buf.extend_from_slice(&octets[..byte_count]);
414 }
415 }
416 }
417}
418
419pub fn decode_nlri_addpath_generic(buf: &[u8]) -> Result<Vec<NlriEntry>, DecodeError> {
425 decode_nlri_addpath(buf).map(|entries| {
426 entries
427 .into_iter()
428 .map(|e| NlriEntry {
429 path_id: e.path_id,
430 prefix: Prefix::V4(e.prefix),
431 })
432 .collect()
433 })
434}
435
436#[cfg(test)]
437mod tests {
438 use super::*;
439
440 #[test]
441 fn roundtrip_single_prefix() {
442 let prefix = Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 0), 24);
443 let mut buf = Vec::new();
444 encode_nlri(&[prefix], &mut buf);
445 let decoded = decode_nlri(&buf).unwrap();
446 assert_eq!(decoded, vec![prefix]);
447 }
448
449 #[test]
450 fn roundtrip_multiple_prefixes() {
451 let prefixes = vec![
452 Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 0), 8),
453 Ipv4Prefix::new(Ipv4Addr::new(192, 168, 1, 0), 24),
454 Ipv4Prefix::new(Ipv4Addr::new(172, 16, 0, 0), 12),
455 ];
456 let mut buf = Vec::new();
457 encode_nlri(&prefixes, &mut buf);
458 let decoded = decode_nlri(&buf).unwrap();
459 assert_eq!(decoded, prefixes);
460 }
461
462 #[test]
463 fn prefix_len_zero() {
464 let prefix = Ipv4Prefix::new(Ipv4Addr::UNSPECIFIED, 0);
465 assert_eq!(prefix.addr, Ipv4Addr::UNSPECIFIED);
466 let mut buf = Vec::new();
467 encode_nlri(&[prefix], &mut buf);
468 assert_eq!(buf, vec![0]); let decoded = decode_nlri(&buf).unwrap();
470 assert_eq!(decoded, vec![prefix]);
471 }
472
473 #[test]
474 fn prefix_len_32() {
475 let prefix = Ipv4Prefix::new(Ipv4Addr::new(10, 1, 2, 3), 32);
476 let mut buf = Vec::new();
477 encode_nlri(&[prefix], &mut buf);
478 assert_eq!(buf, vec![32, 10, 1, 2, 3]);
479 let decoded = decode_nlri(&buf).unwrap();
480 assert_eq!(decoded, vec![prefix]);
481 }
482
483 #[test]
484 fn host_bits_masked() {
485 let prefix = Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 255), 24);
486 assert_eq!(prefix.addr, Ipv4Addr::new(10, 0, 0, 0));
487 }
488
489 #[test]
490 fn reject_prefix_len_exceeds_32() {
491 let buf = [33, 10, 0, 0, 0];
492 let err = decode_nlri(&buf).unwrap_err();
493 assert!(matches!(err, DecodeError::InvalidNetworkField { .. }));
494 let (code, subcode, data) = err.to_notification();
495 assert_eq!(code, crate::notification::NotificationCode::UpdateMessage);
496 assert_eq!(subcode, 10);
497 assert_eq!(data.as_ref(), &[33, 10, 0, 0, 0]);
499 }
500
501 #[test]
502 fn reject_truncated_buffer() {
503 let buf = [24, 10, 0];
505 let err = decode_nlri(&buf).unwrap_err();
506 assert!(matches!(err, DecodeError::InvalidNetworkField { .. }));
507 let (code, subcode, data) = err.to_notification();
508 assert_eq!(code, crate::notification::NotificationCode::UpdateMessage);
509 assert_eq!(subcode, 10);
510 assert_eq!(data.as_ref(), &[24, 10, 0]);
512 }
513
514 #[test]
515 fn empty_buffer_yields_empty_vec() {
516 let decoded = decode_nlri(&[]).unwrap();
517 assert!(decoded.is_empty());
518 }
519
520 #[test]
521 fn display_format() {
522 let prefix = Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 0), 24);
523 assert_eq!(format!("{prefix}"), "10.0.0.0/24");
524 }
525
526 #[test]
527 fn wire_encoding_10_0_slash_24() {
528 let buf = [24, 10, 0, 0];
530 let decoded = decode_nlri(&buf).unwrap();
531 assert_eq!(decoded.len(), 1);
532 assert_eq!(decoded[0].addr, Ipv4Addr::new(10, 0, 0, 0));
533 assert_eq!(decoded[0].len, 24);
534 }
535
536 #[test]
537 fn wire_encoding_odd_prefix_len() {
538 let buf = [9, 10, 128];
540 let decoded = decode_nlri(&buf).unwrap();
541 assert_eq!(decoded.len(), 1);
542 assert_eq!(decoded[0].addr, Ipv4Addr::new(10, 128, 0, 0));
543 assert_eq!(decoded[0].len, 9);
544 }
545
546 #[test]
549 fn ipv6_prefix_new_masks_host_bits() {
550 let prefix = Ipv6Prefix::new("2001:db8::ffff".parse().unwrap(), 32);
551 assert_eq!(prefix.addr, "2001:db8::".parse::<Ipv6Addr>().unwrap());
552 assert_eq!(prefix.len, 32);
553 }
554
555 #[test]
556 fn ipv6_prefix_len_zero() {
557 let prefix = Ipv6Prefix::new(Ipv6Addr::UNSPECIFIED, 0);
558 assert_eq!(prefix.addr, Ipv6Addr::UNSPECIFIED);
559 }
560
561 #[test]
562 fn ipv6_prefix_len_128() {
563 let addr: Ipv6Addr = "2001:db8::1".parse().unwrap();
564 let prefix = Ipv6Prefix::new(addr, 128);
565 assert_eq!(prefix.addr, addr);
566 assert_eq!(prefix.len, 128);
567 }
568
569 #[test]
570 fn ipv6_prefix_display() {
571 let prefix = Ipv6Prefix::new("2001:db8::".parse().unwrap(), 32);
572 assert_eq!(format!("{prefix}"), "2001:db8::/32");
573 }
574
575 #[test]
576 fn ipv6_nlri_roundtrip_single() {
577 let prefix = Ipv6Prefix::new("2001:db8::".parse().unwrap(), 32);
578 let mut buf = Vec::new();
579 encode_ipv6_nlri(&[prefix], &mut buf);
580 let decoded = decode_ipv6_nlri(&buf).unwrap();
581 assert_eq!(decoded, vec![prefix]);
582 }
583
584 #[test]
585 fn ipv6_nlri_roundtrip_multiple() {
586 let prefixes = vec![
587 Ipv6Prefix::new("2001:db8::".parse().unwrap(), 32),
588 Ipv6Prefix::new("fd00::".parse().unwrap(), 64),
589 Ipv6Prefix::new("::1".parse().unwrap(), 128),
590 ];
591 let mut buf = Vec::new();
592 encode_ipv6_nlri(&prefixes, &mut buf);
593 let decoded = decode_ipv6_nlri(&buf).unwrap();
594 assert_eq!(decoded, prefixes);
595 }
596
597 #[test]
598 fn ipv6_nlri_len_zero() {
599 let prefix = Ipv6Prefix::new(Ipv6Addr::UNSPECIFIED, 0);
600 let mut buf = Vec::new();
601 encode_ipv6_nlri(&[prefix], &mut buf);
602 assert_eq!(buf, vec![0]); let decoded = decode_ipv6_nlri(&buf).unwrap();
604 assert_eq!(decoded, vec![prefix]);
605 }
606
607 #[test]
608 fn ipv6_nlri_reject_exceeds_128() {
609 let buf = [129, 0x20, 0x01];
610 let err = decode_ipv6_nlri(&buf).unwrap_err();
611 assert!(matches!(err, DecodeError::InvalidNetworkField { .. }));
612 }
613
614 #[test]
615 fn ipv6_nlri_reject_truncated() {
616 let buf = [64, 0x20, 0x01, 0x0d, 0xb8];
618 let err = decode_ipv6_nlri(&buf).unwrap_err();
619 assert!(matches!(err, DecodeError::InvalidNetworkField { .. }));
620 }
621
622 #[test]
623 fn ipv6_nlri_empty_buffer() {
624 let decoded = decode_ipv6_nlri(&[]).unwrap();
625 assert!(decoded.is_empty());
626 }
627
628 #[test]
631 fn prefix_display_v4() {
632 let p = Prefix::V4(Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 0), 24));
633 assert_eq!(format!("{p}"), "10.0.0.0/24");
634 }
635
636 #[test]
637 fn ipv4_prefix_clamps_length() {
638 let prefix = Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 0), 33);
639 assert_eq!(prefix.len, 32);
640 let prefix = Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 0), 255);
641 assert_eq!(prefix.len, 32);
642 }
643
644 #[test]
645 fn ipv6_prefix_clamps_length() {
646 let prefix = Ipv6Prefix::new("2001:db8::".parse().unwrap(), 129);
647 assert_eq!(prefix.len, 128);
648 let prefix = Ipv6Prefix::new("2001:db8::".parse().unwrap(), 200);
649 assert_eq!(prefix.len, 128);
650 }
651
652 #[test]
653 fn prefix_display_v6() {
654 let p = Prefix::V6(Ipv6Prefix::new("2001:db8::".parse().unwrap(), 32));
655 assert_eq!(format!("{p}"), "2001:db8::/32");
656 }
657
658 #[test]
661 fn addpath_ipv4_roundtrip_single() {
662 let entry = Ipv4NlriEntry {
663 path_id: 42,
664 prefix: Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 0), 24),
665 };
666 let mut buf = Vec::new();
667 encode_nlri_addpath(&[entry], &mut buf);
668 let decoded = decode_nlri_addpath(&buf).unwrap();
669 assert_eq!(decoded, vec![entry]);
670 }
671
672 #[test]
673 fn addpath_ipv4_roundtrip_multiple() {
674 let entries = vec![
675 Ipv4NlriEntry {
676 path_id: 1,
677 prefix: Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 0), 8),
678 },
679 Ipv4NlriEntry {
680 path_id: 2,
681 prefix: Ipv4Prefix::new(Ipv4Addr::new(192, 168, 1, 0), 24),
682 },
683 Ipv4NlriEntry {
684 path_id: 0xFFFF_FFFF,
685 prefix: Ipv4Prefix::new(Ipv4Addr::new(172, 16, 0, 0), 12),
686 },
687 ];
688 let mut buf = Vec::new();
689 encode_nlri_addpath(&entries, &mut buf);
690 let decoded = decode_nlri_addpath(&buf).unwrap();
691 assert_eq!(decoded, entries);
692 }
693
694 #[test]
695 fn addpath_ipv4_empty() {
696 let decoded = decode_nlri_addpath(&[]).unwrap();
697 assert!(decoded.is_empty());
698 }
699
700 #[test]
701 fn addpath_ipv4_truncated_path_id() {
702 let buf = [0, 0, 0];
704 assert!(decode_nlri_addpath(&buf).is_err());
705 }
706
707 #[test]
708 fn addpath_ipv4_prefix_len_exceeds_32() {
709 let buf = [0, 0, 0, 1, 33, 10, 0, 0, 0, 0];
711 assert!(decode_nlri_addpath(&buf).is_err());
712 }
713
714 #[test]
715 fn addpath_ipv4_truncated_prefix() {
716 let buf = [0, 0, 0, 1, 24, 10, 0];
718 assert!(decode_nlri_addpath(&buf).is_err());
719 }
720
721 #[test]
722 fn addpath_ipv4_wire_format() {
723 let entry = Ipv4NlriEntry {
724 path_id: 1,
725 prefix: Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 0), 24),
726 };
727 let mut buf = Vec::new();
728 encode_nlri_addpath(&[entry], &mut buf);
729 assert_eq!(buf, vec![0, 0, 0, 1, 24, 10, 0, 0]);
731 }
732
733 #[test]
736 fn addpath_ipv6_roundtrip_single() {
737 let entry = NlriEntry {
738 path_id: 7,
739 prefix: Prefix::V6(Ipv6Prefix::new("2001:db8::".parse().unwrap(), 32)),
740 };
741 let mut buf = Vec::new();
742 encode_ipv6_nlri_addpath(&[entry], &mut buf);
743 let decoded = decode_ipv6_nlri_addpath(&buf).unwrap();
744 assert_eq!(decoded, vec![entry]);
745 }
746
747 #[test]
748 fn addpath_ipv6_roundtrip_multiple() {
749 let entries = vec![
750 NlriEntry {
751 path_id: 1,
752 prefix: Prefix::V6(Ipv6Prefix::new("2001:db8::".parse().unwrap(), 32)),
753 },
754 NlriEntry {
755 path_id: 2,
756 prefix: Prefix::V6(Ipv6Prefix::new("fd00::".parse().unwrap(), 64)),
757 },
758 ];
759 let mut buf = Vec::new();
760 encode_ipv6_nlri_addpath(&entries, &mut buf);
761 let decoded = decode_ipv6_nlri_addpath(&buf).unwrap();
762 assert_eq!(decoded, entries);
763 }
764
765 #[test]
766 fn addpath_ipv6_empty() {
767 let decoded = decode_ipv6_nlri_addpath(&[]).unwrap();
768 assert!(decoded.is_empty());
769 }
770
771 #[test]
772 fn addpath_ipv6_truncated() {
773 let buf = [0, 0, 0];
774 assert!(decode_ipv6_nlri_addpath(&buf).is_err());
775 }
776
777 #[test]
778 fn addpath_generic_ipv4_roundtrip() {
779 let entries = vec![Ipv4NlriEntry {
780 path_id: 1,
781 prefix: Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 0), 24),
782 }];
783 let mut buf = Vec::new();
784 encode_nlri_addpath(&entries, &mut buf);
785 let generic = decode_nlri_addpath_generic(&buf).unwrap();
786 assert_eq!(generic.len(), 1);
787 assert_eq!(generic[0].path_id, 1);
788 assert_eq!(
789 generic[0].prefix,
790 Prefix::V4(Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 0), 24))
791 );
792 }
793}