1use bytes::{Buf, BufMut, Bytes};
2
3use crate::constants::{capability_code, param_type};
4use crate::error::{DecodeError, EncodeError};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[repr(u16)]
9pub enum Afi {
10 Ipv4 = 1,
12 Ipv6 = 2,
14 L2Vpn = 25,
16}
17
18impl Afi {
19 #[must_use]
21 pub fn from_u16(value: u16) -> Option<Self> {
22 match value {
23 1 => Some(Self::Ipv4),
24 2 => Some(Self::Ipv6),
25 25 => Some(Self::L2Vpn),
26 _ => None,
27 }
28 }
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33#[repr(u8)]
34pub enum Safi {
35 Unicast = 1,
37 Multicast = 2,
39 Evpn = 70,
41 FlowSpec = 133,
43}
44
45impl Safi {
46 #[must_use]
48 pub fn from_u8(value: u8) -> Option<Self> {
49 match value {
50 1 => Some(Self::Unicast),
51 2 => Some(Self::Multicast),
52 70 => Some(Self::Evpn),
53 133 => Some(Self::FlowSpec),
54 _ => None,
55 }
56 }
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub struct GracefulRestartFamily {
62 pub afi: Afi,
64 pub safi: Safi,
66 pub forwarding_preserved: bool,
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
72#[repr(u8)]
73pub enum AddPathMode {
74 Receive = 1,
76 Send = 2,
78 Both = 3,
80}
81
82impl AddPathMode {
83 #[must_use]
85 pub fn from_u8(value: u8) -> Option<Self> {
86 match value {
87 1 => Some(Self::Receive),
88 2 => Some(Self::Send),
89 3 => Some(Self::Both),
90 _ => None,
91 }
92 }
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
97pub struct AddPathFamily {
98 pub afi: Afi,
100 pub safi: Safi,
102 pub send_receive: AddPathMode,
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
111pub struct ExtendedNextHopFamily {
112 pub nlri_afi: Afi,
114 pub nlri_safi: Safi,
116 pub next_hop_afi: Afi,
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122pub struct LlgrFamily {
123 pub afi: Afi,
125 pub safi: Safi,
127 pub forwarding_preserved: bool,
129 pub stale_time: u32,
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
140#[repr(u8)]
141pub enum BgpRole {
142 Provider = 0,
144 RouteServer = 1,
146 RouteServerClient = 2,
148 Customer = 3,
150 Peer = 4,
152}
153
154impl BgpRole {
155 #[must_use]
158 pub fn from_u8(value: u8) -> Option<Self> {
159 match value {
160 0 => Some(Self::Provider),
161 1 => Some(Self::RouteServer),
162 2 => Some(Self::RouteServerClient),
163 3 => Some(Self::Customer),
164 4 => Some(Self::Peer),
165 _ => None,
166 }
167 }
168
169 #[must_use]
171 pub fn to_u8(self) -> u8 {
172 self as u8
173 }
174}
175
176#[derive(Debug, Clone, PartialEq, Eq)]
178pub enum Capability {
179 MultiProtocol {
181 afi: Afi,
183 safi: Safi,
185 },
186 ExtendedNextHop(Vec<ExtendedNextHopFamily>),
188 GracefulRestart {
190 restart_state: bool,
193 notification: bool,
196 restart_time: u16,
198 families: Vec<GracefulRestartFamily>,
200 },
201 RouteRefresh,
203 EnhancedRouteRefresh,
205 ExtendedMessage,
207 LongLivedGracefulRestart(Vec<LlgrFamily>),
209 AddPath(Vec<AddPathFamily>),
211 FourOctetAs {
213 asn: u32,
215 },
216 Role {
218 role: BgpRole,
220 },
221 Unknown {
223 code: u8,
225 data: Bytes,
227 },
228}
229
230impl Capability {
231 #[expect(clippy::too_many_lines)]
238 pub fn decode(buf: &mut impl Buf) -> Result<Self, DecodeError> {
239 if buf.remaining() < 2 {
240 return Err(DecodeError::MalformedOptionalParameter {
241 offset: 0,
242 detail: "capability TLV too short".into(),
243 });
244 }
245
246 let code = buf.get_u8();
247 let length = buf.get_u8();
248
249 if buf.remaining() < usize::from(length) {
250 return Err(DecodeError::MalformedOptionalParameter {
251 offset: 0,
252 detail: format!(
253 "capability code {code} claims length {length}, \
254 but only {} bytes remain",
255 buf.remaining()
256 ),
257 });
258 }
259
260 match code {
261 capability_code::MULTI_PROTOCOL => {
262 if length != 4 {
263 let data = buf.copy_to_bytes(usize::from(length));
265 return Ok(Capability::Unknown { code, data });
266 }
267 let afi_raw = buf.get_u16();
268 let _reserved = buf.get_u8();
269 let safi_raw = buf.get_u8();
270
271 if let (Some(afi), Some(safi)) = (Afi::from_u16(afi_raw), Safi::from_u8(safi_raw)) {
272 Ok(Capability::MultiProtocol { afi, safi })
273 } else {
274 let mut data = bytes::BytesMut::with_capacity(4);
276 data.put_u16(afi_raw);
277 data.put_u8(0); data.put_u8(safi_raw);
279 Ok(Capability::Unknown {
280 code,
281 data: data.freeze(),
282 })
283 }
284 }
285 capability_code::ROUTE_REFRESH => {
286 if length != 0 {
287 let data = buf.copy_to_bytes(usize::from(length));
288 return Ok(Capability::Unknown { code, data });
289 }
290 Ok(Capability::RouteRefresh)
291 }
292 capability_code::ENHANCED_ROUTE_REFRESH => {
293 if length != 0 {
294 let data = buf.copy_to_bytes(usize::from(length));
295 return Ok(Capability::Unknown { code, data });
296 }
297 Ok(Capability::EnhancedRouteRefresh)
298 }
299 capability_code::EXTENDED_NEXT_HOP => {
300 if !usize::from(length).is_multiple_of(6) {
303 let data = buf.copy_to_bytes(usize::from(length));
304 return Ok(Capability::Unknown { code, data });
305 }
306 let entry_count = usize::from(length) / 6;
307 let raw_data = buf.copy_to_bytes(usize::from(length));
308 let mut cursor = raw_data.clone();
309 let mut families = Vec::with_capacity(entry_count);
310 let mut all_valid = true;
311 for _ in 0..entry_count {
312 let nlri_afi_raw = cursor.get_u16();
313 let nlri_safi_field = cursor.get_u16();
314 let next_hop_afi_raw = cursor.get_u16();
315 let nlri_safi = u8::try_from(nlri_safi_field).ok().and_then(Safi::from_u8);
316 if let (Some(nlri_afi), Some(nlri_safi), Some(next_hop_afi)) = (
317 Afi::from_u16(nlri_afi_raw),
318 nlri_safi,
319 Afi::from_u16(next_hop_afi_raw),
320 ) {
321 families.push(ExtendedNextHopFamily {
322 nlri_afi,
323 nlri_safi,
324 next_hop_afi,
325 });
326 } else {
327 all_valid = false;
328 }
329 }
330 if all_valid {
331 Ok(Capability::ExtendedNextHop(families))
332 } else {
333 Ok(Capability::Unknown {
334 code,
335 data: raw_data,
336 })
337 }
338 }
339 capability_code::EXTENDED_MESSAGE => {
340 if length != 0 {
341 let data = buf.copy_to_bytes(usize::from(length));
342 return Ok(Capability::Unknown { code, data });
343 }
344 Ok(Capability::ExtendedMessage)
345 }
346 capability_code::GRACEFUL_RESTART => {
347 if length < 2 || !(length - 2).is_multiple_of(4) {
349 let data = buf.copy_to_bytes(usize::from(length));
350 return Ok(Capability::Unknown { code, data });
351 }
352 let flags_and_time = buf.get_u16();
353 let restart_state = (flags_and_time & 0x8000) != 0;
354 let notification = (flags_and_time & 0x4000) != 0;
355 let restart_time = flags_and_time & 0x0FFF;
356 let family_count = (length - 2) / 4;
357 let mut families = Vec::with_capacity(usize::from(family_count));
358 for _ in 0..family_count {
359 let afi_raw = buf.get_u16();
360 let safi_raw = buf.get_u8();
361 let flags = buf.get_u8();
362 if let (Some(afi), Some(safi)) =
363 (Afi::from_u16(afi_raw), Safi::from_u8(safi_raw))
364 {
365 families.push(GracefulRestartFamily {
366 afi,
367 safi,
368 forwarding_preserved: (flags & 0x80) != 0,
369 });
370 }
371 }
373 Ok(Capability::GracefulRestart {
374 restart_state,
375 notification,
376 restart_time,
377 families,
378 })
379 }
380 capability_code::LONG_LIVED_GRACEFUL_RESTART => {
381 if !usize::from(length).is_multiple_of(7) {
383 let data = buf.copy_to_bytes(usize::from(length));
384 return Ok(Capability::Unknown { code, data });
385 }
386 let entry_count = usize::from(length) / 7;
387 let raw_data = buf.copy_to_bytes(usize::from(length));
388 let mut cursor = raw_data.clone();
389 let mut families = Vec::with_capacity(entry_count);
390 let mut all_valid = true;
391 for _ in 0..entry_count {
392 let afi_raw = cursor.get_u16();
393 let safi_raw = cursor.get_u8();
394 let flags = cursor.get_u8();
395 let st_hi = cursor.get_u8();
397 let st_lo = cursor.get_u16();
398 let stale_time = (u32::from(st_hi) << 16) | u32::from(st_lo);
399 if let (Some(afi), Some(safi)) =
400 (Afi::from_u16(afi_raw), Safi::from_u8(safi_raw))
401 {
402 families.push(LlgrFamily {
403 afi,
404 safi,
405 forwarding_preserved: (flags & 0x80) != 0,
406 stale_time,
407 });
408 } else {
409 all_valid = false;
410 }
411 }
412 if all_valid {
413 Ok(Capability::LongLivedGracefulRestart(families))
414 } else {
415 Ok(Capability::Unknown {
416 code,
417 data: raw_data,
418 })
419 }
420 }
421 capability_code::ADD_PATH => {
422 if length == 0 || !usize::from(length).is_multiple_of(4) {
424 let data = buf.copy_to_bytes(usize::from(length));
425 return Ok(Capability::Unknown { code, data });
426 }
427 let entry_count = usize::from(length) / 4;
428 let raw_data = buf.copy_to_bytes(usize::from(length));
431 let mut cursor = raw_data.clone();
432 let mut families = Vec::with_capacity(entry_count);
433 let mut all_valid = true;
434 for _ in 0..entry_count {
435 let afi_raw = cursor.get_u16();
436 let safi_raw = cursor.get_u8();
437 let mode_raw = cursor.get_u8();
438 if let (Some(afi), Some(safi), Some(mode)) = (
439 Afi::from_u16(afi_raw),
440 Safi::from_u8(safi_raw),
441 AddPathMode::from_u8(mode_raw),
442 ) {
443 families.push(AddPathFamily {
444 afi,
445 safi,
446 send_receive: mode,
447 });
448 } else {
449 all_valid = false;
450 }
451 }
452 if all_valid {
455 Ok(Capability::AddPath(families))
456 } else {
457 Ok(Capability::Unknown {
458 code,
459 data: raw_data,
460 })
461 }
462 }
463 capability_code::FOUR_OCTET_AS => {
464 if length != 4 {
465 let data = buf.copy_to_bytes(usize::from(length));
466 return Ok(Capability::Unknown { code, data });
467 }
468 let asn = buf.get_u32();
469 Ok(Capability::FourOctetAs { asn })
470 }
471 capability_code::BGP_ROLE => {
472 if length != 1 {
476 let data = buf.copy_to_bytes(usize::from(length));
477 return Ok(Capability::Unknown { code, data });
478 }
479 let role_byte = buf.get_u8();
480 if let Some(role) = BgpRole::from_u8(role_byte) {
481 Ok(Capability::Role { role })
482 } else {
483 let data = Bytes::copy_from_slice(&[role_byte]);
484 Ok(Capability::Unknown { code, data })
485 }
486 }
487 _ => {
488 let data = buf.copy_to_bytes(usize::from(length));
489 Ok(Capability::Unknown { code, data })
490 }
491 }
492 }
493
494 #[expect(
501 clippy::too_many_lines,
502 reason = "Capability encode keeps all TLV variants in one exhaustive wire encoder"
503 )]
504 pub fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
505 match self {
506 Capability::MultiProtocol { afi, safi } => {
507 buf.put_u8(capability_code::MULTI_PROTOCOL);
508 buf.put_u8(4); buf.put_u16(*afi as u16);
510 buf.put_u8(0); buf.put_u8(*safi as u8);
512 }
513 Capability::RouteRefresh => {
514 buf.put_u8(capability_code::ROUTE_REFRESH);
515 buf.put_u8(0); }
517 Capability::EnhancedRouteRefresh => {
518 buf.put_u8(capability_code::ENHANCED_ROUTE_REFRESH);
519 buf.put_u8(0); }
521 Capability::ExtendedNextHop(families) => {
522 let value_len = families.len() * 6;
523 if value_len > 255 {
524 return Err(EncodeError::ValueOutOfRange {
525 field: "extended_next_hop_capability_length",
526 value: value_len.to_string(),
527 });
528 }
529 buf.put_u8(capability_code::EXTENDED_NEXT_HOP);
530 #[expect(clippy::cast_possible_truncation)]
531 buf.put_u8(value_len as u8);
532 for fam in families {
533 buf.put_u16(fam.nlri_afi as u16);
534 buf.put_u16(u16::from(fam.nlri_safi as u8));
535 buf.put_u16(fam.next_hop_afi as u16);
536 }
537 }
538 Capability::ExtendedMessage => {
539 buf.put_u8(capability_code::EXTENDED_MESSAGE);
540 buf.put_u8(0); }
542 Capability::GracefulRestart {
543 restart_state,
544 notification,
545 restart_time,
546 families,
547 } => {
548 let value_len = 2 + families.len() * 4;
549 if value_len > 255 {
550 return Err(EncodeError::ValueOutOfRange {
551 field: "graceful_restart_capability_length",
552 value: value_len.to_string(),
553 });
554 }
555 if *restart_time > 4095 {
556 return Err(EncodeError::ValueOutOfRange {
557 field: "graceful_restart_time",
558 value: restart_time.to_string(),
559 });
560 }
561 buf.put_u8(capability_code::GRACEFUL_RESTART);
562 #[expect(clippy::cast_possible_truncation)]
563 buf.put_u8(value_len as u8);
564 let mut flags_and_time = *restart_time;
565 if *restart_state {
566 flags_and_time |= 0x8000;
567 }
568 if *notification {
569 flags_and_time |= 0x4000;
570 }
571 buf.put_u16(flags_and_time);
572 for fam in families {
573 buf.put_u16(fam.afi as u16);
574 buf.put_u8(fam.safi as u8);
575 buf.put_u8(if fam.forwarding_preserved { 0x80 } else { 0 });
576 }
577 }
578 Capability::LongLivedGracefulRestart(families) => {
579 let value_len = families.len() * 7;
580 if value_len > 255 {
581 return Err(EncodeError::ValueOutOfRange {
582 field: "llgr_capability_length",
583 value: value_len.to_string(),
584 });
585 }
586 buf.put_u8(capability_code::LONG_LIVED_GRACEFUL_RESTART);
587 #[expect(clippy::cast_possible_truncation)]
588 buf.put_u8(value_len as u8);
589 for fam in families {
590 buf.put_u16(fam.afi as u16);
591 buf.put_u8(fam.safi as u8);
592 buf.put_u8(if fam.forwarding_preserved { 0x80 } else { 0 });
593 #[expect(clippy::cast_possible_truncation)]
595 buf.put_u8((fam.stale_time >> 16) as u8);
596 buf.put_u16((fam.stale_time & 0xFFFF) as u16);
597 }
598 }
599 Capability::AddPath(families) => {
600 let value_len = families.len() * 4;
601 if value_len > 255 {
602 return Err(EncodeError::ValueOutOfRange {
603 field: "add_path_capability_length",
604 value: value_len.to_string(),
605 });
606 }
607 buf.put_u8(capability_code::ADD_PATH);
608 #[expect(clippy::cast_possible_truncation)]
609 buf.put_u8(value_len as u8);
610 for fam in families {
611 buf.put_u16(fam.afi as u16);
612 buf.put_u8(fam.safi as u8);
613 buf.put_u8(fam.send_receive as u8);
614 }
615 }
616 Capability::FourOctetAs { asn } => {
617 buf.put_u8(capability_code::FOUR_OCTET_AS);
618 buf.put_u8(4); buf.put_u32(*asn);
620 }
621 Capability::Role { role } => {
622 buf.put_u8(capability_code::BGP_ROLE);
623 buf.put_u8(1); buf.put_u8(role.to_u8());
625 }
626 Capability::Unknown { code, data } => {
627 if data.len() > 255 {
628 return Err(EncodeError::ValueOutOfRange {
629 field: "unknown_capability_length",
630 value: data.len().to_string(),
631 });
632 }
633 buf.put_u8(*code);
634 #[expect(clippy::cast_possible_truncation)]
635 buf.put_u8(data.len() as u8);
636 buf.put_slice(data);
637 }
638 }
639 Ok(())
640 }
641
642 #[must_use]
644 pub fn code(&self) -> u8 {
645 match self {
646 Self::MultiProtocol { .. } => capability_code::MULTI_PROTOCOL,
647 Self::RouteRefresh => capability_code::ROUTE_REFRESH,
648 Self::EnhancedRouteRefresh => capability_code::ENHANCED_ROUTE_REFRESH,
649 Self::ExtendedNextHop(_) => capability_code::EXTENDED_NEXT_HOP,
650 Self::ExtendedMessage => capability_code::EXTENDED_MESSAGE,
651 Self::LongLivedGracefulRestart(_) => capability_code::LONG_LIVED_GRACEFUL_RESTART,
652 Self::AddPath(_) => capability_code::ADD_PATH,
653 Self::GracefulRestart { .. } => capability_code::GRACEFUL_RESTART,
654 Self::FourOctetAs { .. } => capability_code::FOUR_OCTET_AS,
655 Self::Role { .. } => capability_code::BGP_ROLE,
656 Self::Unknown { code, .. } => *code,
657 }
658 }
659
660 #[must_use]
662 pub fn encoded_len(&self) -> usize {
663 2 + match self {
664 Self::MultiProtocol { .. } | Self::FourOctetAs { .. } => 4,
665 Self::RouteRefresh | Self::EnhancedRouteRefresh | Self::ExtendedMessage => 0,
666 Self::Role { .. } => 1,
667 Self::ExtendedNextHop(families) => families.len() * 6,
668 Self::LongLivedGracefulRestart(families) => families.len() * 7,
669 Self::AddPath(families) => families.len() * 4,
670 Self::GracefulRestart { families, .. } => 2 + families.len() * 4,
671 Self::Unknown { data, .. } => data.len(),
672 }
673 }
674}
675
676pub fn decode_optional_parameters(
684 buf: &mut impl Buf,
685 opt_params_len: u8,
686) -> Result<Vec<Capability>, DecodeError> {
687 let mut capabilities = Vec::new();
688 let mut remaining = usize::from(opt_params_len);
689
690 while remaining > 0 {
691 if buf.remaining() < 2 {
692 return Err(DecodeError::MalformedOptionalParameter {
693 offset: usize::from(opt_params_len) - remaining,
694 detail: "optional parameter TLV too short".into(),
695 });
696 }
697
698 let param_type = buf.get_u8();
699 let param_len = buf.get_u8();
700 remaining = remaining.saturating_sub(2);
701
702 if usize::from(param_len) > remaining || buf.remaining() < usize::from(param_len) {
703 return Err(DecodeError::MalformedOptionalParameter {
704 offset: usize::from(opt_params_len) - remaining,
705 detail: format!(
706 "parameter type {param_type} claims length {param_len}, \
707 but only {remaining} bytes remain"
708 ),
709 });
710 }
711
712 if param_type == param_type::CAPABILITIES {
713 let param_bytes = buf.copy_to_bytes(usize::from(param_len));
717 let mut cap_buf = param_bytes;
718 while cap_buf.has_remaining() {
719 let cap = Capability::decode(&mut cap_buf)?;
720 capabilities.push(cap);
721 }
722 } else {
723 buf.advance(usize::from(param_len));
725 }
726
727 remaining = remaining.saturating_sub(usize::from(param_len));
728 }
729
730 Ok(capabilities)
731}
732
733pub fn encode_optional_parameters(
746 capabilities: &[Capability],
747 buf: &mut impl BufMut,
748) -> Result<(), EncodeError> {
749 if capabilities.is_empty() {
750 return Ok(());
751 }
752
753 let cap_total: usize = capabilities.iter().map(Capability::encoded_len).sum();
755
756 if cap_total > 255 {
757 return Err(EncodeError::ValueOutOfRange {
758 field: "capabilities_parameter_length",
759 value: cap_total.to_string(),
760 });
761 }
762
763 buf.put_u8(param_type::CAPABILITIES);
765 #[expect(clippy::cast_possible_truncation)]
766 buf.put_u8(cap_total as u8);
767
768 for cap in capabilities {
769 cap.encode(buf)?;
770 }
771 Ok(())
772}
773
774#[cfg(test)]
775mod tests {
776 use super::*;
777
778 #[test]
779 fn decode_multi_protocol_ipv4_unicast() {
780 let data: &[u8] = &[1, 4, 0, 1, 0, 1]; let mut buf = Bytes::copy_from_slice(data);
782 let cap = Capability::decode(&mut buf).unwrap();
783 assert_eq!(
784 cap,
785 Capability::MultiProtocol {
786 afi: Afi::Ipv4,
787 safi: Safi::Unicast
788 }
789 );
790 }
791
792 #[test]
793 fn decode_four_octet_as() {
794 let data: &[u8] = &[65, 4, 0, 0, 0xFD, 0xE8]; let mut buf = Bytes::copy_from_slice(data);
796 let cap = Capability::decode(&mut buf).unwrap();
797 assert_eq!(cap, Capability::FourOctetAs { asn: 65000 });
798 }
799
800 #[test]
801 fn decode_unknown_capability_preserved() {
802 let data: &[u8] = &[99, 3, 0xAA, 0xBB, 0xCC]; let mut buf = Bytes::copy_from_slice(data);
804 let cap = Capability::decode(&mut buf).unwrap();
805 match cap {
806 Capability::Unknown { code, data } => {
807 assert_eq!(code, 99);
808 assert_eq!(data.as_ref(), &[0xAA, 0xBB, 0xCC]);
809 }
810 _ => panic!("expected Unknown"),
811 }
812 }
813
814 #[test]
815 fn unrecognized_afi_safi_stored_as_unknown() {
816 let data: &[u8] = &[1, 4, 0, 99, 0, 1]; let mut buf = Bytes::copy_from_slice(data);
818 let cap = Capability::decode(&mut buf).unwrap();
819 assert!(matches!(cap, Capability::Unknown { code: 1, .. }));
820 }
821
822 #[test]
823 fn roundtrip_multi_protocol() {
824 let original = Capability::MultiProtocol {
825 afi: Afi::Ipv6,
826 safi: Safi::Unicast,
827 };
828 let mut encoded = bytes::BytesMut::with_capacity(6);
829 original.encode(&mut encoded).unwrap();
830 let mut buf = encoded.freeze();
831 let decoded = Capability::decode(&mut buf).unwrap();
832 assert_eq!(original, decoded);
833 }
834
835 #[test]
836 fn roundtrip_four_octet_as() {
837 let original = Capability::FourOctetAs { asn: 4_200_000_000 };
838 let mut encoded = bytes::BytesMut::with_capacity(6);
839 original.encode(&mut encoded).unwrap();
840 let mut buf = encoded.freeze();
841 let decoded = Capability::decode(&mut buf).unwrap();
842 assert_eq!(original, decoded);
843 }
844
845 #[test]
846 fn roundtrip_unknown() {
847 let original = Capability::Unknown {
848 code: 42,
849 data: Bytes::from_static(&[1, 2, 3]),
850 };
851 let mut encoded = bytes::BytesMut::with_capacity(5);
852 original.encode(&mut encoded).unwrap();
853 let mut buf = encoded.freeze();
854 let decoded = Capability::decode(&mut buf).unwrap();
855 assert_eq!(original, decoded);
856 }
857
858 #[test]
859 fn decode_optional_params_multiple_caps() {
860 let mut data = bytes::BytesMut::new();
862 data.put_u8(2); data.put_u8(12); data.put_u8(1);
866 data.put_u8(4);
867 data.put_u16(1); data.put_u8(0);
869 data.put_u8(1); data.put_u8(65);
872 data.put_u8(4);
873 data.put_u32(65001);
874
875 let mut buf = data.freeze();
876 let caps = decode_optional_parameters(&mut buf, 14).unwrap();
877 assert_eq!(caps.len(), 2);
878 assert_eq!(
879 caps[0],
880 Capability::MultiProtocol {
881 afi: Afi::Ipv4,
882 safi: Safi::Unicast
883 }
884 );
885 assert_eq!(caps[1], Capability::FourOctetAs { asn: 65001 });
886 }
887
888 #[test]
889 fn decode_empty_optional_params() {
890 let mut buf = Bytes::new();
891 let caps = decode_optional_parameters(&mut buf, 0).unwrap();
892 assert!(caps.is_empty());
893 }
894
895 #[test]
896 fn reject_truncated_capability() {
897 let data: &[u8] = &[65, 4, 0, 0]; let mut buf = Bytes::copy_from_slice(data);
899 assert!(Capability::decode(&mut buf).is_err());
900 }
901
902 #[test]
903 fn decode_graceful_restart_with_families() {
904 let mut data = bytes::BytesMut::new();
908 data.put_u8(64); data.put_u8(10); data.put_u16(0x8078); data.put_u16(1); data.put_u8(1); data.put_u8(0x80); data.put_u16(2); data.put_u8(1); data.put_u8(0x00); let mut buf = data.freeze();
919 let cap = Capability::decode(&mut buf).unwrap();
920 assert_eq!(
921 cap,
922 Capability::GracefulRestart {
923 restart_state: true,
924 notification: false,
925 restart_time: 120,
926 families: vec![
927 GracefulRestartFamily {
928 afi: Afi::Ipv4,
929 safi: Safi::Unicast,
930 forwarding_preserved: true,
931 },
932 GracefulRestartFamily {
933 afi: Afi::Ipv6,
934 safi: Safi::Unicast,
935 forwarding_preserved: false,
936 },
937 ],
938 }
939 );
940 }
941
942 #[test]
943 fn decode_graceful_restart_no_r_bit() {
944 let mut data = bytes::BytesMut::new();
945 data.put_u8(64);
946 data.put_u8(6); data.put_u16(0x005A); data.put_u16(1); data.put_u8(1); data.put_u8(0x00); let mut buf = data.freeze();
953 let cap = Capability::decode(&mut buf).unwrap();
954 assert_eq!(
955 cap,
956 Capability::GracefulRestart {
957 restart_state: false,
958 notification: false,
959 restart_time: 90,
960 families: vec![GracefulRestartFamily {
961 afi: Afi::Ipv4,
962 safi: Safi::Unicast,
963 forwarding_preserved: false,
964 }],
965 }
966 );
967 }
968
969 #[test]
970 fn decode_graceful_restart_empty_families() {
971 let mut data = bytes::BytesMut::new();
972 data.put_u8(64);
973 data.put_u8(2); data.put_u16(0x003C); let mut buf = data.freeze();
977 let cap = Capability::decode(&mut buf).unwrap();
978 assert_eq!(
979 cap,
980 Capability::GracefulRestart {
981 restart_state: false,
982 notification: false,
983 restart_time: 60,
984 families: vec![],
985 }
986 );
987 }
988
989 #[test]
990 fn roundtrip_graceful_restart() {
991 let original = Capability::GracefulRestart {
992 restart_state: true,
993 notification: false,
994 restart_time: 120,
995 families: vec![
996 GracefulRestartFamily {
997 afi: Afi::Ipv4,
998 safi: Safi::Unicast,
999 forwarding_preserved: true,
1000 },
1001 GracefulRestartFamily {
1002 afi: Afi::Ipv6,
1003 safi: Safi::Unicast,
1004 forwarding_preserved: false,
1005 },
1006 ],
1007 };
1008 let mut encoded = bytes::BytesMut::with_capacity(12);
1009 original.encode(&mut encoded).unwrap();
1010 let mut buf = encoded.freeze();
1011 let decoded = Capability::decode(&mut buf).unwrap();
1012 assert_eq!(original, decoded);
1013 }
1014
1015 #[test]
1016 fn graceful_restart_encoded_len() {
1017 let cap = Capability::GracefulRestart {
1018 restart_state: false,
1019 notification: false,
1020 restart_time: 120,
1021 families: vec![GracefulRestartFamily {
1022 afi: Afi::Ipv4,
1023 safi: Safi::Unicast,
1024 forwarding_preserved: true,
1025 }],
1026 };
1027 assert_eq!(cap.encoded_len(), 8);
1029 }
1030
1031 #[test]
1032 fn graceful_restart_code() {
1033 let cap = Capability::GracefulRestart {
1034 restart_state: false,
1035 notification: false,
1036 restart_time: 0,
1037 families: vec![],
1038 };
1039 assert_eq!(cap.code(), 64);
1040 }
1041
1042 #[test]
1043 fn graceful_restart_bad_length_stored_as_unknown() {
1044 let data: &[u8] = &[64, 3, 0x00, 0x3C, 0xFF];
1046 let mut buf = Bytes::copy_from_slice(data);
1047 let cap = Capability::decode(&mut buf).unwrap();
1048 assert!(matches!(cap, Capability::Unknown { code: 64, .. }));
1049 }
1050
1051 #[test]
1052 fn encode_rejects_oversized_gr_families() {
1053 let families: Vec<GracefulRestartFamily> = (0..64)
1055 .map(|_| GracefulRestartFamily {
1056 afi: Afi::Ipv4,
1057 safi: Safi::Unicast,
1058 forwarding_preserved: false,
1059 })
1060 .collect();
1061 let cap = Capability::GracefulRestart {
1062 restart_state: false,
1063 notification: false,
1064 restart_time: 120,
1065 families,
1066 };
1067 let mut buf = bytes::BytesMut::new();
1068 assert!(cap.encode(&mut buf).is_err());
1069 }
1070
1071 #[test]
1072 fn encode_rejects_oversized_unknown_data() {
1073 let cap = Capability::Unknown {
1074 code: 99,
1075 data: Bytes::from(vec![0u8; 256]),
1076 };
1077 let mut buf = bytes::BytesMut::new();
1078 assert!(cap.encode(&mut buf).is_err());
1079 }
1080
1081 #[test]
1082 fn encode_optional_params_rejects_overflow() {
1083 let caps: Vec<Capability> = (0..50)
1085 .map(|_| Capability::Unknown {
1086 code: 99,
1087 data: Bytes::from(vec![0u8; 5]),
1088 })
1089 .collect();
1090 let mut buf = bytes::BytesMut::new();
1092 assert!(encode_optional_parameters(&caps, &mut buf).is_err());
1093 }
1094
1095 #[test]
1096 fn encode_rejects_restart_time_over_4095() {
1097 let cap = Capability::GracefulRestart {
1098 restart_state: false,
1099 notification: false,
1100 restart_time: 4096,
1101 families: vec![],
1102 };
1103 let mut buf = bytes::BytesMut::new();
1104 assert!(cap.encode(&mut buf).is_err());
1105 }
1106
1107 #[test]
1108 fn encode_accepts_restart_time_at_4095() {
1109 let cap = Capability::GracefulRestart {
1110 restart_state: false,
1111 notification: false,
1112 restart_time: 4095,
1113 families: vec![],
1114 };
1115 let mut buf = bytes::BytesMut::new();
1116 assert!(cap.encode(&mut buf).is_ok());
1117 }
1118
1119 #[test]
1120 fn decode_graceful_restart_n_bit() {
1121 let mut data = bytes::BytesMut::new();
1122 data.put_u8(64);
1123 data.put_u8(6); data.put_u16(0xC078); data.put_u16(1); data.put_u8(1); data.put_u8(0x80); let mut buf = data.freeze();
1130 let cap = Capability::decode(&mut buf).unwrap();
1131 assert_eq!(
1132 cap,
1133 Capability::GracefulRestart {
1134 restart_state: true,
1135 notification: true,
1136 restart_time: 120,
1137 families: vec![GracefulRestartFamily {
1138 afi: Afi::Ipv4,
1139 safi: Safi::Unicast,
1140 forwarding_preserved: true,
1141 }],
1142 }
1143 );
1144 }
1145
1146 #[test]
1147 fn roundtrip_graceful_restart_with_n_bit() {
1148 let original = Capability::GracefulRestart {
1149 restart_state: true,
1150 notification: true,
1151 restart_time: 120,
1152 families: vec![GracefulRestartFamily {
1153 afi: Afi::Ipv4,
1154 safi: Safi::Unicast,
1155 forwarding_preserved: true,
1156 }],
1157 };
1158 let mut encoded = bytes::BytesMut::with_capacity(12);
1159 original.encode(&mut encoded).unwrap();
1160 let mut buf = encoded.freeze();
1161 let decoded = Capability::decode(&mut buf).unwrap();
1162 assert_eq!(original, decoded);
1163 }
1164
1165 #[test]
1166 fn decode_capability_bounded_to_parameter_slice() {
1167 let mut data = bytes::BytesMut::new();
1173 data.put_u8(2); data.put_u8(4); data.put_u8(65);
1178 data.put_u8(8); data.put_u16(0xBEEF); data.put_u8(99); data.put_u8(2); data.put_u16(0xCAFE);
1184
1185 let mut buf = data.freeze();
1186 let result = decode_optional_parameters(&mut buf, 8);
1190 assert!(result.is_err());
1191 }
1192
1193 #[test]
1194 fn decode_extended_message() {
1195 let data: &[u8] = &[6, 0]; let mut buf = Bytes::copy_from_slice(data);
1197 let cap = Capability::decode(&mut buf).unwrap();
1198 assert_eq!(cap, Capability::ExtendedMessage);
1199 }
1200
1201 #[test]
1202 fn roundtrip_extended_message() {
1203 let original = Capability::ExtendedMessage;
1204 let mut encoded = bytes::BytesMut::with_capacity(2);
1205 original.encode(&mut encoded).unwrap();
1206 let mut buf = encoded.freeze();
1207 let decoded = Capability::decode(&mut buf).unwrap();
1208 assert_eq!(original, decoded);
1209 }
1210
1211 #[test]
1212 fn extended_message_code_and_len() {
1213 let cap = Capability::ExtendedMessage;
1214 assert_eq!(cap.code(), 6);
1215 assert_eq!(cap.encoded_len(), 2);
1216 }
1217
1218 #[test]
1219 fn extended_message_bad_length_stored_as_unknown() {
1220 let data: &[u8] = &[6, 1, 0xFF]; let mut buf = Bytes::copy_from_slice(data);
1222 let cap = Capability::decode(&mut buf).unwrap();
1223 assert!(matches!(cap, Capability::Unknown { code: 6, .. }));
1224 }
1225
1226 #[test]
1229 fn decode_extended_nexthop_single_family() {
1230 let data: &[u8] = &[5, 6, 0, 1, 0, 1, 0, 2];
1233 let mut buf = Bytes::copy_from_slice(data);
1234 let cap = Capability::decode(&mut buf).unwrap();
1235 assert_eq!(
1236 cap,
1237 Capability::ExtendedNextHop(vec![ExtendedNextHopFamily {
1238 nlri_afi: Afi::Ipv4,
1239 nlri_safi: Safi::Unicast,
1240 next_hop_afi: Afi::Ipv6,
1241 }])
1242 );
1243 }
1244
1245 #[test]
1246 fn roundtrip_extended_nexthop() {
1247 let original = Capability::ExtendedNextHop(vec![ExtendedNextHopFamily {
1248 nlri_afi: Afi::Ipv4,
1249 nlri_safi: Safi::Unicast,
1250 next_hop_afi: Afi::Ipv6,
1251 }]);
1252 let mut encoded = bytes::BytesMut::with_capacity(8);
1253 original.encode(&mut encoded).unwrap();
1254 let mut buf = encoded.freeze();
1255 let decoded = Capability::decode(&mut buf).unwrap();
1256 assert_eq!(original, decoded);
1257 }
1258
1259 #[test]
1260 fn extended_nexthop_bad_length_stored_as_unknown() {
1261 let data: &[u8] = &[5, 4, 0, 1, 0, 1];
1263 let mut buf = Bytes::copy_from_slice(data);
1264 let cap = Capability::decode(&mut buf).unwrap();
1265 assert!(matches!(cap, Capability::Unknown { code: 5, .. }));
1266 }
1267
1268 #[test]
1271 fn decode_add_path_single_family() {
1272 let data: &[u8] = &[69, 4, 0, 1, 1, 3];
1274 let mut buf = Bytes::copy_from_slice(data);
1275 let cap = Capability::decode(&mut buf).unwrap();
1276 assert_eq!(
1277 cap,
1278 Capability::AddPath(vec![AddPathFamily {
1279 afi: Afi::Ipv4,
1280 safi: Safi::Unicast,
1281 send_receive: AddPathMode::Both,
1282 }])
1283 );
1284 }
1285
1286 #[test]
1287 fn decode_add_path_multiple_families() {
1288 let mut data = bytes::BytesMut::new();
1289 data.put_u8(69); data.put_u8(8); data.put_u16(1); data.put_u8(1); data.put_u8(1); data.put_u16(2); data.put_u8(1); data.put_u8(2); let mut buf = data.freeze();
1299 let cap = Capability::decode(&mut buf).unwrap();
1300 assert_eq!(
1301 cap,
1302 Capability::AddPath(vec![
1303 AddPathFamily {
1304 afi: Afi::Ipv4,
1305 safi: Safi::Unicast,
1306 send_receive: AddPathMode::Receive,
1307 },
1308 AddPathFamily {
1309 afi: Afi::Ipv6,
1310 safi: Safi::Unicast,
1311 send_receive: AddPathMode::Send,
1312 },
1313 ])
1314 );
1315 }
1316
1317 #[test]
1318 fn roundtrip_add_path() {
1319 let original = Capability::AddPath(vec![
1320 AddPathFamily {
1321 afi: Afi::Ipv4,
1322 safi: Safi::Unicast,
1323 send_receive: AddPathMode::Both,
1324 },
1325 AddPathFamily {
1326 afi: Afi::Ipv6,
1327 safi: Safi::Unicast,
1328 send_receive: AddPathMode::Receive,
1329 },
1330 ]);
1331 let mut encoded = bytes::BytesMut::with_capacity(10);
1332 original.encode(&mut encoded).unwrap();
1333 let mut buf = encoded.freeze();
1334 let decoded = Capability::decode(&mut buf).unwrap();
1335 assert_eq!(original, decoded);
1336 }
1337
1338 #[test]
1339 fn add_path_code_and_len() {
1340 let cap = Capability::AddPath(vec![AddPathFamily {
1341 afi: Afi::Ipv4,
1342 safi: Safi::Unicast,
1343 send_receive: AddPathMode::Receive,
1344 }]);
1345 assert_eq!(cap.code(), 69);
1346 assert_eq!(cap.encoded_len(), 6);
1348 }
1349
1350 #[test]
1351 fn add_path_bad_length_stored_as_unknown() {
1352 let data: &[u8] = &[69, 3, 0, 1, 1];
1354 let mut buf = Bytes::copy_from_slice(data);
1355 let cap = Capability::decode(&mut buf).unwrap();
1356 assert!(matches!(cap, Capability::Unknown { code: 69, .. }));
1357 }
1358
1359 #[test]
1360 fn add_path_zero_length_stored_as_unknown() {
1361 let data: &[u8] = &[69, 0];
1363 let mut buf = Bytes::copy_from_slice(data);
1364 let cap = Capability::decode(&mut buf).unwrap();
1365 assert!(matches!(cap, Capability::Unknown { code: 69, .. }));
1366 }
1367
1368 #[test]
1369 fn add_path_unknown_afi_preserved_as_unknown() {
1370 let data: &[u8] = &[69, 4, 0, 99, 1, 3];
1372 let mut buf = Bytes::copy_from_slice(data);
1373 let cap = Capability::decode(&mut buf).unwrap();
1374 assert!(matches!(cap, Capability::Unknown { code: 69, .. }));
1376 }
1377
1378 #[test]
1379 fn add_path_invalid_mode_preserved_as_unknown() {
1380 let data: &[u8] = &[69, 4, 0, 1, 1, 0];
1382 let mut buf = Bytes::copy_from_slice(data);
1383 let cap = Capability::decode(&mut buf).unwrap();
1384 assert!(matches!(cap, Capability::Unknown { code: 69, .. }));
1386 }
1387
1388 #[test]
1389 fn add_path_mixed_valid_and_invalid_preserved_as_unknown() {
1390 let mut data = bytes::BytesMut::new();
1392 data.put_u8(69); data.put_u8(8); data.put_u16(1); data.put_u8(1); data.put_u8(3); data.put_u16(99); data.put_u8(1); data.put_u8(3); let mut buf = data.freeze();
1401 let cap = Capability::decode(&mut buf).unwrap();
1402 assert!(matches!(cap, Capability::Unknown { code: 69, .. }));
1404 }
1405
1406 #[test]
1407 fn llgr_capability_roundtrip() {
1408 let families = vec![
1409 LlgrFamily {
1410 afi: Afi::Ipv4,
1411 safi: Safi::Unicast,
1412 forwarding_preserved: true,
1413 stale_time: 86400,
1414 },
1415 LlgrFamily {
1416 afi: Afi::Ipv6,
1417 safi: Safi::Unicast,
1418 forwarding_preserved: false,
1419 stale_time: 3600,
1420 },
1421 ];
1422 let cap = Capability::LongLivedGracefulRestart(families);
1423
1424 let mut buf = bytes::BytesMut::new();
1425 cap.encode(&mut buf).unwrap();
1426 let mut frozen = buf.freeze();
1427 let decoded = Capability::decode(&mut frozen).unwrap();
1428
1429 match decoded {
1430 Capability::LongLivedGracefulRestart(fams) => {
1431 assert_eq!(fams.len(), 2);
1432 assert_eq!(fams[0].afi, Afi::Ipv4);
1433 assert_eq!(fams[0].safi, Safi::Unicast);
1434 assert!(fams[0].forwarding_preserved);
1435 assert_eq!(fams[0].stale_time, 86400);
1436 assert_eq!(fams[1].afi, Afi::Ipv6);
1437 assert_eq!(fams[1].safi, Safi::Unicast);
1438 assert!(!fams[1].forwarding_preserved);
1439 assert_eq!(fams[1].stale_time, 3600);
1440 }
1441 other => panic!("expected LongLivedGracefulRestart, got {other:?}"),
1442 }
1443 }
1444
1445 #[test]
1446 fn llgr_capability_max_stale_time() {
1447 let cap = Capability::LongLivedGracefulRestart(vec![LlgrFamily {
1448 afi: Afi::Ipv4,
1449 safi: Safi::Unicast,
1450 forwarding_preserved: false,
1451 stale_time: 0x00FF_FFFF, }]);
1453
1454 let mut buf = bytes::BytesMut::new();
1455 cap.encode(&mut buf).unwrap();
1456 let mut frozen = buf.freeze();
1457 let decoded = Capability::decode(&mut frozen).unwrap();
1458
1459 match decoded {
1460 Capability::LongLivedGracefulRestart(fams) => {
1461 assert_eq!(fams[0].stale_time, 0x00FF_FFFF);
1462 }
1463 other => panic!("expected LongLivedGracefulRestart, got {other:?}"),
1464 }
1465 }
1466
1467 #[test]
1468 fn llgr_capability_empty() {
1469 let cap = Capability::LongLivedGracefulRestart(vec![]);
1470 let mut buf = bytes::BytesMut::new();
1471 cap.encode(&mut buf).unwrap();
1472 let mut frozen = buf.freeze();
1473 let decoded = Capability::decode(&mut frozen).unwrap();
1474 assert!(matches!(
1475 decoded,
1476 Capability::LongLivedGracefulRestart(fams) if fams.is_empty()
1477 ));
1478 }
1479
1480 #[test]
1483 fn bgp_role_capability_encode_decode_roundtrip() {
1484 for role in [
1485 BgpRole::Provider,
1486 BgpRole::RouteServer,
1487 BgpRole::RouteServerClient,
1488 BgpRole::Customer,
1489 BgpRole::Peer,
1490 ] {
1491 let original = Capability::Role { role };
1492 let mut buf = bytes::BytesMut::new();
1493 original.encode(&mut buf).unwrap();
1494 assert_eq!(buf.as_ref(), &[9, 1, role.to_u8()][..]);
1496 let mut frozen = buf.freeze();
1497 let decoded = Capability::decode(&mut frozen).unwrap();
1498 assert_eq!(decoded, original);
1499 }
1500 }
1501
1502 #[test]
1503 fn bgp_role_capability_code_returns_nine() {
1504 assert_eq!(
1505 Capability::Role {
1506 role: BgpRole::Provider
1507 }
1508 .code(),
1509 9
1510 );
1511 }
1512
1513 #[test]
1514 fn bgp_role_capability_encoded_len_is_three() {
1515 assert_eq!(
1517 Capability::Role {
1518 role: BgpRole::Customer
1519 }
1520 .encoded_len(),
1521 3
1522 );
1523 }
1524
1525 #[test]
1526 fn bgp_role_capability_bad_length_stored_as_unknown() {
1527 for (len, payload) in [
1530 (0u8, &[][..]),
1531 (2u8, &[0x00, 0x00][..]),
1532 (3u8, &[0x00, 0x00, 0x03][..]),
1533 ] {
1534 let mut wire = vec![9, len];
1535 wire.extend_from_slice(payload);
1536 let mut buf = Bytes::copy_from_slice(&wire);
1537 let cap = Capability::decode(&mut buf).unwrap();
1538 assert!(
1539 matches!(cap, Capability::Unknown { code: 9, .. }),
1540 "len {len}: expected Unknown, got {cap:?}"
1541 );
1542 }
1543 }
1544
1545 #[test]
1546 fn bgp_role_capability_invalid_role_byte_stored_as_unknown() {
1547 for invalid in [5u8, 99u8, 200u8, 255u8] {
1550 let wire = [9u8, 1, invalid];
1551 let mut buf = Bytes::copy_from_slice(&wire);
1552 let cap = Capability::decode(&mut buf).unwrap();
1553 match cap {
1554 Capability::Unknown { code, data } => {
1555 assert_eq!(code, 9);
1556 assert_eq!(data.as_ref(), &[invalid][..]);
1557 }
1558 other => panic!("invalid role byte {invalid}: expected Unknown, got {other:?}"),
1559 }
1560 }
1561 }
1562
1563 #[test]
1564 fn bgp_role_from_u8_roundtrip() {
1565 for role in [
1566 BgpRole::Provider,
1567 BgpRole::RouteServer,
1568 BgpRole::RouteServerClient,
1569 BgpRole::Customer,
1570 BgpRole::Peer,
1571 ] {
1572 assert_eq!(BgpRole::from_u8(role.to_u8()), Some(role));
1573 }
1574 for invalid in [5u8, 9, 99, 255] {
1575 assert_eq!(BgpRole::from_u8(invalid), None);
1576 }
1577 }
1578}