1use std::collections::BTreeMap;
2use std::fmt::{self, Display};
3use std::net::Ipv4Addr;
4
5use log::{debug, warn};
6use octseq::{Octets, OctetsBuilder, OctetsFrom, Parser};
7
8use inetnum::asn::Asn;
9use crate::bgp::message::{
10 PduParseInfo,
11 UpdateMessage,
12 update_builder::ComposeError,
13};
14use crate::bgp::message::update_builder::{
15 MpReachNlriBuilder,
16 MpUnreachNlriBuilder,
17 StandardCommunitiesList
18};
19use crate::bgp::communities::StandardCommunity;
20use crate::bgp::nlri::afisafi::{AfiSafiType, NlriCompose};
21use crate::bgp::types::NextHop;
22use crate::util::parser::{ParseError, parse_ipv4addr};
23
24
25#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
26#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
27#[cfg_attr(feature = "serde", derive(serde::Serialize))]
28pub struct Flags(u8);
29
30impl core::ops::BitOr<u8> for Flags {
31 type Output = Self;
32
33 fn bitor(self, rhs: u8) -> Self::Output {
34 Self(self.0 | rhs)
35 }
36}
37
38impl core::ops::BitOr for Flags {
39 type Output = Self;
40
41 fn bitor(self, rhs: Self) -> Self::Output {
42 Self(self.0 | rhs.0)
43 }
44}
45
46impl Flags {
47 pub const OPT_NON_TRANS: u8 = 0b1000_0000;
55 pub const OPT_TRANS: u8 = 0b1100_0000;
56 pub const WELLKNOWN: u8 = 0b0100_0000;
57
58 const EXTENDED_LEN: u8 = 0b0001_0000;
59 #[allow(dead_code)]
60 const PARTIAL: u8 = 0b0010_0000;
61
62 pub fn is_optional(self) -> bool {
64 self.0 & 0x80 == 0x80
65 }
66
67 pub fn is_transitive(self) -> bool {
69 self.0 & 0x40 == 0x40
70 }
71
72 pub fn is_partial(self) -> bool {
74 self.0 & 0x20 == 0x20
75 }
76
77 pub fn is_extended_length(self) -> bool {
79 self.0 & 0x10 == 0x10
80 }
81
82}
83
84impl From<u8> for Flags {
85 fn from(u: u8) -> Flags {
86 Flags(u)
87 }
88}
89
90impl From<Flags> for u8 {
91 fn from(f: Flags) -> u8 {
92 f.0
93 }
94}
95
96
97pub trait AttributeHeader {
98 const FLAGS: u8;
99 const TYPE_CODE: u8;
100}
101
102
103#[derive(Clone, Debug, Eq, PartialEq)]
108#[cfg_attr(feature = "serde", derive(serde::Serialize))]
109pub struct OwnedPathAttributes {
110 ppi: PduParseInfo,
111 raw: Vec<u8>
112}
113
114impl OwnedPathAttributes {
115 pub fn new(ppi: PduParseInfo, raw: Vec<u8>) -> Self {
117 Self { ppi, raw }
118 }
119
120 pub fn iter(&self) -> PathAttributes<'_, Vec<u8>> {
122 let parser = Parser::from_ref(&self.raw);
123 PathAttributes::new(parser, self.ppi)
124 }
125
126 pub fn pdu_parse_info(&self) -> PduParseInfo {
128 self.ppi
129 }
130
131 pub fn into_vec(self) -> Vec<u8> {
133 self.raw
134 }
135
136 pub fn get<A: FromAttribute>(&self) -> Option<A> {
138 if let Some(attr_type) = A::attribute_type() {
139 self.iter().get(attr_type)
140 .and_then(|a| a.to_owned().ok())
141 .and_then(|a| A::from_attribute(a))
142 } else {
143 None
144 }
145 }
146}
147
148impl<'a, O> From<PathAttributes<'a, O>> for OwnedPathAttributes
149where
150 O: AsRef<[u8]>
151{
152 fn from(value: PathAttributes<'a, O>) -> Self {
153 OwnedPathAttributes {
154 ppi: value.pdu_parse_info,
155 raw: value.parser.peek_all().to_owned()
156 }
157 }
158}
159
160impl From<(PduParseInfo, Vec<u8>)> for OwnedPathAttributes {
161 fn from(value: (PduParseInfo, Vec<u8>)) -> Self {
162 Self::new(value.0, value.1)
163 }
164}
165
166impl AsRef<[u8]> for OwnedPathAttributes {
167 fn as_ref(&self) -> &[u8] {
168 &self.raw
169 }
170}
171
172pub type AttributesMap = BTreeMap<u8, PathAttribute>;
175
176#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
177#[cfg_attr(feature = "serde", derive(serde::Serialize))]
178pub struct PaMap {
179 attributes: AttributesMap,
180}
181
182impl PaMap {
183 pub fn empty() -> Self {
184 Self {
185 attributes: BTreeMap::new()
186 }
187 }
188
189 pub fn from_update_pdu<'a, Octs: Octets>(pdu: &'a UpdateMessage<Octs>)
192 -> Result<Self, ComposeError>
193 where
194 Vec<u8>: OctetsFrom<Octs::Range<'a>>
195 {
196 let mut pa_map = Self::empty();
197 for pa in pdu.path_attributes()? {
198 if let Ok(pa) = pa {
199 if pa.type_code() != MpUnreachNlriBuilder::<()>::TYPE_CODE {
200 if let PathAttributeType::Invalid(n) = pa.type_code().into() {
201 warn!("invalid PA {}:\n{}", n, pdu.fmt_pcap_string());
202 }
203 pa_map.attributes_mut().insert(pa.type_code(), pa.to_owned()?);
204 }
205 } else {
206 return Err(ComposeError::InvalidAttribute);
207 }
208 }
209 Ok(pa_map)
210 }
211
212 pub fn remove_non_transitives(&mut self) {
213 self.attributes.retain(|_tc, pa| pa.default_flags().is_transitive());
214 }
215
216 pub fn set<A: FromAttribute + Into<PathAttribute>>(
217 &mut self, attr: A
218 ) -> Option<A> {
219 let attr = attr.into();
220 self.attributes.insert(attr.type_code(), attr).map(A::from_attribute)?
221 }
222
223 pub fn set_from_enum(
224 &mut self, attr: PathAttribute
225 ) -> Option<PathAttribute> {
226 match attr {
227 PathAttribute::Origin(a) => self.set(a).map(Into::into),
228 PathAttribute::AsPath(a) => self.set(a).map(Into::into),
229 PathAttribute::ConventionalNextHop(a) => self.set(a).map(Into::into),
230 PathAttribute::MultiExitDisc(a) => self.set(a).map(Into::into),
231 PathAttribute::LocalPref(a) => self.set(a).map(Into::into),
232 PathAttribute::AtomicAggregate(a) => self.set(a).map(Into::into),
233 PathAttribute::Aggregator(a) => self.set(a).map(Into::into),
234 PathAttribute::StandardCommunities(a) => self.set(a).map(Into::into),
235 PathAttribute::OriginatorId(a) => self.set(a).map(Into::into),
236 PathAttribute::ClusterList(a) => self.set(a).map(Into::into),
237 PathAttribute::MpReachNlri(a) => self.set(a).map(Into::into),
238 PathAttribute::ExtendedCommunities(a) => self.set(a).map(Into::into),
239 PathAttribute::As4Path(a) => self.set(a).map(Into::into),
240 PathAttribute::As4Aggregator(a) => self.set(a).map(Into::into),
241 PathAttribute::Connector(a) => self.set(a).map(Into::into),
242 PathAttribute::AsPathLimit(a) => self.set(a).map(Into::into),
243 PathAttribute::Ipv6ExtendedCommunities(a) => self.set(a).map(Into::into),
244 PathAttribute::LargeCommunities(a) => self.set(a).map(Into::into),
245 PathAttribute::Otc(a) => self.set(a).map(Into::into),
246 PathAttribute::AttrSet(a) => self.set(a).map(Into::into),
247 PathAttribute::Reserved(a) => self.set(a).map(Into::into),
248 PathAttribute::Unimplemented(_u) => None, PathAttribute::Invalid(_flags, _tc, _v) => None, }
251 }
252
253 pub fn get<A: FromAttribute>(
254 &self,
255 ) -> Option<A> {
256 if let Some(attr_type) = A::attribute_type() {
257 self.attributes
258 .get(&attr_type.into()).and_then(|a| A::from_attribute(a.clone()))
259 } else {
260 None
261 }
262 }
263
264 pub fn get_by_type_code(&self, type_code: u8) -> Option<&PathAttribute> {
265 self.attributes.get(&type_code)
266 }
267
268 pub fn get_mut_by_type_code(&mut self, type_code: u8) -> Option<&mut PathAttribute> {
269 self.attributes.get_mut(&type_code)
270 }
271
272 pub fn add_attribute(
273 &mut self,
274 attr: PathAttribute,
275 ) -> Result<Option<PathAttribute>, ComposeError> {
276 if let PathAttribute::Invalid(..) = attr {
277 warn!(
278 "adding Invalid attribute to UpdateBuilder: {}",
279 &attr.type_code()
280 );
281 }
282
283 let replaced = self.attributes_mut().insert(attr.type_code(),attr);
284 Ok(replaced)
285 }
286
287 pub fn attributes(&self) -> &AttributesMap {
288 &self.attributes
289 }
290
291 pub fn attributes_mut(&mut self) -> &mut AttributesMap {
292 &mut self.attributes
293 }
294
295 pub fn into_attributes(self) -> AttributesMap {
296 self.attributes
297 }
298
299 pub fn remove<A: FromAttribute>(&mut self) -> Option<A>
300 {
301 if let Some(attr_type) = A::attribute_type() {
302 self.attributes.remove(&attr_type.into()).and_then(|a| A::from_attribute(a))
303 } else {
304 None
305 }
306 }
307
308 pub fn merge_upsert(&mut self, other: &mut Self) {
309 self.attributes_mut().append(other.attributes_mut())
310 }
311
312 pub(in crate::bgp) fn take<A: FromAttribute>(&mut self) -> Option<A> {
313 self.remove::<A>()
322 }
323
324 pub(in crate::bgp) fn contains<A: FromAttribute>(&self) -> bool {
325 if let Some(attr_type) = A::attribute_type() {
326 self.attributes().contains_key(&attr_type.into())
327 } else {
328 false
329 }
330 }
331
332 pub fn len(&self) -> usize { self.attributes().len() }
333
334 pub fn is_empty(&self) -> bool { self.attributes().is_empty() }
335
336 pub fn bytes_len(&self) -> usize {
338 self.attributes.values()
339 .filter(|pa| pa.type_code() != MpReachNextHop::TYPE_CODE)
340 .fold(0, |sum, a| sum + a.compose_len())
341 }
342}
343
344#[cfg(feature = "arbitrary")]
348impl arbitrary::Arbitrary<'_> for PaMap {
349 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
350 let num = u.arbitrary_len::<Self>()?;
351 let mut res = PaMap::empty();
352 for _ in 0..num {
353 let pa = PathAttribute::arbitrary(u)?;
355 res.set_from_enum(pa);
356 }
357 Ok(res)
358 }
359}
360
361pub trait FromAttribute {
362 fn from_attribute(_value: PathAttribute) -> Option<Self>
363 where
364 Self: Sized {
365 None
366 }
367
368 fn attribute_type() -> Option<PathAttributeType> {
369 None
370 }
371
372}
373
374impl From<AttributesMap> for PaMap {
375 fn from(attributes: AttributesMap) -> Self {
376 Self { attributes }
377 }
378}
379
380
381macro_rules! path_attributes {
382 (
383 $(
384 $type_code:expr => $name:ident($data:ty), $flags:expr
385 ),+ $(,)*
386 ) => {
387
388#[derive(Clone, Debug, Eq, Hash, PartialEq)]
391 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
392 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
393 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
394 pub enum PathAttribute {
395 $( $name($data) ),+,
396 Unimplemented(UnimplementedPathAttribute),
397 Invalid(Flags, u8, Vec<u8>),
398 }
399
400 impl PathAttribute {
401 pub fn compose<Target: OctetsBuilder>(
402 &self,
403 target: &mut Target
404 ) -> Result<(), Target::AppendError> {
405
406 match self {
407 $(
408 PathAttribute::$name(i) => {
409 i.compose(target)
410 }
411 ),+
412 PathAttribute::Unimplemented(u) => {
413 u.compose(target)
414 }
415 PathAttribute::Invalid(flags, tc, val) => {
416 debug!("composing invalid path attribute {tc}");
417 target.append_slice(&[flags.0 | Flags::PARTIAL, *tc])?;
418 if val.len() > 255 {
419 target.append_slice(&u16::try_from(val.len()).unwrap_or(u16::MAX).to_be_bytes())?;
420 } else {
421 target.append_slice(&u8::try_from(val.len()).unwrap_or(u8::MAX).to_be_bytes())?;
422 }
423 target.append_slice(&val)
424 }
425 }
426 }
427
428 pub fn compose_len(&self) -> usize {
429 match self {
430 $(
431 PathAttribute::$name(i) => i.compose_len()
432 ),+,
433 PathAttribute::Unimplemented(u) => u.compose_len(),
434 PathAttribute::Invalid(_, _, val) => if val.len() > 255 {
435 2 + 2 + val.len()
436 } else {
437 2 + 1 + val.len()
438
439 }
440 }
441 }
442
443 pub fn type_code(&self) -> u8 {
444 match self {
445 $(
446 PathAttribute::$name(_pa) =>
447 <$data>::TYPE_CODE
448 ),+,
449 PathAttribute::Unimplemented(u) => {
450 u.type_code()
451 }
452 PathAttribute::Invalid(_, tc, _) => {
453 *tc
454 }
455 }
456 }
457
458 pub fn default_flags(&self) -> Flags {
459 match self {
460 $(
461 PathAttribute::$name(_pa) =>
462 <$data>::FLAGS.into()
463 ),+,
464 PathAttribute::Unimplemented(u) => {
465 u.flags()
466 }
467 PathAttribute::Invalid(f, _, _) => {
468 *f
469 }
470 }
471 }
472 }
473
474 $(
475 impl From<$data> for PathAttribute {
476 fn from(value: $data) -> Self {
477 PathAttribute::$name(value)
478 }
479 }
480 )+
481
482
483#[derive(Debug)]
486 pub struct EncodedPathAttribute<'a, Octs: Octets> {
487 parser: Parser<'a, Octs>,
488 pdu_parse_info: PduParseInfo,
489 }
490 impl<'a, Octs: Octets> EncodedPathAttribute<'a, Octs> {
491 fn new(
492 parser: Parser<'a, Octs>,
493 ppi: PduParseInfo,
494 ) -> Self {
495 Self { parser, pdu_parse_info: ppi }
496 }
497
498 pub fn pdu_parse_info(&self) -> PduParseInfo {
499 self.pdu_parse_info
500 }
501
502 pub fn flags(&self) -> Flags {
503 self.parser.peek_all()[0].into()
504 }
505
506 pub fn type_code(&self) -> u8 {
507 self.parser.peek_all()[1]
508 }
509
510 pub fn length(&self) -> usize {
511 if self.flags().is_extended_length() {
512 let raw = self.parser.peek(4).unwrap();
513 u16::from_be_bytes([raw[2], raw[3]]).into()
514 } else {
515 self.parser.peek_all()[2].into()
516 }
517 }
518
519 pub fn value_into_parser(&self) -> Parser<'a, Octs> {
520 let mut res = self.parser;
521 if self.flags().is_extended_length() {
522 res.advance(4).unwrap();
523 } else {
524 res.advance(3).unwrap();
525 }
526 res
527 }
528
529 }
530
531 impl<'a, Octs: Octets> AsRef<[u8]> for EncodedPathAttribute<'a, Octs> {
532 fn as_ref(&self) -> &[u8] {
533 self.parser.peek_all()
534 }
535 }
536
537 #[derive(Debug)]
538 pub enum WireformatPathAttribute<'a, Octs: Octets> {
539 $( $name(EncodedPathAttribute<'a, Octs>) ),+,
540 Unimplemented(UnimplementedWireformat<'a, Octs>),
541 Invalid(Flags, u8, Parser<'a, Octs>),
542 }
543
544
545 impl<'a, Octs: Octets> WireformatPathAttribute<'a, Octs> {
546 fn parse(parser: &mut Parser<'a, Octs>, ppi: PduParseInfo)
547 -> Result<WireformatPathAttribute<'a, Octs>, ParseError>
548 {
549 let start_pos = parser.pos();
550 let flags = parser.parse_u8()?;
551 let type_code = parser.parse_u8()?;
552 let (header_len, len) = match flags & 0x10 == 0x10 {
553 true => (4, parser.parse_u16_be()? as usize),
554 false => (3, parser.parse_u8()? as usize),
555 };
556
557 let mut pp = parser.parse_parser(len)?;
558
559 let res = match type_code {
560 $(
561 $type_code => {
562 if let Err(e) = <$data>::validate(
563 flags.into(), &mut pp, ppi
564 ) {
565 debug!("failed to parse path attribute: {e}");
566 if $type_code == 14 {
567 return Err(ParseError::form_error(
568 "invalid MP_REACH_NLRI"
569 ))
570 } else if $type_code == 15 {
571 return Err(ParseError::form_error(
572 "invalid MP_UNREACH_NLRI"
573 ))
574 } else {
575 pp.seek(start_pos + header_len)?;
576 WireformatPathAttribute::Invalid(
577 $flags.into(), $type_code, pp
578 )
579 }
580 } else {
581 pp.seek(start_pos)?;
582 WireformatPathAttribute::$name(
583 EncodedPathAttribute::new(pp, ppi)
584 )
585 }
586 }
587 ),+
588 ,
589 _ => {
590 pp.seek(start_pos )?;
591 WireformatPathAttribute::Unimplemented(
592 UnimplementedWireformat::new(
593 flags.into(), type_code, pp
594 )
595 )
596 }
597 };
598
599 Ok(res)
600 }
601
602 pub fn to_owned(&self) -> Result<PathAttribute, ParseError>
606 where
607 Vec<u8>: OctetsFrom<Octs::Range<'a>>
608 {
609 match self {
610 $(
611 WireformatPathAttribute::$name(epa) => {
612 Ok(PathAttribute::$name(
613 <$data>::parse(
614 &mut epa.value_into_parser(),
615 epa.pdu_parse_info()
616 )?
617 ))
618 }
619 ),+,
620 WireformatPathAttribute::Unimplemented(u) => {
621 Ok(PathAttribute::Unimplemented(
622 UnimplementedPathAttribute::new(
623 u.flags(),
624 u.type_code(),
625 u.value().to_vec()
626 )
627 ))
628 },
629 WireformatPathAttribute::Invalid(f, tc, p) => {
630 Ok(PathAttribute::Invalid(
631 *f, *tc, p.peek_all().to_vec()
632 ))
633 }
634 }
635 }
636
637 pub fn type_code(&self) -> u8 {
638 match self {
639 $(
640 WireformatPathAttribute::$name(_) =>
641 $type_code
642 ),+,
643 WireformatPathAttribute::Unimplemented(u) => {
644 u.type_code()
645 }
646 WireformatPathAttribute::Invalid(_, tc, _) => {
647 *tc
648 }
649 }
650 }
651
652
653 pub fn flags(&self) -> Flags {
654 match self {
655 $( Self::$name(epa) => { epa.flags() }),+,
656 Self::Unimplemented(u) => u.flags,
657 Self::Invalid(f, _, _) => *f,
658 }
659 }
660
661 pub fn length(&self) -> usize {
663 match self {
664 $(
665 Self::$name(epa) => epa.length()
666 ),+,
667 Self::Unimplemented(u) => u.value.len(),
668 Self::Invalid(_, _, v) => v.remaining()
669 }
670 }
671 }
672
673 impl<'a, Octs: Octets> AsRef<[u8]> for WireformatPathAttribute<'a, Octs> {
674 fn as_ref(&self) -> &[u8] {
675 match self {
676 $(
677 WireformatPathAttribute::$name(epa) => {
678 epa.as_ref()
679 }
680 ),+,
681 WireformatPathAttribute::Unimplemented(u) => {
682 u.value()
683 }
684 WireformatPathAttribute::Invalid(_, _, pp) => {
685 pp.peek_all()
686 }
687
688 }
689 }
690 }
691
692
693#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
696 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
697 pub enum PathAttributeType {
698 $( $name ),+,
699 Unimplemented(u8),
700 Invalid(u8),
701 }
702
703 impl fmt::Display for PathAttributeType {
704 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
705 match self {
706 $(
707 PathAttributeType::$name => {
708 write!(f, stringify!($name))
709 }
710 )+
711 PathAttributeType::Unimplemented(tc) => {
712 write!(f, "Unimplemented-PA-{}", tc)
713 }
714 PathAttributeType::Invalid(tc) => {
715 write!(f, "Invalid-PA-{}", tc)
716 }
717 }
718 }
719 }
720
721 impl From<u8> for PathAttributeType {
722 fn from(code: u8) -> PathAttributeType {
723 match code {
724 $( $type_code => PathAttributeType::$name ),+,
725 u => PathAttributeType::Unimplemented(u)
726 }
727 }
728 }
729
730 impl From<PathAttributeType> for u8 {
731 fn from(pat: PathAttributeType) -> u8 {
732 match pat {
733 $( PathAttributeType::$name => $type_code ),+,
734 PathAttributeType::Unimplemented(i) => i,
735 PathAttributeType::Invalid(i) => i,
736 }
737 }
738 }
739
740 $(
741 impl AttributeHeader for $data {
742 const FLAGS: u8 = $flags;
743 const TYPE_CODE: u8 = $type_code;
744 }
745 )+
746
747 $(
756 impl FromAttribute for $data {
757 fn from_attribute(value: PathAttribute) -> Option<$data> {
758 if let PathAttribute::$name(pa) = value {
759 Some(pa)
760 } else {
761 None
762 }
763 }
764
765 fn attribute_type() -> Option<PathAttributeType> {
766 Some(PathAttributeType::$name)
767 }
768 }
769 )+
770 }
771}
772
773path_attributes!(
774 1 => Origin(crate::bgp::types::Origin), Flags::WELLKNOWN,
775 2 => AsPath(crate::bgp::aspath::HopPath), Flags::WELLKNOWN,
776 3 => ConventionalNextHop(crate::bgp::types::ConventionalNextHop), Flags::WELLKNOWN,
777 4 => MultiExitDisc(crate::bgp::types::MultiExitDisc), Flags::OPT_NON_TRANS,
778 5 => LocalPref(crate::bgp::types::LocalPref), Flags::WELLKNOWN,
779 6 => AtomicAggregate(crate::bgp::types::AtomicAggregate), Flags::WELLKNOWN,
780 7 => Aggregator(crate::bgp::path_attributes::AggregatorInfo), Flags::OPT_TRANS,
781 8 => StandardCommunities(crate::bgp::message::update_builder::StandardCommunitiesList), Flags::OPT_TRANS,
782 9 => OriginatorId(crate::bgp::types::OriginatorId), Flags::OPT_NON_TRANS,
783 10 => ClusterList(crate::bgp::path_attributes::ClusterIds), Flags::OPT_NON_TRANS,
784 14 => MpReachNlri(MpReachNextHop), Flags::OPT_NON_TRANS,
785 16 => ExtendedCommunities(crate::bgp::path_attributes::ExtendedCommunitiesList), Flags::OPT_TRANS,
787 17 => As4Path(crate::bgp::types::As4Path), Flags::OPT_TRANS,
788 18 => As4Aggregator(crate::bgp::types::As4Aggregator), Flags::OPT_TRANS,
789 20 => Connector(crate::bgp::types::Connector), Flags::OPT_TRANS,
790 21 => AsPathLimit(crate::bgp::path_attributes::AsPathLimitInfo), Flags::OPT_TRANS,
791 25 => Ipv6ExtendedCommunities(crate::bgp::path_attributes::Ipv6ExtendedCommunitiesList), Flags::OPT_TRANS,
793 32 => LargeCommunities(crate::bgp::path_attributes::LargeCommunitiesList), Flags::OPT_TRANS,
794 35 => Otc(crate::bgp::types::Otc), Flags::OPT_TRANS,
796 128 => AttrSet(crate::bgp::path_attributes::AttributeSet), Flags::OPT_TRANS,
799 255 => Reserved(crate::bgp::path_attributes::ReservedRaw), Flags::OPT_TRANS,
800);
801
802#[derive(Clone, Debug, Eq, Hash, PartialEq)]
816#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
817#[cfg_attr(feature = "serde", derive(serde::Serialize))]
818pub struct UnimplementedPathAttribute {
819 flags: Flags,
820 type_code: u8,
821 value: Vec<u8>,
822}
823
824impl UnimplementedPathAttribute {
825 pub fn new(flags: Flags, type_code: u8, value: Vec<u8>) -> Self {
826 Self { flags, type_code, value }
827 }
828
829 pub fn type_code(&self) -> u8 {
830 self.type_code
831 }
832
833 pub fn flags(&self) -> Flags {
834 self.flags
835 }
836
837 pub fn value(&self) -> &Vec<u8> {
838 &self.value
839 }
840
841 pub fn value_len(&self) -> usize {
842 self.value.len()
843 }
844
845 pub fn compose_len(&self) -> usize {
846 let value_len = self.value_len();
847 if value_len > 255 {
848 4 + value_len
849 } else {
850 3 + value_len
851 }
852 }
853}
854
855impl From<UnimplementedPathAttribute> for PathAttribute {
856 fn from(u: UnimplementedPathAttribute) -> PathAttribute {
857 PathAttribute::Unimplemented(u)
858 }
859}
860
861pub struct UnimplementedWireformat<'a, Octs: Octets> {
862 flags: Flags,
863 type_code: u8,
864 value: Parser<'a, Octs>,
865}
866
867impl<Octs: Octets> fmt::Debug for UnimplementedWireformat<'_, Octs> {
868 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
869 write!(f, "{:08b} {} {:02x?}",
870 u8::from(self.flags()), self.type_code(), self.value()
871 )
872 }
873}
874
875impl<'a, Octs: Octets> UnimplementedWireformat<'a, Octs> {
876 pub fn new(flags: Flags, type_code: u8, value: Parser<'a, Octs>) -> Self {
877 Self { flags, type_code, value }
878 }
879 pub fn type_code(&self) -> u8 {
880 self.type_code
881 }
882
883 pub fn flags(&self) -> Flags {
884 self.flags
885 }
886
887 pub fn value(&self) -> &[u8] {
888 if self.flags().is_extended_length() {
889 &self.value.peek_all()[4..]
890 } else {
891 &self.value.peek_all()[3..]
892 }
893 }
894}
895
896
897pub trait Attribute: AttributeHeader + Clone {
900 fn compose_len(&self) -> usize {
901 self.header_len() + self.value_len()
902 }
903
904 fn is_extended(&self) -> bool {
905 self.value_len() > 255
906 }
907
908 fn header_len(&self) -> usize {
909 if self.is_extended() {
910 4
911 } else {
912 3
913 }
914 }
915
916 fn value_len(&self) -> usize;
917
918 fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
919 -> Result<(), Target::AppendError>
920 {
921 self.compose_header(target)?;
922 self.compose_value(target)
923 }
924
925 fn compose_header<Target: OctetsBuilder>(&self, target: &mut Target)
926 -> Result<(), Target::AppendError>
927 {
928 if self.is_extended() {
929 target.append_slice(&[
930 Self::FLAGS | Flags::EXTENDED_LEN,
931 Self::TYPE_CODE,
932 ])?;
933 target.append_slice(
934 &u16::try_from(self.value_len()).unwrap_or(u16::MAX)
935 .to_be_bytes()
936 )
937 } else {
938 target.append_slice(&[
939 Self::FLAGS,
940 Self::TYPE_CODE,
941 u8::try_from(self.value_len()).unwrap_or(u8::MAX)
942 ])
943 }
944 }
945
946 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
947 -> Result<(), Target::AppendError>;
948
949 fn validate<Octs: Octets>(
950 flags: Flags,
951 parser: &mut Parser<'_, Octs>,
952 ppi: PduParseInfo
953 )
954 -> Result<(), ParseError>;
955
956 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, ppi: PduParseInfo)
957 -> Result<Self, ParseError>
958 where
959 Self: Sized,
960 Vec<u8>: OctetsFrom<Octs::Range<'a>>
961 ;
962
963}
964
965#[derive(Debug)]
968pub struct PathAttributes<'a, Octs> {
969 pub parser: Parser<'a, Octs>,
970 pub pdu_parse_info: PduParseInfo,
971}
972
973impl<Octs> Clone for PathAttributes<'_, Octs> {
974 fn clone(&self) -> Self {
975 *self
976 }
977}
978
979impl<Octs> Copy for PathAttributes<'_, Octs> { }
980
981impl<'a, Octs: Octets> PathAttributes<'a, Octs> {
982 pub fn new(parser: Parser<'_, Octs>, pdu_parse_info: PduParseInfo)
983 -> PathAttributes<'_, Octs>
984 {
985 PathAttributes { parser, pdu_parse_info }
986 }
987
988 pub fn get(&self, pat: PathAttributeType)
989 -> Option<WireformatPathAttribute<'a, Octs>>
990 {
991 let mut iter = *self;
992 iter.find(|pa|
993 pa.as_ref().is_ok_and(|pa| pa.type_code() == u8::from(pat))
994 ).map(|res| res.unwrap()) }
996}
997
998impl<'a, Octs: Octets> Iterator for PathAttributes<'a, Octs> {
999 type Item = Result<WireformatPathAttribute<'a, Octs>, ParseError>;
1000 fn next(&mut self) -> Option<Self::Item> {
1001 if self.parser.remaining() == 0 {
1002 return None;
1003 }
1004
1005 let res = WireformatPathAttribute::parse(
1006 &mut self.parser,
1007 self.pdu_parse_info
1008 );
1009 Some(res)
1010 }
1011}
1012
1013macro_rules! check_len_exact {
1014 ($p:expr, $len:expr, $name:expr) => {
1015 if $p.remaining() != $len {
1016 Err(ParseError::form_error(
1017 "wrong length for $name, expected $len "
1018 ))
1019 } else {
1020 Ok(())
1021 }
1022 }
1023}
1024
1025pub struct UncheckedPathAttributes<'a, Octs> {
1026 parser: Parser<'a, Octs>,
1027}
1028
1029impl<'a, Octs> UncheckedPathAttributes<'a, Octs> {
1030 pub fn from_parser(parser: Parser<'a, Octs>) -> Self {
1031 Self { parser }
1032 }
1033}
1034
1035impl<'a, Octs: Octets> Iterator for UncheckedPathAttributes<'a, Octs> {
1036 type Item = EncodedPathAttribute<'a, Octs>;
1037 fn next(&mut self) -> Option<Self::Item> {
1038 if self.parser.remaining() == 0 {
1039 return None
1040 }
1041 let pos = self.parser.pos();
1042 let flags = self.parser.parse_u8().ok()?;
1043 let _type_code = self.parser.parse_u8().ok()?;
1044 let (header_len, len) = match flags & 0x10 == 0x10 {
1045 true => (4, self.parser.parse_u16_be().ok()? as usize),
1046 false => (3, self.parser.parse_u8().ok()? as usize),
1047 };
1048
1049 let _ = self.parser.seek(pos);
1050 let pp = self.parser.parse_parser(header_len + len).ok()?;
1051 Some(EncodedPathAttribute::new(pp, PduParseInfo::default()))
1052 }
1053}
1054
1055
1056impl Attribute for crate::bgp::types::Origin {
1059 fn value_len(&self) -> usize { 1 }
1060
1061 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1062 -> Result<(), Target::AppendError>
1063 {
1064 target.append_slice(&[self.0.into()])
1065 }
1066
1067 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'_, Octs>, _ppi: PduParseInfo)
1068 -> Result<Self, ParseError>
1069 {
1070 Ok(Self(parser.parse_u8()?.into()))
1071 }
1072
1073 fn validate<Octs: Octets>(
1074 _flags: Flags,
1075 parser: &mut Parser<'_, Octs>,
1076 _pdu_parse_info: PduParseInfo
1077 ) -> Result<(), ParseError> {
1078 check_len_exact!(parser, 1, "ORIGIN")
1079 }
1080}
1081
1082impl Attribute for crate::bgp::aspath::HopPath {
1085 fn value_len(&self) -> usize {
1086 self.to_as_path::<Vec<u8>>().unwrap().into_inner().len()
1087 }
1088
1089 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1090 -> Result<(), Target::AppendError>
1091 {
1092 target.append_slice(
1093 self.to_as_path::<Vec<u8>>().unwrap().into_inner().as_ref()
1094 )
1095 }
1096
1097 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, ppi: PduParseInfo)
1098 -> Result<Self, ParseError>
1099 {
1100 let asp = crate::bgp::aspath::AsPath::new(
1102 parser.peek_all().to_vec(),
1103 ppi.four_octet_enabled()
1104 ).map_err(|_| ParseError::form_error("invalid AS_PATH"))?;
1105
1106 Ok(asp.to_hop_path())
1107 }
1108
1109 fn validate<Octs: Octets>(
1110 _flags: Flags,
1111 parser: &mut Parser<'_, Octs>,
1112 pdu_parse_info: PduParseInfo
1113 ) -> Result<(), ParseError> {
1114 let asn_size = if pdu_parse_info.four_octet_enabled() {
1115 4
1116 } else {
1117 2
1118 };
1119 while parser.remaining() > 0 {
1120 let segment_type = parser.parse_u8()?;
1121 if !(1..=4).contains(&segment_type) {
1122 return Err(ParseError::form_error(
1123 "illegal segment type in AS_PATH"
1124 ));
1125 }
1126 let len = usize::from(parser.parse_u8()?); parser.advance(len * asn_size)?; }
1129 Ok(())
1130 }
1131}
1132
1133impl Attribute for crate::bgp::types::ConventionalNextHop {
1136 fn value_len(&self) -> usize { 4 }
1137
1138 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1139 -> Result<(), Target::AppendError>
1140 {
1141 target.append_slice(&self.0.octets())
1142 }
1143
1144 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
1145 -> Result<Self, ParseError>
1146 {
1147 Ok(Self(parse_ipv4addr(parser)?))
1148 }
1149
1150 fn validate<Octs: Octets>(
1151 _flags: Flags,
1152 parser: &mut Parser<'_, Octs>,
1153 _pdu_parse_info: PduParseInfo
1154 ) -> Result<(), ParseError> {
1155 check_len_exact!(parser, 4, "NEXT_HOP")
1156 }
1157}
1158
1159impl Attribute for crate::bgp::types::MultiExitDisc {
1162 fn value_len(&self) -> usize { 4 }
1163
1164 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1165 -> Result<(), Target::AppendError>
1166 {
1167 target.append_slice(&self.0.to_be_bytes())
1168 }
1169
1170 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
1171 -> Result<Self, ParseError>
1172 {
1173 Ok(Self(parser.parse_u32_be()?))
1174 }
1175
1176 fn validate<Octs: Octets>(
1177 _flags: Flags,
1178 parser: &mut Parser<'_, Octs>,
1179 _pdu_parse_info: PduParseInfo
1180 ) -> Result<(), ParseError> {
1181 check_len_exact!(parser, 4, "MULTI_EXIT_DISC")
1182 }
1183}
1184
1185impl Attribute for crate::bgp::types::LocalPref {
1188 fn value_len(&self) -> usize { 4 }
1189
1190 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1191 -> Result<(), Target::AppendError>
1192 {
1193 target.append_slice(&self.0.to_be_bytes())
1194 }
1195
1196 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
1197 -> Result<Self, ParseError>
1198 {
1199 Ok(Self(parser.parse_u32_be()?))
1200 }
1201
1202 fn validate<Octs: Octets>(
1203 _flags: Flags,
1204 parser: &mut Parser<'_, Octs>,
1205 _pdu_parse_info: PduParseInfo
1206 ) -> Result<(), ParseError> {
1207 check_len_exact!(parser, 4, "LOCAL_PREF")
1208 }
1209}
1210
1211impl Attribute for crate::bgp::types::AtomicAggregate {
1214 fn value_len(&self) -> usize { 0 }
1215
1216 fn compose_value<Target: OctetsBuilder>(&self, _target: &mut Target)
1217 -> Result<(), Target::AppendError>
1218 {
1219 Ok(())
1220 }
1221
1222 fn parse<'a, Octs: 'a + Octets>(_parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
1223 -> Result<Self, ParseError>
1224 {
1225 Ok(Self)
1226 }
1227
1228 fn validate<Octs: Octets>(
1229 _flags: Flags,
1230 parser: &mut Parser<'_, Octs>,
1231 _pdu_parse_info: PduParseInfo
1232 ) -> Result<(), ParseError> {
1233 check_len_exact!(parser, 0, "ATOMIC_AGGREGATE")
1234 }
1235}
1236
1237impl Display for crate::bgp::types::AtomicAggregate {
1238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1239 write!(f, "ATOMIC_AGGREGATE")
1240 }
1241}
1242
1243#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1246#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1247#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1248pub struct AggregatorInfo {
1249 asn: Asn,
1250 address: Ipv4Addr,
1251}
1252
1253impl AggregatorInfo {
1254 pub fn new(asn: Asn, address: Ipv4Addr) -> AggregatorInfo {
1255 AggregatorInfo { asn, address }
1256 }
1257 pub fn asn(&self) -> Asn {
1258 self.asn
1259 }
1260 pub fn address(&self) -> Ipv4Addr {
1261 self.address
1262 }
1263}
1264
1265
1266impl Attribute for AggregatorInfo {
1267 fn value_len(&self) -> usize {
1272 8
1273 }
1274
1275 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1276 -> Result<(), Target::AppendError>
1277 {
1278 target.append_slice(&self.asn().to_raw())?;
1279 target.append_slice(&self.address().octets())
1280 }
1281
1282 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, ppi: PduParseInfo)
1283 -> Result<Self, ParseError>
1284 {
1285 let asn = if ppi.four_octet_enabled() {
1286 Asn::from_u32(parser.parse_u32_be()?)
1287 } else {
1288 Asn::from_u32(parser.parse_u16_be()?.into())
1289 };
1290
1291 let address = parse_ipv4addr(parser)?;
1292 Ok(Self::new(asn, address))
1293 }
1294
1295 fn validate<Octs: Octets>(
1296 _flags: Flags,
1297 parser: &mut Parser<'_, Octs>,
1298 pdu_parse_info: PduParseInfo
1299 ) -> Result<(), ParseError> {
1300 if pdu_parse_info.four_octet_enabled() {
1304 check_len_exact!(parser, 8, "AGGREGATOR")?;
1305 } else {
1306 check_len_exact!(parser, 6, "AGGREGATOR")?;
1307 }
1308 Ok(())
1309 }
1310}
1311
1312impl Display for AggregatorInfo {
1313 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1314 write!(f, "{}:{}", self.asn, self.address)
1315 }
1316}
1317
1318impl Attribute for crate::bgp::message::update_builder::StandardCommunitiesList {
1321 fn value_len(&self) -> usize {
1322 self.communities().len() * 4
1323 }
1324
1325 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1326 -> Result<(), Target::AppendError>
1327 {
1328 for c in self.communities() {
1329 target.append_slice(&c.to_raw())?;
1330 }
1331 Ok(())
1332 }
1333
1334 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
1335 -> Result<Self, ParseError>
1336 {
1337 let mut builder = StandardCommunitiesList::with_capacity(
1338 parser.remaining() / 4
1339 );
1340 while parser.remaining() > 0 {
1341 builder.add_community(parser.parse_u32_be()?.into());
1342 }
1343
1344 Ok(builder)
1345 }
1346
1347 fn validate<Octs: Octets>(
1348 _flags: Flags,
1349 parser: &mut Parser<'_, Octs>,
1350 _pdu_parse_info: PduParseInfo
1351 ) -> Result<(), ParseError> {
1352 if parser.remaining() % 4 != 0 {
1353 return Err(ParseError::form_error(
1354 "unexpected length for COMMUNITIES"
1355 ));
1356 }
1357 Ok(())
1358 }
1359}
1360
1361impl StandardCommunitiesList {
1362 pub fn fmap<T, F: Fn(&StandardCommunity) -> T>(self, fmap: F) -> Vec<T> {
1363 self.communities().iter().map(fmap).collect::<Vec<T>>()
1364 }
1365}
1366
1367
1368impl Attribute for crate::bgp::types::OriginatorId {
1371 fn value_len(&self) -> usize { 4 }
1372
1373 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1374 -> Result<(), Target::AppendError>
1375 {
1376 target.append_slice(&self.0.octets())
1377 }
1378
1379 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
1380 -> Result<Self, ParseError>
1381 {
1382 Ok(Self(parse_ipv4addr(parser)?))
1383 }
1384
1385 fn validate<Octs: Octets>(
1386 _flags: Flags,
1387 parser: &mut Parser<'_, Octs>,
1388 _pdu_parse_info: PduParseInfo
1389 ) -> Result<(), ParseError> {
1390 check_len_exact!(parser, 4, "ORIGINATOR_ID")
1391 }
1392}
1393
1394#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1397#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1398#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1399pub struct BgpIdentifier([u8; 4]);
1400
1401impl From<[u8; 4]> for BgpIdentifier {
1402 fn from(raw: [u8; 4]) -> BgpIdentifier {
1403 BgpIdentifier(raw)
1404 }
1405}
1406
1407impl From<BgpIdentifier> for [u8; 4] {
1408 fn from(bgp_id: BgpIdentifier) -> Self {
1409 bgp_id.0
1410 }
1411}
1412
1413#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1414#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1415#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1416pub struct ClusterIds {
1417 cluster_ids: Vec<BgpIdentifier>
1418}
1419
1420impl ClusterIds {
1421 fn new(cluster_ids: Vec<BgpIdentifier>) -> ClusterIds {
1422 ClusterIds {cluster_ids }
1423 }
1424
1425 pub fn cluster_ids(&self) -> &Vec<BgpIdentifier> {
1426 &self.cluster_ids
1427 }
1428
1429 #[allow(clippy::len_without_is_empty)]
1430 pub fn len(&self) -> usize {
1431 self.cluster_ids.len()
1432 }
1433}
1434
1435
1436impl Attribute for ClusterIds {
1437 fn value_len(&self) -> usize {
1438 self.cluster_ids.len() * 4
1439 }
1440
1441 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1442 -> Result<(), Target::AppendError>
1443 {
1444 for c in &self.cluster_ids {
1445 target.append_slice(&c.0)?;
1446 }
1447 Ok(())
1448 }
1449
1450 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
1451 -> Result<Self, ParseError>
1452 {
1453 let mut cluster_ids = Vec::with_capacity(parser.remaining() / 4);
1454 while parser.remaining() > 0 {
1455 cluster_ids.push(parser.parse_u32_be()?.to_be_bytes().into());
1456 }
1457 Ok(ClusterIds::new(cluster_ids))
1458 }
1459
1460 fn validate<Octs: Octets>(
1461 _flags: Flags,
1462 parser: &mut Parser<'_, Octs>,
1463 _pdu_parse_info: PduParseInfo
1464 ) -> Result<(), ParseError> {
1465 if parser.remaining() % 4 != 0 {
1466 return Err(ParseError::form_error(
1467 "unexpected length for CLUSTER_LIST"
1468 ));
1469 }
1470 Ok(())
1471 }
1472}
1473
1474#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1477#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1478#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1479#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
1480pub struct MpReachNextHop {
1481 next_hop: NextHop,
1482}
1483
1484impl Attribute for MpReachNextHop {
1485 fn value_len(&self) -> usize {
1486 todo!()
1487 }
1488
1489 fn compose_value<Target: OctetsBuilder>(&self, _target: &mut Target)
1490 -> Result<(), Target::AppendError> {
1491 todo!()
1492 }
1493
1494 fn validate<Octs: Octets>(
1495 _flags: Flags,
1496 parser: &mut Parser<'_, Octs>,
1497 _ppi: PduParseInfo
1498 )
1499 -> Result<(), ParseError> {
1500
1501 let afi = parser.parse_u16_be()?;
1502 let safi= parser.parse_u8()?;
1503 let afisafi = AfiSafiType::from((afi, safi));
1504 let _next_hop = crate::bgp::types::NextHop::parse(parser, afisafi)?;
1505 Ok(())
1506 }
1507
1508 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
1509 -> Result<Self, ParseError>
1510 where
1511 Self: Sized,
1512 Vec<u8>: OctetsFrom<Octs::Range<'a>>
1513 {
1514 let afi = parser.parse_u16_be()?;
1515 let safi= parser.parse_u8()?;
1516 let afisafi = AfiSafiType::from((afi, safi));
1517 let next_hop = crate::bgp::types::NextHop::parse(parser, afisafi)?;
1518 Ok(MpReachNextHop{next_hop})
1519 }
1520}
1521
1522
1523impl<A> AttributeHeader for MpReachNlriBuilder<A> {
1525 const FLAGS: u8 = Flags::OPT_NON_TRANS;
1526 const TYPE_CODE: u8 = 14;
1527}
1528impl<A> FromAttribute for MpReachNlriBuilder<A> {
1529 fn from_attribute(_value: PathAttribute) -> Option<MpReachNlriBuilder<A>> {
1530 None
1531 }
1532
1533 fn attribute_type() -> Option<PathAttributeType> {
1534 None
1535 }
1537}
1538
1539
1540impl<A: Clone + NlriCompose> Attribute for MpReachNlriBuilder<A> {
1541 fn value_len(&self) -> usize {
1542 self.value_len()
1543 }
1544
1545 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1546 -> Result<(), Target::AppendError>
1547 {
1548 self.compose_value(target)
1549 }
1550
1551 fn parse<'a, Octs: 'a + Octets>(
1552 _parser: &mut Parser<'a, Octs>,
1553 _ppi: PduParseInfo,
1555 ) -> Result<Self, ParseError>
1556 where
1557 Vec<u8>: OctetsFrom<Octs::Range<'a>>
1558 {
1559 todo!()
1560 }
1601
1602 fn validate<Octs: Octets>(
1603 _flags: Flags,
1604 parser: &mut Parser<'_, Octs>,
1605 _ppi: PduParseInfo
1606 ) -> Result<(), ParseError> {
1607 if parser.remaining() < 5 {
1611 return Err(ParseError::form_error(
1612 "length for MP_REACH_NLRI less than minimum"
1613 ))
1614 }
1615 Ok(())
1616
1617
1618 }
1683}
1684
1685
1686impl<A> AttributeHeader for MpUnreachNlriBuilder<A> {
1688 const FLAGS: u8 = Flags::OPT_NON_TRANS;
1689 const TYPE_CODE: u8 = 15;
1690}
1691
1692impl<A: Clone + NlriCompose> Attribute for MpUnreachNlriBuilder<A> {
1693 fn value_len(&self) -> usize {
1694 self.value_len()
1695 }
1696
1697 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1698 -> Result<(), Target::AppendError>
1699 {
1700 self.compose_value(target)
1701 }
1702
1703 fn parse<'a, Octs: 'a + Octets>(_parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
1704 -> Result<Self, ParseError>
1705 where
1706 Vec<u8>: OctetsFrom<Octs::Range<'a>>
1707 {
1708 todo!()
1709 }
1739
1740 fn validate<Octs: Octets>(
1741 _flags: Flags,
1742 parser: &mut Parser<'_, Octs>,
1743 _pdu_parse_info: PduParseInfo
1744 ) -> Result<(), ParseError> {
1745 if parser.remaining() < 3 {
1749 return Err(ParseError::form_error(
1750 "length for MP_UNREACH_NLRI less than minimum"
1751 ))
1752 }
1753 Ok(())
1754 }
1815}
1816
1817use crate::bgp::communities::ExtendedCommunity;
1820#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1821#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1822#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1823#[cfg_attr(feature = "serde", serde(transparent))]
1824pub struct ExtendedCommunitiesList {
1825 communities: Vec<ExtendedCommunity>
1826}
1827
1828impl ExtendedCommunitiesList {
1829 pub fn new(communities: Vec<ExtendedCommunity>)
1830 -> ExtendedCommunitiesList
1831 {
1832 ExtendedCommunitiesList {communities }
1833 }
1834
1835 pub fn communities(&self) -> &Vec<ExtendedCommunity> {
1836 &self.communities
1837 }
1838
1839 pub fn fmap<T, F: Fn(ExtendedCommunity) -> T>(self, fmap: F) -> Vec<T> {
1840 self.communities.into_iter().map(fmap).collect::<Vec<T>>()
1841 }
1842
1843 pub fn add_community(&mut self, comm: ExtendedCommunity) {
1844 self.communities.push(comm);
1845 }
1846}
1847
1848
1849impl Attribute for crate::bgp::path_attributes::ExtendedCommunitiesList {
1850 fn value_len(&self) -> usize {
1851 self.communities.len() * 8
1852 }
1853
1854 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1855 -> Result<(), Target::AppendError>
1856 {
1857 for c in &self.communities {
1858 target.append_slice(&c.to_raw())?;
1859 }
1860 Ok(())
1861 }
1862
1863 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
1864 -> Result<Self, ParseError>
1865 {
1866 let mut communities = Vec::with_capacity(parser.remaining() / 8);
1867 let mut buf = [0u8; 8];
1868 while parser.remaining() > 0 {
1869 parser.parse_buf(&mut buf)?;
1870 communities.push(buf.into());
1871 }
1872 Ok(Self::new(communities))
1873 }
1874
1875 fn validate<Octs: Octets>(
1876 _flags: Flags,
1877 parser: &mut Parser<'_, Octs>,
1878 _pdu_parse_info: PduParseInfo
1879 ) -> Result<(), ParseError> {
1880 if parser.remaining() % 8 != 0 {
1881 return Err(ParseError::form_error(
1882 "unexpected length for EXTENDED_COMMUNITIES"
1883 ));
1884 }
1885 Ok(())
1886 }
1887}
1888
1889impl Attribute for crate::bgp::types::As4Path {
1892 fn value_len(&self) -> usize {
1893 self.0.to_as_path::<Vec<u8>>().unwrap().into_inner().len()
1894 }
1895
1896 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1897 -> Result<(), Target::AppendError>
1898 {
1899 target.append_slice(
1900 self.0.to_as_path::<Vec<u8>>().unwrap().into_inner().as_ref()
1901 )
1902 }
1903
1904 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, ppi: PduParseInfo)
1905 -> Result<Self, ParseError>
1906 {
1907 let asp = crate::bgp::aspath::AsPath::new(
1909 parser.peek_all().to_vec(),
1910 ppi.four_octet_enabled()
1911 ).map_err(|_| ParseError::form_error("invalid AS4_PATH"))?;
1912 Ok(Self(asp.to_hop_path()))
1913 }
1914
1915 fn validate<Octs: Octets>(
1916 _flags: Flags,
1917 parser: &mut Parser<'_, Octs>,
1918 _pdu_parse_info: PduParseInfo
1919 ) -> Result<(), ParseError> {
1920 while parser.remaining() > 0 {
1921 let segment_type = parser.parse_u8()?;
1922 if !(1..=4).contains(&segment_type) {
1923 return Err(ParseError::form_error(
1924 "illegal segment type in AS4_PATH"
1925 ));
1926 }
1927 let len = usize::from(parser.parse_u8()?); parser.advance(len * 4)?; }
1930 Ok(())
1931 }
1932
1933}
1934
1935impl Attribute for crate::bgp::types::As4Aggregator {
1938 fn value_len(&self) -> usize { 8 }
1939
1940 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1941 -> Result<(), Target::AppendError>
1942 {
1943 target.append_slice(&self.0.asn().to_raw())?;
1944 target.append_slice(&self.0.address().octets())
1945 }
1946
1947 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
1948 -> Result<Self, ParseError>
1949 {
1950 let asn = Asn::from_u32(parser.parse_u32_be()?);
1951 let address = parse_ipv4addr(parser)?;
1952 Ok(Self(AggregatorInfo::new(asn, address)))
1953 }
1954
1955 fn validate<Octs: Octets>(
1956 _flags: Flags,
1957 parser: &mut Parser<'_, Octs>,
1958 _pdu_parse_info: PduParseInfo
1959 ) -> Result<(), ParseError> {
1960 check_len_exact!(parser, 8, "AS4_AGGREGATOR")
1961 }
1962}
1963
1964
1965impl Attribute for crate::bgp::types::Connector {
1968 fn value_len(&self) -> usize { 4 }
1969
1970 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
1971 -> Result<(), Target::AppendError>
1972 {
1973 target.append_slice(&self.0.octets())
1974 }
1975
1976 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
1977 -> Result<Self, ParseError>
1978 {
1979 Ok(Self(parse_ipv4addr(parser)?))
1980 }
1981
1982 fn validate<Octs: Octets>(
1983 _flags: Flags,
1984 parser: &mut Parser<'_, Octs>,
1985 _ppi: PduParseInfo
1986 )
1987 -> Result<(), ParseError>
1988 {
1989 check_len_exact!(parser, 4, "CONNECTOR")
1990 }
1991}
1992
1993#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1996#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1997#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1998pub struct AsPathLimitInfo {
1999 upper_bound: u8,
2000 attacher: Asn,
2001}
2002
2003impl AsPathLimitInfo {
2004 pub fn new(upper_bound: u8, attacher: Asn) -> AsPathLimitInfo {
2005 AsPathLimitInfo { upper_bound, attacher }
2006 }
2007}
2008
2009impl Attribute for AsPathLimitInfo {
2010 fn value_len(&self) -> usize { 5 }
2011
2012 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
2013 -> Result<(), Target::AppendError>
2014 {
2015 target.append_slice(&[self.upper_bound])?;
2016 target.append_slice(&self.attacher.to_raw())
2017 }
2018
2019 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
2020 -> Result<Self, ParseError>
2021 {
2022 let info = AsPathLimitInfo {
2023 upper_bound: parser.parse_u8()?,
2024 attacher: Asn::from_u32(parser.parse_u32_be()?)
2025 };
2026
2027 Ok(info)
2028 }
2029
2030 fn validate<Octs: Octets>(
2031 _flags: Flags,
2032 parser: &mut Parser<'_, Octs>,
2033 _ppi: PduParseInfo
2034 )
2035 -> Result<(), ParseError>
2036 {
2037 check_len_exact!(parser, 5, "AS_PATHLIMIT")
2038 }
2039}
2040
2041use crate::bgp::communities::Ipv6ExtendedCommunity;
2044#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
2045#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2046#[cfg_attr(feature = "serde", derive(serde::Serialize))]
2047#[cfg_attr(feature = "serde", serde(transparent))]
2048pub struct Ipv6ExtendedCommunitiesList {
2049 communities: Vec<Ipv6ExtendedCommunity>
2050}
2051
2052impl Ipv6ExtendedCommunitiesList {
2053 pub fn new(communities: Vec<Ipv6ExtendedCommunity>)
2054 -> Ipv6ExtendedCommunitiesList
2055 {
2056 Ipv6ExtendedCommunitiesList {communities }
2057 }
2058
2059 pub fn communities(&self) -> &Vec<Ipv6ExtendedCommunity> {
2060 &self.communities
2061 }
2062
2063 pub fn fmap<T, F: Fn(Ipv6ExtendedCommunity) -> T>(self, fmap: F) -> Vec<T> {
2064 self.communities.into_iter().map(fmap).collect::<Vec<T>>()
2065 }
2066
2067 pub fn add_community(&mut self, comm: Ipv6ExtendedCommunity) {
2068 self.communities.push(comm);
2069 }
2070}
2071
2072impl Attribute for Ipv6ExtendedCommunitiesList {
2073 fn value_len(&self) -> usize {
2074 self.communities.len() * 20
2075 }
2076
2077 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
2078 -> Result<(), Target::AppendError>
2079 {
2080 for c in &self.communities {
2081 target.append_slice(&c.to_raw())?;
2082 }
2083 Ok(())
2084 }
2085
2086 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
2087 -> Result<Self, ParseError>
2088 {
2089 let mut communities = Vec::with_capacity(parser.remaining() / 20);
2090 let mut buf = [0u8; 20];
2091 while parser.remaining() > 0 {
2092 parser.parse_buf(&mut buf)?;
2093 communities.push(buf.into());
2094 }
2095 Ok(Ipv6ExtendedCommunitiesList::new(communities))
2096 }
2097
2098 fn validate<Octs: Octets>(
2099 _flags: Flags,
2100 parser: &mut Parser<'_, Octs>,
2101 _pdu_parse_info: PduParseInfo
2102 ) -> Result<(), ParseError> {
2103 if parser.remaining() % 20 != 0 {
2104 return Err(ParseError::form_error(
2105 "unexpected length for IPV6_EXTENDED_COMMUNITIES"
2106 ));
2107 }
2108 Ok(())
2109 }
2110}
2111
2112use crate::bgp::communities::LargeCommunity;
2115
2116#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
2117#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2118#[cfg_attr(feature = "serde", derive(serde::Serialize))]
2119#[cfg_attr(feature = "serde", serde(transparent))]
2120pub struct LargeCommunitiesList {
2121 communities: Vec<LargeCommunity>
2122}
2123
2124impl LargeCommunitiesList {
2125 fn new(communities: Vec<LargeCommunity>)
2126 -> LargeCommunitiesList
2127 {
2128 LargeCommunitiesList {communities }
2129 }
2130
2131 pub fn communities(&self) -> &Vec<LargeCommunity> {
2132 &self.communities
2133 }
2134
2135 pub fn fmap<T, F: Fn(LargeCommunity) -> T>(self, fmap: F) -> Vec<T> {
2136 self.communities.into_iter().map(fmap).collect::<Vec<T>>()
2137 }
2138
2139 pub fn add_community(&mut self, comm: LargeCommunity) {
2140 self.communities.push(comm)
2141 }
2142}
2143
2144
2145impl Attribute for LargeCommunitiesList {
2146 fn value_len(&self) -> usize {
2147 self.communities.len() * 12
2148 }
2149
2150 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
2151 -> Result<(), Target::AppendError>
2152 {
2153 for c in &self.communities {
2154 target.append_slice(&c.to_raw())?;
2155 }
2156 Ok(())
2157 }
2158
2159 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
2160 -> Result<Self, ParseError>
2161 {
2162 let mut communities = Vec::with_capacity(parser.remaining() / 12);
2163 let mut buf = [0u8; 12];
2164 while parser.remaining() > 0 {
2165 parser.parse_buf(&mut buf)?;
2166 communities.push(buf.into());
2167 }
2168 Ok(Self::new(communities))
2169 }
2170
2171 fn validate<Octs: Octets>(
2172 _flags: Flags,
2173 parser: &mut Parser<'_, Octs>,
2174 _pdu_parse_info: PduParseInfo
2175 ) -> Result<(), ParseError> {
2176 if parser.remaining() % 12 != 0 {
2177 return Err(ParseError::form_error(
2178 "unexpected length for LARGE_COMMUNITIES"
2179 ));
2180 }
2181 Ok(())
2182 }
2183}
2184
2185impl Attribute for crate::bgp::types::Otc {
2188 fn value_len(&self) -> usize { 4 }
2189
2190 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
2191 -> Result<(), Target::AppendError>
2192 {
2193 target.append_slice(&self.0.to_raw())
2194 }
2195
2196 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
2197 -> Result<Self, ParseError>
2198 {
2199 Ok(Self(Asn::from_u32(parser.parse_u32_be()?)))
2200 }
2201
2202 fn validate<Octs: Octets>(
2203 _flags: Flags,
2204 parser: &mut Parser<'_, Octs>,
2205 _ppi: PduParseInfo
2206 )
2207 -> Result<(), ParseError>
2208 {
2209 check_len_exact!(parser, 4, "OTC")
2210 }
2211}
2212
2213#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
2216#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2217#[cfg_attr(feature = "serde", derive(serde::Serialize))]
2218pub struct AttributeSet {
2219 origin: Asn,
2220 attributes: Vec<u8>,
2221}
2222
2223impl AttributeSet {
2224 pub fn new(origin: Asn, attributes: Vec<u8>) -> AttributeSet {
2225 AttributeSet { origin, attributes }
2226 }
2227}
2228
2229impl Attribute for AttributeSet {
2230 fn value_len(&self) -> usize {
2231 4 + self.attributes.len()
2232 }
2233
2234 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
2235 -> Result<(), Target::AppendError>
2236 {
2237 target.append_slice(&self.origin.to_raw())?;
2238 target.append_slice(&self.attributes)
2239 }
2240
2241 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
2242 -> Result<Self, ParseError>
2243 {
2244 let origin = Asn::from_u32(parser.parse_u32_be()?);
2245 let attributes = parser.peek_all().to_vec();
2246 Ok(Self::new(origin, attributes))
2247 }
2248
2249 fn validate<Octs: Octets>(
2250 _flags: Flags,
2251 parser: &mut Parser<'_, Octs>,
2252 _ppi: PduParseInfo
2253 )
2254 -> Result<(), ParseError>
2255 {
2256 if parser.remaining() < 4 {
2260 return Err(ParseError::form_error(
2261 "length for ATTR_SET less than minimum"
2262 ))
2263 }
2264 Ok(())
2265 }
2266}
2267
2268#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
2271#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2272#[cfg_attr(feature = "serde", derive(serde::Serialize))]
2273pub struct ReservedRaw {
2274 raw: Vec<u8>,
2275}
2276
2277impl ReservedRaw {
2278 pub fn new(raw: Vec<u8>) -> ReservedRaw {
2279 ReservedRaw { raw }
2280 }
2281}
2282
2283impl Attribute for ReservedRaw {
2284 fn value_len(&self) -> usize {
2285 self.raw.len()
2286 }
2287
2288 fn compose_value<Target: OctetsBuilder>(&self, target: &mut Target)
2289 -> Result<(), Target::AppendError>
2290 {
2291 target.append_slice(&self.raw)
2292 }
2293
2294 fn parse<'a, Octs: 'a + Octets>(parser: &mut Parser<'a, Octs>, _ppi: PduParseInfo)
2295 -> Result<Self, ParseError>
2296 {
2297 let raw = parser.peek_all().to_vec();
2298 Ok(Self::new(raw))
2299 }
2300
2301 fn validate<Octs: Octets>(
2302 _flags: Flags,
2303 _parser: &mut Parser<'_, Octs>,
2304 _ppi: PduParseInfo
2305 )
2306 -> Result<(), ParseError>
2307 {
2308 Ok(())
2310 }
2311}
2312
2313
2314impl UnimplementedPathAttribute {
2324 fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
2325 -> Result<(), Target::AppendError>
2326 {
2327 let len = self.value().len();
2328 let flags = self.flags() | Flags::PARTIAL;
2330 target.append_slice(
2331 &[flags.into(), self.type_code()]
2332 )?;
2333 if flags.is_extended_length() {
2334 target.append_slice(
2335 &u16::try_from(len).unwrap_or(u16::MAX)
2336 .to_be_bytes()
2337 )?;
2338 } else {
2339 target.append_slice(&[
2340 u8::try_from(len).unwrap_or(u8::MAX)
2341 ])?;
2342 }
2343 target.append_slice(self.value())
2344 }
2345}
2346
2347
2348#[cfg(test)]
2351mod tests {
2352
2353 use super::*;
2354
2355 use inetnum::asn::Asn;
2356 use crate::bgp::communities::Wellknown;
2357 use crate::bgp::aspath::HopPath;
2358 use crate::bgp::types::OriginType;
2359
2360 #[test]
2361 fn wireformat_to_owned_and_back() {
2362 use super::PathAttribute as PA;
2363 fn check(raw: Vec<u8>, owned: PathAttribute) {
2364 let mut parser = Parser::from_ref(&raw);
2365 let sc = PduParseInfo::modern();
2366 let pa = WireformatPathAttribute::parse(&mut parser, sc)
2367 .unwrap();
2368 assert_eq!(owned, pa.to_owned().unwrap());
2369 let mut target = Vec::new();
2370 owned.compose(&mut target).unwrap();
2371 assert_eq!(target, raw);
2372 }
2373
2374 check(vec![0x40, 0x01, 0x01, 0x00], PA::Origin(OriginType::Igp.into()));
2375
2376 check(
2377 vec![0x40, 0x02, 10,
2378 0x02, 0x02, 0x00, 0x00, 0x00, 100,
2380 0x00, 0x00, 0x00, 200,
2381 ],
2382 PA::AsPath(HopPath::from(vec![
2383 Asn::from_u32(100),
2384 Asn::from_u32(200)]
2385 ))
2386 );
2387
2388 check(
2389 vec![0x40, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04],
2390 PA::ConventionalNextHop(crate::bgp::types::ConventionalNextHop("1.2.3.4".parse().unwrap()))
2391 );
2392
2393 check(
2394 vec![0x80, 0x04, 0x04, 0x00, 0x00, 0x00, 0xff],
2395 PA::MultiExitDisc(crate::bgp::types::MultiExitDisc(255))
2396 );
2397
2398 check(
2399 vec![0x40, 0x05, 0x04, 0x00, 0x00, 0x00, 0x0a],
2400 PA::LocalPref(crate::bgp::types::LocalPref(10))
2401 );
2402
2403 check(
2404 vec![0x40, 0x06, 0x00],
2405 PA::AtomicAggregate(crate::bgp::types::AtomicAggregate)
2406 );
2407
2408 check(
2409 vec![
2410 0xc0, 0x07, 0x08, 0x00, 0x00, 0x00, 0x65, 0xc6,
2411 0x33, 0x64, 0x01
2412 ],
2413 PA::Aggregator(AggregatorInfo::new(
2414 Asn::from_u32(101),
2415 "198.51.100.1".parse().unwrap()
2416 ))
2417 );
2418
2419 check(
2420 vec![
2421 0xc0, 0x08, 0x10, 0x00, 0x2a, 0x02, 0x06, 0xff,
2422 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x02, 0xff,
2423 0xff, 0xff, 0x03
2424 ],
2425 {
2426 let mut builder = StandardCommunitiesList::new();
2427 builder.add_community("AS42:518".parse().unwrap());
2428 builder.add_community(Wellknown::NoExport.into());
2429 builder.add_community(Wellknown::NoAdvertise.into());
2430 builder.add_community(Wellknown::NoExportSubconfed.into());
2431 PA::StandardCommunities(builder)
2432 }
2433 );
2434
2435 check(
2436 vec![0x80, 0x09, 0x04, 0x0a, 0x00, 0x00, 0x04],
2437 crate::bgp::types::OriginatorId("10.0.0.4".parse().unwrap()).into()
2438 );
2439
2440 check(
2441 vec![0x80, 0x0a, 0x04, 0x0a, 0x00, 0x00, 0x03],
2442 ClusterIds::new(vec![[10, 0, 0, 3].into()]).into()
2443 );
2444
2445 check(
2505 vec![
2506 0xc0, 0x10, 0x08, 0x00, 0x02, 0xfc, 0x85, 0x00,
2507 0x00, 0xcf, 0x08
2508 ],
2509 ExtendedCommunitiesList::new(vec![
2510 "rt:64645:53000".parse().unwrap()
2511 ]).into()
2512 );
2513
2514 check(
2515 vec![
2516 0xc0, 0x11, 10,
2517 0x02, 0x02, 0x00, 0x00, 0x00, 100,
2519 0x00, 0x00, 0x00, 200,
2520 ],
2521 PA::As4Path(crate::bgp::types::As4Path(HopPath::from(vec![
2522 Asn::from_u32(100),
2523 Asn::from_u32(200)]
2524 )))
2525 );
2526
2527 check(
2528 vec![
2529 0xc0, 0x12, 0x08, 0x00, 0x00, 0x04, 0xd2,
2530 10, 0, 0, 99
2531 ],
2532 crate::bgp::types::As4Aggregator(AggregatorInfo::new(
2533 Asn::from_u32(1234),
2534 "10.0.0.99".parse().unwrap()
2535 )).into()
2536 );
2537
2538 check(
2539 vec![0xc0, 0x14, 0x04, 1, 2, 3, 4],
2540 crate::bgp::types::Connector("1.2.3.4".parse().unwrap()).into()
2541 );
2542
2543 check(
2544 vec![0xc0, 0x15, 0x05, 0x14, 0x00, 0x00, 0x04, 0xd2],
2545 AsPathLimitInfo::new(20, Asn::from_u32(1234)).into()
2546 );
2547
2548 check(
2552 vec![
2553 0xc0, 0x20, 0x3c, 0x00, 0x00, 0x20, 0x5b, 0x00,
2554 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00,
2555 0x00, 0xe2, 0x0a, 0x00, 0x00, 0x00, 0x64, 0x00,
2556 0x00, 0x0b, 0x62, 0x00, 0x00, 0xe2, 0x0a, 0x00,
2557 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x64, 0x00,
2558 0x00, 0xe2, 0x0a, 0x00, 0x00, 0x00, 0x67, 0x00,
2559 0x00, 0x00, 0x01, 0x00, 0x00, 0xe2, 0x0a, 0x00,
2560 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x1f
2561 ],
2562 LargeCommunitiesList::new(
2563 vec![
2564 "AS8283:6:15".parse().unwrap(),
2565 "AS57866:100:2914".parse().unwrap(),
2566 "AS57866:101:100".parse().unwrap(),
2567 "AS57866:103:1".parse().unwrap(),
2568 "AS57866:104:31".parse().unwrap(),
2569 ]
2570 ).into()
2571 );
2572
2573 check(
2574 vec![0xc0, 0x23, 0x04, 0x00, 0x00, 0x04, 0xd2],
2575 crate::bgp::types::Otc(Asn::from_u32(1234)).into()
2576 );
2577
2578 let flags = Flags::OPT_TRANS | Flags::PARTIAL;
2585 check(
2586 vec![flags, 254, 0x04, 0x01, 0x02, 0x03, 0x04],
2587 UnimplementedPathAttribute::new(
2588 flags.into(),
2589 254,
2590 vec![0x01, 0x02, 0x03, 0x04]
2591 ).into()
2592 );
2593 }
2594
2595 #[test]
2596 fn iter_and_find() {
2597 let raw = vec![
2598 0x40, 0x01, 0x01, 0x00, 0x40, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x80, 0x04, 0x04, 0x00, 0x00, 0x00, 0xff ];
2602 let pas = PathAttributes::new(
2603 Parser::from_ref(&raw), PduParseInfo::modern()
2604 );
2605 assert!(pas.get(PathAttributeType::Origin).is_some());
2611 assert!(pas.get(PathAttributeType::AsPath).is_none());
2612 assert!(pas.get(PathAttributeType::MultiExitDisc).is_some());
2613 assert!(pas.get(PathAttributeType::ConventionalNextHop).is_some());
2614 }
2615
2616 #[test]
2617 fn unimplemented_path_attributes() {
2618 let raw = vec![
2619 0xc0, 254, 0x04, 0x01, 0x02, 0x03, 0x04
2620 ];
2621 let mut parser = Parser::from_ref(&raw);
2622 let sc = PduParseInfo::modern();
2623 let pa = WireformatPathAttribute::parse(&mut parser, sc);
2624
2625 if let Ok(WireformatPathAttribute::Unimplemented(u)) = pa {
2626 assert_eq!(u.type_code(), 254);
2627 assert!(u.flags().is_optional());
2628 assert!(u.flags().is_transitive());
2629 assert_eq!(u.value(), &[0x01, 0x02, 0x03, 0x04]);
2630 } else {
2631 panic!("fail");
2632 }
2633
2634 }
2635
2636 #[test]
2637 fn parse_unexpected_two_octet_asn() {
2638 let raw = vec![
2639 0xc0, 0x07, 0x06, 0x00, 0x65, 0xc6,
2640 0x33, 0x64, 0x01
2641 ];
2642 let mut parser = Parser::from_ref(&raw);
2643 let pa = WireformatPathAttribute::parse(
2644 &mut parser, PduParseInfo::modern()
2645 ).unwrap();
2646 assert!(matches!(pa, WireformatPathAttribute::Invalid(_,_,_)));
2647 }
2648
2649 #[test]
2677 fn as_ref_as_mut() {
2678 let raw = vec![0x40, 0x02, 10,
2680 0x02, 0x02, 0x00, 0x00, 0x00, 100,
2682 0x00, 0x00, 0x00, 200,
2683 ];
2684
2685 let pa = WireformatPathAttribute::parse(
2686 &mut Parser::from_ref(&raw), PduParseInfo::modern()
2687 ).unwrap();
2688 let mut owned = pa.to_owned().unwrap();
2689 if let PathAttribute::AsPath(ref mut asp) = owned {
2690 assert_eq!(format!("{}", asp), "AS100 AS200");
2691 asp.prepend(Asn::from_u32(50));
2692 assert_eq!(format!("{}", asp), "AS50 AS100 AS200");
2693 assert_eq!(3, asp.hop_count());
2694 }
2695
2696 let mut composed = Vec::new();
2697 owned.compose(&mut composed).unwrap();
2698 assert!(composed != raw);
2699 }
2700
2701 use crate::bgp::types::LocalPref as LP;
2702 use crate::bgp::types::MultiExitDisc as MED;
2703 #[test]
2704 fn pamap() {
2705 let mut pamap = PaMap::empty();
2706 pamap.set(LP(100));
2707 pamap.set::<MED>(MED(12));
2708
2709 let _lp1 = pamap.remove::<LP>();
2710 dbg!(&pamap);
2712
2713 dbg!(&pamap);
2718
2719 let asp = HopPath::new();
2720 pamap.set(asp);
2721 dbg!(&pamap);
2722 }
2723
2724 #[test]
2725 fn remove_non_transitives() {
2726 let mut pamap = PaMap::empty();
2727 pamap.set(LP(100));
2729 pamap.set::<MED>(MED(12));
2731
2732 assert_eq!(pamap.attributes.len(), 2);
2733 pamap.remove_non_transitives();
2734 assert_eq!(pamap.attributes.len(), 1);
2735 assert!(pamap.get::<LP>().is_some());
2736 assert!(pamap.get::<MED>().is_none());
2737 }
2738}