Skip to main content

routecore/bgp/nlri/
afisafi.rs

1use core::hash::Hash;
2use core::str::FromStr;
3use std::cmp;
4use std::fmt::{self, Debug};
5
6
7use crate::typeenum; // from util::macros
8
9#[cfg(feature = "serde")]
10use serde::{Serialize, Deserialize};
11
12// notes:
13// - move in and adapt all remaining stuff from bgp/message/nlri.rs
14// - can we do PartialEq impls in macro?
15// - eventually rename this to bgp/nlri.rs ?
16// - remove bgp/message/nlri.rs  
17// - pub use Afi/Nlri/etc from bgp::types 
18// - clean up / remove bgp/workshop/afisafi_nlri.rs 
19
20use inetnum::addr::Prefix;
21use super::common::{compose_len_prefix, compose_prefix, parse_v4_prefix, parse_v6_prefix};
22use super::common::{PathId, prefix_bits_to_bytes};
23use crate::util::parser::ParseError;
24use paste::paste;
25
26
27use octseq::{Octets, OctetsBuilder, Parser};
28
29use super::evpn::*;
30use super::flowspec::*;
31use super::mpls::*;
32use super::mpls_vpn::*;
33use super::routetarget::*;
34use super::vpls::*;
35
36// The addpath! macro creates Addpath versions of Nlri types.
37//
38// Because some Nlri types are generic over Octets, the 'first part' of the
39// macro is split up. This way we can derive more traits (most notably, Copy)
40// on the simpler AddpathNlri.
41// After this 'first part' where the structs are generated, both patterns call
42// the generic pattern via `addpath!(@generic $nlri)` to generate all the
43// other parts which are not hindered by the optional generic Octs parameter.
44
45macro_rules! addpath {
46    ($nlri:ident ) => { paste! {
47    #[derive(Copy, Clone, Debug, Hash, PartialEq, Ord, PartialOrd)]
48    #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
49    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50    pub struct [<$nlri AddpathNlri>](PathId, [<$nlri Nlri>]);
51    impl AfiSafiNlri for [<$nlri AddpathNlri>] {
52        type Nlri = <[<$nlri Nlri>] as AfiSafiNlri>::Nlri;
53        fn nlri(&self) -> &Self::Nlri {
54            &self.1.nlri()
55        }
56    }
57
58    addpath!(@generic $nlri);
59
60    }};
61
62    ($nlri:ident <$gen:ident>) => { paste! {
63    #[allow(clippy::derived_hash_with_manual_eq)]
64    #[derive(Clone, Debug, Hash)]
65    #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
66    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
67    pub struct [<$nlri AddpathNlri>]<$gen>(PathId, [<$nlri Nlri>]<$gen>);
68    impl<$gen> AfiSafiNlri for [<$nlri AddpathNlri>]<$gen> {
69        type Nlri = <[<$nlri Nlri>]<$gen> as AfiSafiNlri>::Nlri;
70        fn nlri(&self) -> &Self::Nlri {
71            &self.1.nlri()
72        }
73    }
74
75    impl<$gen: AsRef<[u8]>> Ord for [<$nlri AddpathNlri>]<$gen> {
76        fn cmp(&self, other: &Self) -> cmp::Ordering {
77            self.1.cmp(&other.1).then(self.0.cmp(&other.0))
78        }
79    }
80    impl<$gen: AsRef<[u8]>> PartialOrd for [<$nlri AddpathNlri>]<$gen> {
81        fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
82            Some(self.cmp(&other))
83        }
84    }
85
86    addpath!(@generic $nlri<$gen>);
87
88    }};
89
90    (@generic $nlri:ident $(<$gen:ident>)?) => { paste! {
91
92    impl$(<$gen>)? AfiSafi for [<$nlri AddpathNlri>]$(<$gen>)? {
93        fn afi() -> Afi { <[<$nlri Nlri>]$(<$gen>)? as AfiSafi>::afi() }
94        fn afi_safi() -> AfiSafiType { <[<$nlri Nlri>]$(<$gen>)? as AfiSafi>::afi_safi() }
95    }
96
97    impl<'a, Octs, P> NlriParse<'a, Octs, P> for [<$nlri AddpathNlri>]$(<$gen>)?
98    where
99        Octs: Octets,
100        P: 'a + Octets<Range<'a> = Octs>
101    {
102        type Output = Self;
103        fn parse(parser: &mut Parser<'a, P>) -> Result<Self::Output, ParseError> {
104            let path_id = PathId(parser.parse_u32_be()?);
105            let inner = [<$nlri Nlri>]::parse(parser)?;
106            Ok(
107                Self(path_id, inner)
108            )
109        }
110    }
111
112    impl$(<$gen>)? NlriCompose for [<$nlri AddpathNlri>]$(<$gen>)?
113    $(where 
114        $gen: AsRef<[u8]>
115    )?
116    {
117        fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
118            -> Result<(), Target::AppendError>
119        {
120                target.append_slice(&self.0.0.to_be_bytes())?;
121                self.1.compose(target)
122        }
123
124        fn compose_len(&self) -> usize {
125            4 + self.1.compose_len()
126        }
127    }
128
129    impl$(<$gen>)? IsNlri for [<$nlri AddpathNlri>]$(<$gen>)? { 
130        fn nlri_type() -> NlriType {
131            NlriType::[<$nlri Addpath>]
132        }
133    }
134
135    impl$(<$gen>)? Addpath for [<$nlri AddpathNlri>]$(<$gen>)? {
136        fn path_id(&self) -> PathId {
137            self.0
138        }
139    }
140
141    impl$(<$gen: AsRef<[u8]>>)? Eq for [<$nlri AddpathNlri>]$(<$gen>)? { }
142
143    impl$(<$gen>)? fmt::Display for [<$nlri AddpathNlri>]$(<$gen>)? {
144        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145            write!(f, "[{}] ", self.0)?;
146            fmt::Display::fmt(&self.1, f)
147        }
148    }
149    }};
150}
151
152// For Nlri generic over anything, use <Octs> literally. Using another name,
153// e.g. <O>, does not work. This is a limitation of the macro.
154macro_rules! afisafi {
155    (
156        $(
157            $afi_code:expr => $afi_name:ident [ $( $safi_code:expr => $safi_name:ident$(<$gen:ident>)? ),+ $(,)* ]
158        ),+ $(,)*
159    ) =>
160{
161    typeenum!(
162        /// AFI as used in BGP OPEN and UPDATE messages.
163        #[cfg_attr(feature = "serde", serde(from = "u16"))]
164        Afi, u16,
165        {
166            $($afi_code => $afi_name),+
167        });
168
169paste! {
170    #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
171    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
172    #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
173    pub enum AfiSafiType {
174        $( $( [<$afi_name $safi_name>] ,)+)+
175        Unsupported(u16, u8),
176    }
177
178    impl From<(u16, u8)> for AfiSafiType {
179        fn from(t: (u16, u8)) -> Self {
180            match t {
181            $($(
182                ($afi_code, $safi_code) => Self::[<$afi_name $safi_name>],
183            )+)+
184                _ => Self::Unsupported(t.0, t.1)
185            }
186        }
187    }
188
189    impl From<AfiSafiType> for (u16, u8) {
190        fn from(afisafi: AfiSafiType) -> (u16, u8) {
191            match afisafi {
192            $($(
193                AfiSafiType::[<$afi_name $safi_name>] => ($afi_code, $safi_code),
194            )+)+
195                AfiSafiType::Unsupported(a, s) => (a, s)
196            }
197        }
198    }
199
200    impl AfiSafiType {
201        pub const fn afi(self) -> Afi {
202            match self {
203            $($(
204                Self::[<$afi_name $safi_name>] => Afi::$afi_name,
205            )+)+
206                Self::Unsupported(a, _s) => Afi::Unimplemented(a)
207            }
208        }
209
210        pub const fn as_bytes(self) -> [u8; 3] {
211            match self {
212            $($(
213                Self::[<$afi_name $safi_name>] => {
214                    let afi = $afi_code.to_be_bytes();
215                    [afi[0], afi[1], $safi_code]
216                }
217            )+)+
218                AfiSafiType::Unsupported(a, s) => {
219                    let afi = a.to_be_bytes();
220                    [afi[0], afi[1], s]
221                }
222            }
223        }
224    }
225
226
227    impl fmt::Display for AfiSafiType {
228        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229            match self {
230            $($(
231                Self::[<$afi_name $safi_name>] => {
232                    write!(f, stringify!([<$afi_name $safi_name>]))
233                }
234            )+)+
235                Self::Unsupported(a, s) => {
236                    write!(f, "UnsupportedAfiSafi({}, {})", a, s)
237                }
238            }
239        }
240    }
241
242    // this enforces these derives on all *Nlri structs.
243    #[derive(Clone, Debug, Hash)]
244    #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
245    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
246    pub enum Nlri<Octs> {
247    $($(
248        [<$afi_name $safi_name>]([<$afi_name $safi_name Nlri>]$(<$gen>)?),
249        [<$afi_name $safi_name Addpath>]([<$afi_name $safi_name AddpathNlri>]$(<$gen>)?)
250    ,)+)+
251    }
252
253    impl<Octs> Nlri<Octs> {
254        pub const fn afi_safi(&self) -> AfiSafiType {
255            match self {
256            $($(
257                Self::[<$afi_name $safi_name>](..) => AfiSafiType::[<$afi_name $safi_name >],
258                Self::[<$afi_name $safi_name Addpath>](..) => AfiSafiType::[<$afi_name $safi_name >],
259            )+)+
260            }
261        }
262
263        pub const fn nlri_type(&self) -> NlriType {
264            match self {
265            $($(
266                Self::[<$afi_name $safi_name>](..) => NlriType::[<$afi_name $safi_name >],
267                Self::[<$afi_name $safi_name Addpath>](..) => NlriType::[<$afi_name $safi_name Addpath>],
268            )+)+
269            }
270        }
271    }
272
273    impl<Octs> Nlri<Octs>
274    where
275        Octs: AsRef<[u8]>
276    {
277        pub fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
278            -> Result<(), Target::AppendError> {
279            match self {
280            $($(
281                Nlri::[<$afi_name $safi_name>](n) => n.compose(target),
282                Nlri::[<$afi_name $safi_name Addpath>](n) => n.compose(target),
283            )+)+
284            }
285        }
286    }
287
288
289    impl<Octs, Other> PartialEq<Nlri<Other>> for Nlri<Octs>
290    where Octs: AsRef<[u8]>,
291          Other: AsRef<[u8]>
292    {
293        fn eq(&self, other: &Nlri<Other>) -> bool {
294            match (self, other) {
295            $($(
296                (Nlri::[<$afi_name $safi_name>](p1), Nlri::[<$afi_name $safi_name>](p2)) => p1 == p2,
297                (Nlri::[<$afi_name $safi_name Addpath>](p1), Nlri::[<$afi_name $safi_name Addpath>](p2)) => p1 == p2,
298            )+)+
299            _ => false
300            }
301        }
302    }
303
304    impl<Octs> Ord for Nlri<Octs>
305    where Octs: AsRef<[u8]>
306    {
307        fn cmp(&self, other: &Nlri<Octs>) -> cmp::Ordering {
308            match (self, other) {
309            $($(
310                (Nlri::[<$afi_name $safi_name>](p1), Nlri::[<$afi_name $safi_name>](p2)) => p1.cmp(p2),
311                (Nlri::[<$afi_name $safi_name Addpath>](p1), Nlri::[<$afi_name $safi_name Addpath>](p2)) => p1.cmp(p2),
312            )+)+
313                (a, b) => a.nlri_type().cmp(&b.nlri_type()),
314            }
315        }
316    }
317
318    impl<T> fmt::Display for Nlri<T> {
319        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
320            match self {
321            $($(
322                Self::[<$afi_name $safi_name>](i) => fmt::Display::fmt(i, f),
323                Self::[<$afi_name $safi_name Addpath>](i) => {
324                    fmt::Display::fmt(i, f)
325                }
326            )+)+
327            }
328        }
329    }
330
331    #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
332    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
333    #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
334    pub enum NlriType {
335    $($(
336        [<$afi_name $safi_name>],
337        [<$afi_name $safi_name Addpath>],
338    )+)+
339        Unsupported(u16, u8),
340    }
341
342    impl NlriType {
343        pub const fn afi_safi(&self) -> AfiSafiType {
344            match self {
345            $($(
346                Self::[<$afi_name $safi_name>] => AfiSafiType::[<$afi_name $safi_name >],
347                Self::[<$afi_name $safi_name Addpath>] => AfiSafiType::[<$afi_name $safi_name >],
348            )+)+
349                Self::Unsupported(a, s) => AfiSafiType::Unsupported(*a, *s)
350            }
351        }
352    }
353
354
355    impl From<(AfiSafiType, bool)> for NlriType {
356        fn from(t: (AfiSafiType, bool)) -> Self {
357            match (t.0, t.1) {
358                $($(
359                    (AfiSafiType::[<$afi_name $safi_name>], false) => NlriType::[<$afi_name $safi_name >],
360                    (AfiSafiType::[<$afi_name $safi_name>], true)  => NlriType::[<$afi_name $safi_name Addpath>],
361                )+)+
362                    (AfiSafiType::Unsupported(a, s), _)  => NlriType::Unsupported(a, s),
363            }
364        }
365    }
366
367    impl From<NlriType> for AfiSafiType {
368        fn from(n: NlriType) -> Self {
369            n.afi_safi()
370        }
371    }
372
373
374$($(
375    // Instead of doing:
376    //pub struct [<$afi_name $safi_name Nlri>];
377    //
378    // .. we rely on the impl below, forcing us to actually create the
379    // $Afi$SafiNlri struct, along with all its basic or exotic data fields
380    // and whatnot. We can not do that in a generic way in this macro.
381    impl$(<$gen>)? AfiSafi for [<$afi_name $safi_name Nlri>]$(<$gen>)? { 
382        fn afi() -> Afi { Afi::$afi_name }
383        fn afi_safi() -> AfiSafiType {
384            AfiSafiType::[<$afi_name $safi_name>]
385        }
386    }
387
388    impl$(<$gen>)? IsNlri for [<$afi_name $safi_name Nlri>]$(<$gen>)? { 
389        fn nlri_type() -> NlriType {
390            NlriType::[<$afi_name $safi_name>]
391        }
392    }
393
394    impl$(<$gen>)? fmt::Display for [<$afi_name $safi_name Nlri>]$(<$gen>)?
395    where <[<$afi_name $safi_name Nlri>]$(<$gen>)? as AfiSafiNlri>::Nlri: fmt::Display {
396        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
397            write!(f, "{}", self.nlri())
398        }
399    }
400
401    impl<Octs> From<[<$afi_name $safi_name Nlri>]$(<$gen>)?> for Nlri<Octs> {
402        fn from(n: [<$afi_name $safi_name Nlri>]$(<$gen>)?) -> Self {
403            Nlri::[<$afi_name $safi_name>](n)
404        }
405    }
406
407    impl<Octs> From<[<$afi_name $safi_name AddpathNlri>]$(<$gen>)?> for Nlri<Octs> {
408        fn from(n: [<$afi_name $safi_name AddpathNlri>]$(<$gen>)?) -> Self {
409            Nlri::[<$afi_name $safi_name Addpath>](n)
410        }
411    }
412
413    impl$(<$gen>)? From<[<$afi_name $safi_name AddpathNlri>]$(<$gen>)?> for [<$afi_name $safi_name Nlri>]$(<$gen>)? {
414        fn from(n: [<$afi_name $safi_name AddpathNlri>]$(<$gen>)?) -> Self {
415            n.1
416        }
417    }
418
419    impl$(<$gen: AsRef<[u8]>>)? Eq for [<$afi_name $safi_name Nlri>]$(<$gen>)? { }
420
421    //--- NlriIter
422
423    impl<'a, Octs, P> NlriIter<'a, Octs, P, [<$afi_name $safi_name Nlri>]$(<$gen>)?>
424    where
425        Octs: Octets,
426        P: Octets<Range<'a> = Octs>
427    {
428        pub const fn [<$afi_name:lower _ $safi_name:lower>](parser: Parser<'a, P>) -> Self {
429            NlriIter::<'a, Octs, P, [<$afi_name $safi_name Nlri>]$(<$gen>)?>::new(parser)
430        }
431    }
432
433    impl<'a, Octs, P> NlriIter<'a, Octs, P, [<$afi_name $safi_name AddpathNlri>]$(<$gen>)?>
434    where
435        Octs: Octets,
436        P: Octets<Range<'a> = Octs>
437    {
438        pub const fn [<$afi_name:lower _ $safi_name:lower _ addpath>](parser: Parser<'a, P>) -> Self {
439            NlriIter::<'a, Octs, P, [<$afi_name $safi_name AddpathNlri>]$(<$gen>)?>::new(parser)
440        }
441    }
442
443    // Some attempts to add fn iter() to the Nlri structs below.
444    // Problem is that we can only act on _presence_ of $gen , but not on its
445    // absence. So when we have the <Octs> on the struct, the fn iter can not
446    // define it again, though we need it there for the non <Octs> structs.
447    
448    /*
449    impl [<$afi_name $safi_name Nlri>]  {
450        pub fn iter1<'a, Octs, P>(parser: Parser<'a, P>) -> NlriIter<'a, Octs, P, Self>
451        where
452            Octs: Octets,
453            P: 'a + Octets<Range<'a> = Octs>
454        {
455            NlriIter::[<$afi_name:lower _ $safi_name:lower>](parser)
456        }
457    }
458    */
459
460    /*
461    // <Octs> structs only
462    $(
463    impl<$gen> [<$afi_name $safi_name Nlri>]<$gen>  {
464        pub fn iter2<'a, P>(parser: Parser<'a, P>) -> NlriIter<'a, Octs, P, Self>
465        where
466            Octs: Octets,
467            P: 'a + Octets<Range<'a> = Octs>
468        {
469            NlriIter::[<$afi_name:lower _ $safi_name:lower>](parser)
470        }
471    }
472    )?
473    */
474
475    impl$(<$gen>)?  [<$afi_name $safi_name Nlri>]$(<$gen>)?  {
476        pub const fn into_addpath(self, path_id: PathId) -> [<$afi_name $safi_name AddpathNlri>]$(<$gen>)? {
477            [<$afi_name $safi_name AddpathNlri>](path_id, self)
478        }
479    }
480
481    // Create the Addpath version
482    addpath!([<$afi_name $safi_name>]$(<$gen>)?);
483)+)+
484
485}}
486}
487
488//--- Trait implementations for macro generated types
489
490impl<Octs: AsRef<[u8]>> Eq for Nlri<Octs> {}
491
492impl<Octs> PartialOrd for Nlri<Octs>
493where Octs: AsRef<[u8]>,
494{
495    fn partial_cmp(&self, other: &Nlri<Octs>) -> Option<cmp::Ordering> {
496        Some(self.cmp(other))
497    }
498}
499
500
501// While Nlri<()> might make more sense, it clashes with trait bounds
502// like Vec<u8>: OctetsFrom<T> elsewhere, as, From<()> is not implemented for
503// Vec<u8>. Similarly, () is not AsRef<[u8]>.
504impl Nlri<&[u8]> {
505    /// Creates a `Nlri::Unicast` for `prefix`.
506    ///
507    /// This returns the error thrown by `Prefix::from_str` if `prefix` does
508    /// not represent a valid IPv6 or IPv4 prefix.
509    pub fn unicast_from_str(prefix: &str)
510        -> Result<Nlri<&[u8]>, <Prefix as FromStr>::Err>
511    {
512        let p = Prefix::from_str(prefix)?;
513        if p.is_v4() {
514            Ok(Nlri::Ipv4Unicast(Ipv4UnicastNlri(p)))
515        } else {
516            Ok(Nlri::Ipv6Unicast(Ipv6UnicastNlri(p)))
517        }
518    }
519}
520
521//------------ Traits ---------------------------------------------------------
522
523/// A type characterized by an AFI and SAFI.
524pub trait AfiSafi {
525    fn afi() -> Afi;
526    fn afi_safi() -> AfiSafiType;
527}
528
529pub trait IsNlri {
530    fn nlri_type() -> NlriType;
531}
532
533/// A type representing an NLRI for a certain AFI+SAFI.
534pub trait AfiSafiNlri: AfiSafi + IsNlri { // + Clone + Hash + Debug {
535    type Nlri;
536    fn nlri(&self) -> &Self::Nlri;
537
538    // TODO
539    //fn nexthop_compatible(&self, nh: &super::nexthop::NextHop) -> bool;
540}
541
542pub trait NlriParse<'a, O, P>: Sized + IsNlri
543    where P: 'a + Octets<Range<'a> = O>
544{
545    type Output: AfiSafi;
546    fn parse(parser: &mut Parser<'a, P>) -> Result<Self::Output, ParseError>;
547}
548
549pub trait NlriCompose: AfiSafiNlri {
550    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
551        -> Result<(), Target::AppendError>;
552
553    fn compose_len(&self) -> usize;
554}
555
556
557/// A type containing nothing more than a (v4 or v6) Prefix.
558pub trait IsPrefix: AfiSafiNlri {
559    fn prefix(&self) -> Prefix;
560    
561    fn path_id(&self) -> Option<PathId> {
562        None
563    }
564}
565
566// with this blanket impl we can't distinguish addpath from non-addpath
567/*
568impl <T, B>IsPrefix for T where T: AfiSafiNlri<Nlri = B>, B: Into<Prefix> {
569    fn prefix(&self) -> Prefix {
570        self.nlri().into()
571    }
572}
573*/
574
575macro_rules! is_prefix {
576    ($nlri:ident) => { paste! {
577        impl IsPrefix for [<$nlri Nlri>] {
578            fn prefix(&self) -> Prefix {
579                (*self.nlri()).into()
580            }
581        }
582        impl IsPrefix for [<$nlri AddpathNlri>] {
583            fn prefix(&self) -> Prefix {
584                (*self.nlri()).into()
585            }
586            fn path_id(&self) -> Option<PathId> {
587                Some(<Self as Addpath>::path_id(&self))
588            }
589        }
590    }}
591}
592is_prefix!(Ipv4Unicast);
593is_prefix!(Ipv4Multicast);
594is_prefix!(Ipv6Unicast);
595is_prefix!(Ipv6Multicast);
596
597/// An Nlri containing a Path Id.
598pub trait Addpath: AfiSafiNlri {
599    fn path_id(&self) -> PathId;
600}
601
602
603//------------ Implementations -----------------------------------------------
604
605// adding AFI/SAFIs here requires some manual labor:
606// - at the least, add a struct for $Afi$SafiNlri , deriving Clone,Debug,Hash
607// - impl AfiSafiNlri, NlriParse and Display
608
609afisafi! {
610    1_u16 => Ipv4 [
611        1 => Unicast,
612        2 => Multicast,
613        4 => MplsUnicast<Octs>,
614        128 => MplsVpnUnicast<Octs>,
615        132 => RouteTarget<Octs>,
616        133 => FlowSpec<Octs>,
617        //134 => FlowSpecVpn<Octs>,
618
619    ],
620    2_u16 => Ipv6 [
621        1 => Unicast,
622        2 => Multicast,
623        4 => MplsUnicast<Octs>,
624        128 => MplsVpnUnicast<Octs>,
625        133 => FlowSpec<Octs>,
626        //134 => FlowSpecVpn<Octs>,
627    ],
628    25_u16 => L2Vpn [
629        65 => Vpls,
630        70 => Evpn<Octs>,
631    ]
632}
633
634
635//------------ Ipv4 ----------------------------------------------------------
636
637
638// --- Ipv4Unicast
639
640#[derive(Copy, Clone, Debug, Hash, PartialEq, Ord, PartialOrd)]
641#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
642#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
643pub struct Ipv4UnicastNlri(Prefix);
644
645impl AfiSafiNlri for Ipv4UnicastNlri {
646    type Nlri = Prefix;
647    fn nlri(&self) -> &Self::Nlri {
648        &self.0
649    }
650}
651
652impl FromStr for Ipv4UnicastNlri {
653    type Err = &'static str;
654    fn from_str(s: &str) -> Result<Self, Self::Err> {
655        let p = Prefix::from_str(s).map_err(|_| "could not parse prefix")?;
656        p.try_into()
657    }
658}
659
660impl TryFrom<Prefix> for Ipv4UnicastNlri {
661    type Error = &'static str;
662    fn try_from(p: Prefix) -> Result<Self, Self::Error> {
663        if p.is_v4() {
664            Ok( Self(p) )
665        } else {
666            Err("prefix is not IPv4")
667        }
668    }
669}
670
671impl TryFrom<(Prefix, PathId)> for Ipv4UnicastAddpathNlri {
672    type Error = &'static str;
673
674    fn try_from((prefix, path_id): (Prefix, PathId)) -> Result<Self, Self::Error> {
675        Ok(Ipv4UnicastNlri::try_from(prefix)?.into_addpath(path_id))
676    }
677}
678
679
680impl<'a, O, P> NlriParse<'a, O, P> for Ipv4UnicastNlri
681where
682    O: Octets,
683    P: 'a + Octets<Range<'a> = O>
684{
685    type Output = Self;
686    fn parse(parser: &mut Parser<'a, P>) -> Result<Self::Output, ParseError> {
687        Ok(
688            Self(parse_v4_prefix(parser)?)
689        )
690    }
691}
692
693impl NlriCompose for Ipv4UnicastNlri {
694    fn compose_len(&self) -> usize {
695        // 1 byte for the length itself
696        1 + compose_len_prefix(self.prefix())
697    }
698
699    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
700        -> Result<(), Target::AppendError>
701    {
702        compose_prefix(self.prefix(), target)
703    }
704}
705
706//--- Ipv4Multicast
707
708#[derive(Copy, Clone, Debug, Hash, PartialEq, Ord, PartialOrd)]
709#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
710#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
711pub struct Ipv4MulticastNlri(Prefix);
712
713impl AfiSafiNlri for Ipv4MulticastNlri {
714    type Nlri = Prefix;
715    fn nlri(&self) -> &Self::Nlri {
716        &self.0
717    }
718}
719
720impl FromStr for Ipv4MulticastNlri {
721    type Err = &'static str;
722    fn from_str(s: &str) -> Result<Self, Self::Err> {
723        let p = Prefix::from_str(s).map_err(|_| "err")?;
724        p.try_into()
725    }
726}
727
728impl TryFrom<Prefix> for Ipv4MulticastNlri {
729    type Error = &'static str;
730    fn try_from(p: Prefix) -> Result<Self, Self::Error> {
731        if p.is_v4() {
732            Ok( Self(p) )
733        } else {
734            Err("prefix is not IPv4")
735        }
736    }
737}
738
739impl TryFrom<(Prefix, PathId)> for Ipv4MulticastAddpathNlri {
740    type Error = &'static str;
741
742    fn try_from((prefix, path_id): (Prefix, PathId)) -> Result<Self, Self::Error> {
743        Ok(Ipv4MulticastNlri::try_from(prefix)?.into_addpath(path_id))
744    }
745}
746
747impl<'a, O, P> NlriParse<'a, O, P> for Ipv4MulticastNlri
748where
749    O: Octets,
750    P: 'a + Octets<Range<'a> = O>
751{
752    type Output = Self;
753    fn parse(parser: &mut Parser<'a, P>) -> Result<Self::Output, ParseError> {
754        Ok(
755            Self(parse_v4_prefix(parser)?)
756        )
757    }
758}
759
760impl NlriCompose for Ipv4MulticastNlri {
761    fn compose_len(&self) -> usize {
762        // 1 byte for the length itself
763        1 + compose_len_prefix(self.prefix())
764    }
765
766    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
767        -> Result<(), Target::AppendError>
768    {
769        compose_prefix(self.prefix(), target)
770    }
771}
772
773//--- Ipv4MplsUnicast
774
775#[derive(Copy, Clone, Debug, Hash)]
776#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
777#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
778pub struct Ipv4MplsUnicastNlri<Octs>(MplsNlri<Octs>);
779
780impl<Octs> AfiSafiNlri for Ipv4MplsUnicastNlri<Octs> {
781    type Nlri = MplsNlri<Octs>;
782    fn nlri(&self) -> &Self::Nlri {
783        &self.0
784    }
785}
786
787impl<'a, O, P> NlriParse<'a, O, P> for Ipv4MplsUnicastNlri<O>
788where
789    O: Octets,
790    P: 'a + Octets<Range<'a> = O>
791{
792    type Output = Self;
793
794    fn parse(parser: &mut Parser<'a, P>)
795        -> Result<Self::Output, ParseError>
796    {
797        Ok(
798            Self(MplsNlri::parse(parser, Afi::Ipv4)?)
799        )
800    }
801}
802
803impl<Octs: AsRef<[u8]>> NlriCompose for Ipv4MplsUnicastNlri<Octs> {
804    fn compose_len(&self) -> usize {
805        // 1 byte for the length itself
806        1 + self.nlri().compose_len()
807    }
808
809    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
810        -> Result<(), Target::AppendError> {
811            self.nlri().compose(target)
812    }
813}
814
815impl<Octs, Other> PartialEq<Ipv4MplsUnicastNlri<Other>> for Ipv4MplsUnicastNlri<Octs>
816where Octs: AsRef<[u8]>,
817      Other: AsRef<[u8]>
818{
819    fn eq(&self, other: &Ipv4MplsUnicastNlri<Other>) -> bool {
820        self.0 == other.0
821    }
822}
823
824
825impl<Octs, Other> PartialEq<Ipv4MplsUnicastAddpathNlri<Other>> for Ipv4MplsUnicastAddpathNlri<Octs>
826where Octs: AsRef<[u8]>,
827      Other: AsRef<[u8]>
828{
829    fn eq(&self, other: &Ipv4MplsUnicastAddpathNlri<Other>) -> bool {
830        self.0 == other.0
831    }
832}
833
834impl<Octs> PartialOrd for Ipv4MplsUnicastNlri<Octs>
835where Octs: AsRef<[u8]>,
836{
837    fn partial_cmp(&self, other: &Ipv4MplsUnicastNlri<Octs>) -> Option<cmp::Ordering> {
838        Some(self.cmp(other))
839    }
840}
841
842impl<Octs: AsRef<[u8]>> Ord for Ipv4MplsUnicastNlri<Octs> {
843    fn cmp(&self, other: &Self) -> cmp::Ordering {
844        self.0.cmp(&other.0)
845    }
846}
847
848//--- Ipv4MplsVpnUnicastNlri
849
850#[derive(Copy, Clone, Debug, Hash)]
851#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
852#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
853pub struct Ipv4MplsVpnUnicastNlri<Octs>(MplsVpnNlri<Octs>);
854
855impl<Octs> AfiSafiNlri for Ipv4MplsVpnUnicastNlri<Octs> {
856    type Nlri = MplsVpnNlri<Octs>;
857    fn nlri(&self) -> &Self::Nlri {
858        &self.0
859    }
860}
861
862impl<'a, O, P> NlriParse<'a, O, P> for Ipv4MplsVpnUnicastNlri<O>
863where
864    O: Octets,
865    P: 'a + Octets<Range<'a> = O>
866{
867    type Output = Self;
868
869    fn parse(parser: &mut Parser<'a, P>)
870        -> Result<Self::Output, ParseError>
871    {
872        let (labels, rd, prefix) =
873            parse_labels_rd_prefix(parser, Afi::Ipv4)?;
874
875        Ok(Self(MplsVpnNlri::new(prefix, labels, rd)))
876    }
877}
878
879impl<Octs: AsRef<[u8]>> NlriCompose for Ipv4MplsVpnUnicastNlri<Octs> {
880    fn compose_len(&self) -> usize {
881        1 + self.nlri().compose_len()
882    }
883
884    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
885        -> Result<(), Target::AppendError> {
886            self.nlri().compose(target)
887    }
888}
889
890impl<Octs, Other> PartialEq<Ipv4MplsVpnUnicastNlri<Other>> for Ipv4MplsVpnUnicastNlri<Octs>
891where Octs: AsRef<[u8]>,
892      Other: AsRef<[u8]>
893{
894    fn eq(&self, other: &Ipv4MplsVpnUnicastNlri<Other>) -> bool {
895        self.0 == other.0
896    }
897}
898
899impl<Octs, Other> PartialEq<Ipv4MplsVpnUnicastAddpathNlri<Other>> for Ipv4MplsVpnUnicastAddpathNlri<Octs>
900where Octs: AsRef<[u8]>,
901      Other: AsRef<[u8]>
902{
903    fn eq(&self, other: &Ipv4MplsVpnUnicastAddpathNlri<Other>) -> bool {
904        self.0 == other.0
905    }
906}
907
908impl<Octs> PartialOrd for Ipv4MplsVpnUnicastNlri<Octs>
909where Octs: AsRef<[u8]>,
910{
911    fn partial_cmp(&self, other: &Ipv4MplsVpnUnicastNlri<Octs>) -> Option<cmp::Ordering> {
912        Some(self.cmp(other))
913    }
914}
915
916impl<Octs: AsRef<[u8]>> Ord for Ipv4MplsVpnUnicastNlri<Octs> {
917    fn cmp(&self, other: &Self) -> cmp::Ordering {
918        self.0.cmp(&other.0)
919    }
920}
921
922//--- Ipv4RouteTarget
923
924#[derive(Clone, Debug, Hash)]
925#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
926#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
927pub struct Ipv4RouteTargetNlri<Octs>(RouteTargetNlri<Octs>);
928
929impl<Octs> AfiSafiNlri for Ipv4RouteTargetNlri<Octs> {
930    type Nlri = RouteTargetNlri<Octs>;
931    fn nlri(&self) -> &Self::Nlri {
932        &self.0
933    }
934}
935
936impl<'a, O, P> NlriParse<'a, O, P> for Ipv4RouteTargetNlri<O>
937where
938    O: Octets,
939    P: 'a + Octets<Range<'a> = O>
940{
941    type Output = Self;
942
943    fn parse(parser: &mut Parser<'a, P>)
944        -> Result<Self::Output, ParseError>
945    {
946
947        Ok(Self(RouteTargetNlri::parse(parser)?))
948    }
949}
950
951impl<Octs: AsRef<[u8]>> NlriCompose for Ipv4RouteTargetNlri<Octs> {
952    fn compose_len(&self) -> usize {
953        self.nlri().compose_len()
954    }
955
956    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
957        -> Result<(), Target::AppendError> {
958            self.nlri().compose(target)
959    }
960}
961
962impl<Octs, Other> PartialEq<Ipv4RouteTargetNlri<Other>> for Ipv4RouteTargetNlri<Octs>
963where Octs: AsRef<[u8]>,
964      Other: AsRef<[u8]>
965{
966    fn eq(&self, other: &Ipv4RouteTargetNlri<Other>) -> bool {
967        self.0 == other.0
968    }
969}
970
971impl<Octs, Other> PartialEq<Ipv4RouteTargetAddpathNlri<Other>> for Ipv4RouteTargetAddpathNlri<Octs>
972where Octs: AsRef<[u8]>,
973      Other: AsRef<[u8]>
974{
975    fn eq(&self, other: &Ipv4RouteTargetAddpathNlri<Other>) -> bool {
976        self.0 == other.0
977    }
978}
979
980impl<Octs> PartialOrd for Ipv4RouteTargetNlri<Octs>
981where Octs: AsRef<[u8]>,
982{
983    fn partial_cmp(&self, other: &Ipv4RouteTargetNlri<Octs>) -> Option<cmp::Ordering> {
984        Some(self.cmp(other))
985    }
986}
987
988impl<Octs: AsRef<[u8]>> Ord for Ipv4RouteTargetNlri<Octs> {
989    fn cmp(&self, other: &Self) -> cmp::Ordering {
990        self.0.cmp(&other.0)
991    }
992}
993
994//--- Ipv4FlowSpec
995
996#[derive(Clone, Debug, Hash)]
997#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
998#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
999pub struct Ipv4FlowSpecNlri<Octs>(FlowSpecNlri<Octs>);
1000
1001impl<Octs> AfiSafiNlri for Ipv4FlowSpecNlri<Octs> {
1002    type Nlri = FlowSpecNlri<Octs>;
1003    fn nlri(&self) -> &Self::Nlri {
1004        &self.0
1005    }
1006}
1007
1008impl<'a, O, P> NlriParse<'a, O, P> for Ipv4FlowSpecNlri<O>
1009where
1010    O: Octets,
1011    P: 'a + Octets<Range<'a> = O>
1012{
1013    type Output = Self;
1014
1015    fn parse(parser: &mut Parser<'a, P>)
1016        -> Result<Self::Output, ParseError>
1017    {
1018
1019        Ok(Self(FlowSpecNlri::parse(parser, Afi::Ipv4)?))
1020    }
1021}
1022
1023impl<Octs: AsRef<[u8]>> NlriCompose for Ipv4FlowSpecNlri<Octs> {
1024    fn compose_len(&self) -> usize {
1025        // for lenghts of >= 240, the lenght is described in two bytes
1026        let len = self.nlri().compose_len();
1027        if len >= 240 {
1028            2 + len
1029        } else {
1030            1 + len
1031        }
1032    }
1033
1034    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
1035        -> Result<(), Target::AppendError> {
1036            self.nlri().compose(target)
1037    }
1038}
1039
1040impl<T> From<Ipv4FlowSpecNlri<T>> for FlowSpecNlri<T> {
1041    fn from(value: Ipv4FlowSpecNlri<T>) -> Self {
1042        value.0
1043    }
1044}
1045
1046impl<Octs, Other> PartialEq<Ipv4FlowSpecNlri<Other>> for Ipv4FlowSpecNlri<Octs>
1047where Octs: AsRef<[u8]>,
1048      Other: AsRef<[u8]>
1049{
1050    fn eq(&self, other: &Ipv4FlowSpecNlri<Other>) -> bool {
1051        self.0 == other.0
1052    }
1053}
1054
1055impl<Octs, Other> PartialEq<Ipv4FlowSpecAddpathNlri<Other>> for Ipv4FlowSpecAddpathNlri<Octs>
1056where Octs: AsRef<[u8]>,
1057      Other: AsRef<[u8]>
1058{
1059    fn eq(&self, other: &Ipv4FlowSpecAddpathNlri<Other>) -> bool {
1060        self.0 == other.0
1061    }
1062}
1063
1064impl<Octs> PartialOrd for Ipv4FlowSpecNlri<Octs>
1065where Octs: AsRef<[u8]>,
1066{
1067    fn partial_cmp(&self, other: &Ipv4FlowSpecNlri<Octs>) -> Option<cmp::Ordering> {
1068        Some(self.cmp(other))
1069    }
1070}
1071
1072impl<Octs: AsRef<[u8]>> Ord for Ipv4FlowSpecNlri<Octs> {
1073    fn cmp(&self, other: &Self) -> cmp::Ordering {
1074        self.0.cmp(&other.0)
1075    }
1076}
1077
1078//------------ Ipv6 ----------------------------------------------------------
1079
1080//--- Ipv6Unicast
1081
1082#[derive(Copy, Clone, Debug, Hash, PartialEq, Ord, PartialOrd)]
1083#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1084#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1085pub struct Ipv6UnicastNlri(Prefix);
1086impl AfiSafiNlri for Ipv6UnicastNlri {
1087    type Nlri = Prefix;
1088    fn nlri(&self) -> &Self::Nlri {
1089        &self.0
1090    }
1091}
1092
1093impl FromStr for Ipv6UnicastNlri {
1094    type Err = &'static str;
1095    fn from_str(s: &str) -> Result<Self, Self::Err> {
1096        let p = Prefix::from_str(s).map_err(|_| "could not parse prefix")?;
1097        p.try_into()
1098    }
1099}
1100
1101impl TryFrom<Prefix> for Ipv6UnicastNlri {
1102    type Error = &'static str;
1103    fn try_from(p: Prefix) -> Result<Self, Self::Error> {
1104        if p.is_v6() {
1105            Ok( Self(p) )
1106        } else {
1107            Err("prefix is not IPv6")
1108        }
1109    }
1110}
1111
1112impl TryFrom<(Prefix, PathId)> for Ipv6UnicastAddpathNlri {
1113    type Error = &'static str;
1114
1115    fn try_from((prefix, path_id): (Prefix, PathId)) -> Result<Self, Self::Error> {
1116        Ok(Ipv6UnicastNlri::try_from(prefix)?.into_addpath(path_id))
1117    }
1118}
1119
1120impl<'a, O, P> NlriParse<'a, O, P> for Ipv6UnicastNlri
1121where
1122    O: Octets,
1123    P: 'a + Octets<Range<'a> = O>
1124{
1125    type Output = Self;
1126    fn parse(parser: &mut Parser<'a, P>) -> Result<Self::Output, ParseError> {
1127        Ok(
1128            Self(parse_v6_prefix(parser)?)
1129        )
1130    }
1131}
1132
1133impl NlriCompose for Ipv6UnicastNlri {
1134    fn compose_len(&self) -> usize {
1135        // 1 byte for the length itself
1136        1 + compose_len_prefix(self.prefix())
1137    }
1138
1139    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
1140        -> Result<(), Target::AppendError>
1141    {
1142        compose_prefix(self.prefix(), target)
1143    }
1144}
1145
1146//--- Ipv6Multicast
1147
1148#[derive(Copy, Clone, Debug, Hash, PartialEq, Ord, PartialOrd)]
1149#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1150#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1151pub struct Ipv6MulticastNlri(Prefix);
1152
1153impl FromStr for Ipv6MulticastNlri {
1154    type Err = &'static str;
1155    fn from_str(s: &str) -> Result<Self, Self::Err> {
1156        let p = Prefix::from_str(s).map_err(|_| "could not parse prefix")?;
1157        p.try_into()
1158    }
1159}
1160
1161impl TryFrom<Prefix> for Ipv6MulticastNlri {
1162    type Error = &'static str;
1163    fn try_from(p: Prefix) -> Result<Self, Self::Error> {
1164        if p.is_v6() {
1165            Ok( Self(p) )
1166        } else {
1167            Err("prefix is not IPv6")
1168        }
1169    }
1170}
1171
1172impl TryFrom<(Prefix, PathId)> for Ipv6MulticastAddpathNlri {
1173    type Error = &'static str;
1174
1175    fn try_from((prefix, path_id): (Prefix, PathId)) -> Result<Self, Self::Error> {
1176        Ok(Ipv6MulticastNlri::try_from(prefix)?.into_addpath(path_id))
1177    }
1178}
1179
1180impl AfiSafiNlri for Ipv6MulticastNlri {
1181    type Nlri = Prefix;
1182    fn nlri(&self) -> &Self::Nlri {
1183        &self.0
1184    }
1185}
1186
1187impl<'a, O, P> NlriParse<'a, O, P> for Ipv6MulticastNlri
1188where
1189    O: Octets,
1190    P: 'a + Octets<Range<'a> = O>
1191{
1192    type Output = Self;
1193    fn parse(parser: &mut Parser<'a, P>) -> Result<Self::Output, ParseError> {
1194        Ok(
1195            Self(parse_v6_prefix(parser)?)
1196        )
1197    }
1198}
1199
1200impl NlriCompose for Ipv6MulticastNlri {
1201    fn compose_len(&self) -> usize {
1202        // 1 byte for the length itself
1203        1 + compose_len_prefix(self.prefix())
1204    }
1205
1206    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
1207        -> Result<(), Target::AppendError>
1208    {
1209        compose_prefix(self.prefix(), target)
1210    }
1211}
1212
1213//--- Ipv6MplsUnicast
1214
1215#[derive(Copy, Clone, Debug, Hash)]
1216#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1217#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1218pub struct Ipv6MplsUnicastNlri<Octs>(MplsNlri<Octs>);
1219
1220impl<Octs> AfiSafiNlri for Ipv6MplsUnicastNlri<Octs> {
1221    type Nlri = MplsNlri<Octs>;
1222    fn nlri(&self) -> &Self::Nlri {
1223        &self.0
1224    }
1225}
1226
1227impl<'a, O, P> NlriParse<'a, O, P> for Ipv6MplsUnicastNlri<O>
1228where
1229    O: Octets,
1230    P: 'a + Octets<Range<'a> = O>
1231{
1232    type Output = Self;
1233
1234    fn parse(parser: &mut Parser<'a, P>)
1235        -> Result<Self::Output, ParseError>
1236    {
1237        Ok(
1238            Self(MplsNlri::parse(parser, Afi::Ipv6)?)
1239        )
1240    }
1241}
1242
1243impl<Octs: AsRef<[u8]>> NlriCompose for Ipv6MplsUnicastNlri<Octs> {
1244    fn compose_len(&self) -> usize {
1245        // 1 byte for the length itself
1246        1 + self.nlri().labels().len() +
1247            prefix_bits_to_bytes(self.nlri().prefix().len())
1248    }
1249
1250    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
1251        -> Result<(), Target::AppendError> {
1252            self.nlri().compose(target)
1253    }
1254}
1255
1256impl<Octs, Other> PartialEq<Ipv6MplsUnicastNlri<Other>> for Ipv6MplsUnicastNlri<Octs>
1257where Octs: AsRef<[u8]>,
1258      Other: AsRef<[u8]>
1259{
1260    fn eq(&self, other: &Ipv6MplsUnicastNlri<Other>) -> bool {
1261        self.0 == other.0
1262    }
1263}
1264
1265impl<Octs, Other> PartialEq<Ipv6MplsUnicastAddpathNlri<Other>> for Ipv6MplsUnicastAddpathNlri<Octs>
1266where Octs: AsRef<[u8]>,
1267      Other: AsRef<[u8]>
1268{
1269    fn eq(&self, other: &Ipv6MplsUnicastAddpathNlri<Other>) -> bool {
1270        self.0 == other.0
1271    }
1272}
1273
1274impl<Octs> PartialOrd for Ipv6MplsUnicastNlri<Octs>
1275where Octs: AsRef<[u8]>,
1276{
1277    fn partial_cmp(&self, other: &Ipv6MplsUnicastNlri<Octs>) -> Option<cmp::Ordering> {
1278        Some(self.cmp(other))
1279    }
1280}
1281
1282impl<Octs: AsRef<[u8]>> Ord for Ipv6MplsUnicastNlri<Octs> {
1283    fn cmp(&self, other: &Self) -> cmp::Ordering {
1284        self.0.cmp(&other.0)
1285    }
1286}
1287
1288
1289//--- Ipv6MplsVpnUnicastNlri
1290
1291#[derive(Clone, Debug, Hash)]
1292#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1293#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1294pub struct Ipv6MplsVpnUnicastNlri<Octs>(MplsVpnNlri<Octs>);
1295
1296impl<Octs> AfiSafiNlri for Ipv6MplsVpnUnicastNlri<Octs> {
1297    type Nlri = MplsVpnNlri<Octs>;
1298    fn nlri(&self) -> &Self::Nlri {
1299        &self.0
1300    }
1301}
1302
1303impl<'a, O, P> NlriParse<'a, O, P> for Ipv6MplsVpnUnicastNlri<O>
1304where
1305    O: Octets,
1306    P: 'a + Octets<Range<'a> = O>
1307{
1308    type Output = Self;
1309
1310    fn parse(parser: &mut Parser<'a, P>)
1311        -> Result<Self::Output, ParseError>
1312    {
1313        let (labels, rd, prefix) =
1314            parse_labels_rd_prefix(parser, Afi::Ipv6)?;
1315
1316        Ok(Self(MplsVpnNlri::new(prefix, labels, rd)))
1317    }
1318}
1319
1320impl<Octs: AsRef<[u8]>> NlriCompose for Ipv6MplsVpnUnicastNlri<Octs> {
1321    fn compose_len(&self) -> usize {
1322        1 + self.nlri().compose_len()
1323    }
1324
1325    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
1326        -> Result<(), Target::AppendError> {
1327            self.nlri().compose(target)
1328    }
1329}
1330
1331
1332impl<Octs, Other> PartialEq<Ipv6MplsVpnUnicastNlri<Other>> for Ipv6MplsVpnUnicastNlri<Octs>
1333where Octs: AsRef<[u8]>,
1334      Other: AsRef<[u8]>
1335{
1336    fn eq(&self, other: &Ipv6MplsVpnUnicastNlri<Other>) -> bool {
1337        self.0 == other.0
1338    }
1339}
1340
1341impl<Octs, Other> PartialEq<Ipv6MplsVpnUnicastAddpathNlri<Other>> for Ipv6MplsVpnUnicastAddpathNlri<Octs>
1342where Octs: AsRef<[u8]>,
1343      Other: AsRef<[u8]>
1344{
1345    fn eq(&self, other: &Ipv6MplsVpnUnicastAddpathNlri<Other>) -> bool {
1346        self.0 == other.0
1347    }
1348}
1349
1350impl<Octs> PartialOrd for Ipv6MplsVpnUnicastNlri<Octs>
1351where Octs: AsRef<[u8]>,
1352{
1353    fn partial_cmp(&self, other: &Ipv6MplsVpnUnicastNlri<Octs>) -> Option<cmp::Ordering> {
1354        Some(self.cmp(other))
1355    }
1356}
1357
1358impl<Octs: AsRef<[u8]>> Ord for Ipv6MplsVpnUnicastNlri<Octs> {
1359    fn cmp(&self, other: &Self) -> cmp::Ordering {
1360        self.0.cmp(&other.0)
1361    }
1362}
1363
1364//--- Ipv6FlowSpec
1365
1366#[derive(Clone, Debug, Hash)]
1367#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1368#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1369pub struct Ipv6FlowSpecNlri<Octs>(FlowSpecNlri<Octs>);
1370
1371impl<Octs> AfiSafiNlri for Ipv6FlowSpecNlri<Octs> {
1372    type Nlri = FlowSpecNlri<Octs>;
1373    fn nlri(&self) -> &Self::Nlri {
1374        &self.0
1375    }
1376}
1377
1378impl<'a, O, P> NlriParse<'a, O, P> for Ipv6FlowSpecNlri<O>
1379where
1380    O: Octets,
1381    P: 'a + Octets<Range<'a> = O>
1382{
1383    type Output = Self;
1384
1385    fn parse(parser: &mut Parser<'a, P>)
1386        -> Result<Self::Output, ParseError>
1387    {
1388
1389        Ok(Self(FlowSpecNlri::parse(parser, Afi::Ipv6)?))
1390    }
1391}
1392
1393impl<Octs: AsRef<[u8]>> NlriCompose for Ipv6FlowSpecNlri<Octs> {
1394    fn compose_len(&self) -> usize {
1395        // for lenghts of >= 240, the lenght is described in two bytes
1396        let len = self.nlri().compose_len();
1397        if len >= 240 {
1398            2 + len
1399        } else {
1400            1 + len
1401        }
1402    }
1403
1404    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
1405        -> Result<(), Target::AppendError> {
1406            self.nlri().compose(target)
1407    }
1408}
1409
1410impl<T> From<Ipv6FlowSpecNlri<T>> for FlowSpecNlri<T> {
1411    fn from(value: Ipv6FlowSpecNlri<T>) -> Self {
1412        value.0
1413    }
1414}
1415
1416impl<Octs, Other> PartialEq<Ipv6FlowSpecNlri<Other>> for Ipv6FlowSpecNlri<Octs>
1417where Octs: AsRef<[u8]>,
1418      Other: AsRef<[u8]>
1419{
1420    fn eq(&self, other: &Ipv6FlowSpecNlri<Other>) -> bool {
1421        self.0 == other.0
1422    }
1423}
1424
1425impl<Octs, Other> PartialEq<Ipv6FlowSpecAddpathNlri<Other>> for Ipv6FlowSpecAddpathNlri<Octs>
1426where Octs: AsRef<[u8]>,
1427      Other: AsRef<[u8]>
1428{
1429    fn eq(&self, other: &Ipv6FlowSpecAddpathNlri<Other>) -> bool {
1430        self.0 == other.0
1431    }
1432}
1433
1434impl<Octs> PartialOrd for Ipv6FlowSpecNlri<Octs>
1435where Octs: AsRef<[u8]>,
1436{
1437    fn partial_cmp(&self, other: &Ipv6FlowSpecNlri<Octs>) -> Option<cmp::Ordering> {
1438        Some(self.cmp(other))
1439    }
1440}
1441
1442impl<Octs: AsRef<[u8]>> Ord for Ipv6FlowSpecNlri<Octs> {
1443    fn cmp(&self, other: &Self) -> cmp::Ordering {
1444        self.0.cmp(&other.0)
1445    }
1446}
1447
1448/*
1449impl Ipv6UnicastAddpathNlri {
1450    pub fn iter<'a, O, P>(parser: Parser<'a, P>) -> NlriIter<'a, O, P, Self>
1451    where
1452        O: Octets,
1453        P: 'a + Octets<Range<'a> = O>
1454    {
1455        NlriIter::ipv6_unicast_addpath(parser)
1456    }
1457}
1458
1459impl<Octs> Ipv4MplsUnicastNlri<Octs> {
1460    pub fn iter<'a, P>(parser: Parser<'a, P>) -> NlriIter<'a, Octs, P, Self>
1461    where
1462        Octs: Octets,
1463        P: 'a + Octets<Range<'a> = Octs>
1464    {
1465        NlriIter::ipv4_mplsunicast(parser)
1466    }
1467}
1468*/
1469
1470//------------ L2Vpn ----------------------------------------------------------
1471
1472//--- L2VpnVpls
1473
1474#[derive(Copy, Clone, Debug, Hash, PartialEq, Ord, PartialOrd)]
1475#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1476#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1477pub struct L2VpnVplsNlri(VplsNlri);
1478
1479impl AfiSafiNlri for L2VpnVplsNlri {
1480    type Nlri = VplsNlri;
1481    fn nlri(&self) -> &Self::Nlri {
1482        &self.0
1483    }
1484}
1485
1486impl<'a, O, P> NlriParse<'a, O, P> for L2VpnVplsNlri
1487where
1488    O: Octets,
1489    P: 'a + Octets<Range<'a> = O>
1490{
1491    type Output = Self;
1492
1493    fn parse(parser: &mut Parser<'a, P>)
1494        -> Result<Self::Output, ParseError>
1495    {
1496
1497        Ok(Self(VplsNlri::parse(parser)?))
1498    }
1499}
1500
1501impl NlriCompose for L2VpnVplsNlri {
1502    fn compose_len(&self) -> usize {
1503        self.nlri().compose_len()
1504    }
1505
1506    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
1507        -> Result<(), Target::AppendError> {
1508            self.nlri().compose(target)
1509    }
1510}
1511
1512//--- Evpn
1513
1514#[derive(Clone, Debug, Hash)]
1515#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1516#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1517pub struct L2VpnEvpnNlri<Octs>(EvpnNlri<Octs>);
1518
1519impl<Octs> AfiSafiNlri for L2VpnEvpnNlri<Octs> {
1520    type Nlri = EvpnNlri<Octs>;
1521    fn nlri(&self) -> &Self::Nlri {
1522        &self.0
1523    }
1524}
1525
1526impl<'a, O, P> NlriParse<'a, O, P> for L2VpnEvpnNlri<O>
1527where
1528    O: Octets,
1529    P: 'a + Octets<Range<'a> = O>
1530{
1531    type Output = Self;
1532
1533    fn parse(parser: &mut Parser<'a, P>)
1534        -> Result<Self::Output, ParseError>
1535    {
1536
1537        Ok(Self(EvpnNlri::parse(parser)?))
1538    }
1539}
1540
1541impl<Octs: AsRef<[u8]>> NlriCompose for L2VpnEvpnNlri<Octs> {
1542    fn compose_len(&self) -> usize {
1543        // EPVN uses typed NLRI with embedded the length field 
1544        self.nlri().compose_len()
1545    }
1546
1547    fn compose<Target: OctetsBuilder>(&self, target: &mut Target)
1548        -> Result<(), Target::AppendError> {
1549            self.nlri().compose(target)
1550    }
1551}
1552
1553impl<Octs, Other> PartialEq<L2VpnEvpnNlri<Other>> for L2VpnEvpnNlri<Octs>
1554where Octs: AsRef<[u8]>,
1555      Other: AsRef<[u8]>
1556{
1557    fn eq(&self, other: &L2VpnEvpnNlri<Other>) -> bool {
1558        self.0 == other.0
1559    }
1560}
1561
1562impl<Octs, Other> PartialEq<L2VpnEvpnAddpathNlri<Other>> for L2VpnEvpnAddpathNlri<Octs>
1563where Octs: AsRef<[u8]>,
1564      Other: AsRef<[u8]>
1565{
1566    fn eq(&self, other: &L2VpnEvpnAddpathNlri<Other>) -> bool {
1567        self.0 == other.0
1568    }
1569}
1570
1571impl<Octs> PartialOrd for L2VpnEvpnNlri<Octs>
1572where Octs: AsRef<[u8]>,
1573{
1574    fn partial_cmp(&self, other: &L2VpnEvpnNlri<Octs>) -> Option<cmp::Ordering> {
1575        Some(self.cmp(other))
1576    }
1577}
1578
1579impl<Octs: AsRef<[u8]>> Ord for L2VpnEvpnNlri<Octs> {
1580    fn cmp(&self, other: &Self) -> cmp::Ordering {
1581        self.0.cmp(&other.0)
1582    }
1583}
1584
1585//------------ Iteration ------------------------------------------------------
1586
1587// Iterating over NLRI likely mostly happens when ingesting UPDATE PDUs, i.e.
1588// one or more (possibly >1000) NLRI of one single AfiSafiType. We therefore
1589// want type specific iterators, yielding exact types (e.g. Ipv6UnicastNlri)
1590// instead of the Nlri enum, as that would require the user to match/unpack
1591// every single item returned by next() (which would/should always be of the
1592// same type, anyway).
1593//
1594// For convenience or whatever other use cases, we might still want to provide
1595// an iterator yielding variants of the Nlri enum, probably based on the
1596// type-specific ones.
1597// Because of the From impls generated in the macro call, we can already do:
1598//
1599//     NlriIter::ipv4_mplsunicast(parser).map(Nlri::<_>::from)
1600//
1601// .. to turn a specific iterator into a generic one, returning the Nlri enum
1602// type.
1603//
1604// Seems that creating the convenience constructors involves a lot of typy
1605// typy which could also become part of the afisafi! macro.
1606
1607
1608pub struct NlriIter<'a, O, P, ASP> {
1609    parser: Parser<'a, P>,
1610    asp: std::marker::PhantomData<ASP>,
1611    output: std::marker::PhantomData<O>,
1612}
1613
1614impl<'a, O, P, ASP> NlriIter<'a, O, P, ASP>
1615where
1616    O: Octets,
1617    P: Octets<Range<'a> = O>,
1618    ASP: NlriParse<'a, O, P>
1619{
1620    pub const fn new(parser: Parser<'a, P>) -> Self {
1621        NlriIter {
1622            parser,
1623            asp: std::marker::PhantomData,
1624            output: std::marker::PhantomData
1625        }
1626    }
1627
1628    pub fn afi_safi(&self) -> AfiSafiType {
1629        ASP::Output::afi_safi()
1630    }
1631
1632    pub fn nlri_type(&self) -> NlriType {
1633        ASP::nlri_type()
1634    }
1635
1636    // Validate the entire parser so we can safely return items from this
1637    // iterator, instead of returning Option<Result<Nlri>, ParseError>
1638    //
1639    pub fn validate(&self) -> Result<(), ParseError> {
1640        let mut parser = self.parser;
1641        while parser.remaining() > 0 {
1642            // TODO replace this ::parse with a cheaper ::check, if available
1643            ASP::parse(&mut parser)?;
1644        }
1645        Ok(())
1646    }
1647}
1648
1649
1650impl<'a, O, P, ASP: NlriParse<'a, O, P>> Iterator for NlriIter<'a, O, P, ASP>
1651where 
1652    P: Octets<Range<'a> = O>
1653{
1654    type Item = Result<ASP::Output, ParseError>;
1655
1656    fn next(&mut self) -> Option<Self::Item> {
1657        if self.parser.remaining() == 0 {
1658            return None;
1659        }
1660        Some(ASP::parse(&mut self.parser))
1661    }
1662}
1663
1664/// Generic iterator returning Nlri enum variants instead of specific Nlri
1665/// structs.
1666pub struct NlriEnumIter<'a, P> {
1667    parser: Parser<'a, P>,
1668    ty: NlriType,
1669}
1670
1671impl<'a, P> NlriEnumIter<'a, P> {
1672    pub const fn new(parser: Parser<'a, P>, ty: NlriType) -> Self {
1673        Self { parser, ty }
1674    }
1675
1676    pub const fn nlri_type(&self) -> NlriType {
1677        self.ty
1678    }
1679
1680    pub const fn afi_safi(&self) -> AfiSafiType {
1681        self.ty.afi_safi()
1682    }
1683}
1684
1685impl<'a, O, P> Iterator for NlriEnumIter<'a, P>
1686where 
1687    O: Octets,
1688    P: Octets<Range<'a> = O>,
1689{
1690    type Item = Result<Nlri<O>, ParseError>;
1691
1692    fn next(&mut self) -> Option<Self::Item> {
1693        if self.parser.remaining() == 0 {
1694            return None
1695        }
1696        
1697        let res = match self.ty {
1698            NlriType::Ipv4Unicast => Ipv4UnicastNlri::parse(&mut self.parser).map(Nlri::Ipv4Unicast),
1699            NlriType::Ipv4UnicastAddpath => Ipv4UnicastAddpathNlri::parse(&mut self.parser).map(Nlri::Ipv4UnicastAddpath),
1700            NlriType::Ipv4Multicast => Ipv4MulticastNlri::parse(&mut self.parser).map(Nlri::Ipv4Multicast),
1701            NlriType::Ipv4MulticastAddpath => Ipv4MulticastAddpathNlri::parse(&mut self.parser).map(Nlri::Ipv4MulticastAddpath),
1702            NlriType::Ipv4MplsUnicast => Ipv4MplsUnicastNlri::parse(&mut self.parser).map(Nlri::Ipv4MplsUnicast),
1703            NlriType::Ipv4MplsUnicastAddpath => Ipv4MplsUnicastAddpathNlri::parse(&mut self.parser).map(Nlri::Ipv4MplsUnicastAddpath),
1704            NlriType::Ipv4MplsVpnUnicast => Ipv4MplsVpnUnicastNlri::parse(&mut self.parser).map(Nlri::Ipv4MplsVpnUnicast),
1705            NlriType::Ipv4MplsVpnUnicastAddpath => Ipv4MplsVpnUnicastAddpathNlri::parse(&mut self.parser).map(Nlri::Ipv4MplsVpnUnicastAddpath),
1706            NlriType::Ipv4RouteTarget => Ipv4RouteTargetNlri::parse(&mut self.parser).map(Nlri::Ipv4RouteTarget),
1707            NlriType::Ipv4RouteTargetAddpath => Ipv4RouteTargetAddpathNlri::parse(&mut self.parser).map(Nlri::Ipv4RouteTargetAddpath),
1708            NlriType::Ipv4FlowSpec => Ipv4FlowSpecNlri::parse(&mut self.parser).map(Nlri::Ipv4FlowSpec),
1709            NlriType::Ipv4FlowSpecAddpath => Ipv4FlowSpecAddpathNlri::parse(&mut self.parser).map(Nlri::Ipv4FlowSpecAddpath),
1710            NlriType::Ipv6Unicast => Ipv6UnicastNlri::parse(&mut self.parser).map(Nlri::Ipv6Unicast),
1711            NlriType::Ipv6UnicastAddpath => Ipv6UnicastAddpathNlri::parse(&mut self.parser).map(Nlri::Ipv6UnicastAddpath),
1712            NlriType::Ipv6Multicast => Ipv6MulticastNlri::parse(&mut self.parser).map(Nlri::Ipv6Multicast),
1713            NlriType::Ipv6MulticastAddpath => Ipv6MulticastAddpathNlri::parse(&mut self.parser).map(Nlri::Ipv6MulticastAddpath),
1714            NlriType::Ipv6MplsUnicast => Ipv6MplsUnicastNlri::parse(&mut self.parser).map(Nlri::Ipv6MplsUnicast),
1715            NlriType::Ipv6MplsUnicastAddpath => Ipv6MplsUnicastAddpathNlri::parse(&mut self.parser).map(Nlri::Ipv6MplsUnicastAddpath),
1716            NlriType::Ipv6MplsVpnUnicast => Ipv6MplsVpnUnicastNlri::parse(&mut self.parser).map(Nlri::Ipv6MplsVpnUnicast),
1717            NlriType::Ipv6MplsVpnUnicastAddpath => Ipv6MplsVpnUnicastAddpathNlri::parse(&mut self.parser).map(Nlri::Ipv6MplsVpnUnicastAddpath),
1718            NlriType::Ipv6FlowSpec => Ipv6FlowSpecNlri::parse(&mut self.parser).map(Nlri::Ipv6FlowSpec),
1719            NlriType::Ipv6FlowSpecAddpath => Ipv6FlowSpecAddpathNlri::parse(&mut self.parser).map(Nlri::Ipv6FlowSpecAddpath),
1720            NlriType::L2VpnVpls => L2VpnVplsNlri::parse(&mut self.parser).map(Nlri::L2VpnVpls),
1721            NlriType::L2VpnVplsAddpath => L2VpnVplsAddpathNlri::parse(&mut self.parser).map(Nlri::L2VpnVplsAddpath),
1722            NlriType::L2VpnEvpn => L2VpnEvpnNlri::parse(&mut self.parser).map(Nlri::L2VpnEvpn),
1723            NlriType::L2VpnEvpnAddpath => L2VpnEvpnAddpathNlri::parse(&mut self.parser).map(Nlri::L2VpnEvpnAddpath),
1724            NlriType::Unsupported(..) => { return None; }
1725        };
1726
1727        Some(res)
1728    }
1729}
1730
1731impl<'a, O, P, ASP> From<NlriIter<'a, O, P, ASP>> for NlriEnumIter<'a, P>
1732where 
1733    O: Octets,
1734    ASP: NlriParse<'a, O, P>,
1735    P: Octets<Range<'a> = O>,
1736{
1737    fn from(iter: NlriIter<'a, O, P, ASP>) -> Self {
1738        Self {
1739            parser: iter.parser,
1740            ty: ASP::nlri_type() 
1741        }
1742    }
1743}
1744
1745impl<'a, O, P, ASP: NlriParse<'a, O, P>> NlriIter<'a, O, P, ASP>
1746where
1747    O: Octets,
1748    P: Octets<Range<'a> = O>
1749{
1750    pub fn next_with<T, F: FnOnce(<Self as Iterator>::Item) -> T>(&mut self, fmap: F) -> Option<T> {
1751        self.next().map(fmap)
1752    }
1753}
1754
1755impl<'a, O, P> NlriEnumIter<'a, P>
1756where 
1757    O: Octets,
1758    P: Octets<Range<'a> = O>,
1759{
1760    pub fn next_with<T, F: FnOnce(<Self as Iterator>::Item) -> T>(&mut self, fmap: F) -> Option<T> {
1761        self.next().map(fmap)
1762    }
1763}
1764
1765#[cfg(test)]
1766mod tests {
1767
1768    use super::*;
1769    use inetnum::addr::Prefix;
1770    use std::str::FromStr;
1771
1772    #[test]
1773    fn parse_ipv4unicast() {
1774        let raw = vec![24,1,2,3];
1775        let mut parser = Parser::from_ref(&raw);
1776        let n = Ipv4UnicastNlri::parse(&mut parser).unwrap();
1777
1778        assert_eq!(n.prefix(), Prefix::from_str("1.2.3.0/24").unwrap());
1779    }
1780
1781    #[test]
1782    fn parse_ipv4mplsunicast() {
1783        // Label 8000 10.0.0.9/32
1784        let raw = vec![0x38, 0x01, 0xf4, 0x01, 0x0a, 0x00, 0x00, 0x09];
1785        let mut parser = Parser::from_ref(&raw);
1786        let n = Ipv4MplsUnicastNlri::parse(&mut parser).unwrap();
1787        eprintln!("{}", &n);
1788
1789        let raw = bytes::Bytes::from_static(&[0x38, 0x01, 0xf4, 0x01, 0x0a, 0x00, 0x00, 0x09]);
1790        let mut parser = Parser::from_ref(&raw);
1791        let n2 = Ipv4MplsUnicastNlri::parse(&mut parser).unwrap();
1792        eprintln!("{}", &n2);
1793
1794        assert_eq!(n, n2);
1795
1796        let _n: Nlri<_> = n.into();
1797        let _n2: Nlri<_> = n2.into();
1798    }
1799
1800    #[test]
1801    fn display() {
1802        let p =  Prefix::from_str("1.2.3.0/24").unwrap();
1803        let n: Nlri<()> = Ipv4UnicastNlri(p).into();
1804        assert_eq!(n.to_string(), p.to_string());
1805    }
1806
1807    #[test]
1808    fn iter() {
1809        let raw = vec![
1810            0x38, 0x01, 0xf4, 0x01, 0x0a, 0x00, 0x00, 0x09,
1811            0x38, 0x01, 0xf4, 0x01, 0x0a, 0x00, 0x00, 0x0a,
1812        ];
1813        let parser = Parser::from_ref(&raw);
1814        let iter = NlriIter::ipv4_mplsunicast(parser);
1815        assert_eq!(iter.count(), 2);
1816    }
1817
1818    #[test]
1819    fn iter_generic() {
1820        let mpls_raw = vec![
1821            0x38, 0x01, 0xf4, 0x01, 0x0a, 0x00, 0x00, 0x09,
1822            0x38, 0x01, 0xf4, 0x01, 0x0a, 0x00, 0x00, 0x0a,
1823        ];
1824        let parser = Parser::from_ref(&mpls_raw);
1825        let mpls_iter = NlriIter::ipv4_mplsunicast(parser);
1826
1827        let v4_raw = vec![24, 1, 2, 3];
1828        let parser = Parser::from_ref(&v4_raw);
1829        let v4_iter = NlriIter::ipv4_unicast(parser); 
1830
1831
1832        for n in NlriEnumIter::from(v4_iter)
1833            .chain(NlriEnumIter::from(mpls_iter))
1834        {
1835            dbg!(&n);
1836        }
1837    }
1838
1839    #[test]
1840    fn iter_addpath() {
1841        let raw = vec![
1842            0, 0, 0, 1, 24, 1, 2, 1,
1843            0, 0, 0, 2, 24, 1, 2, 2,
1844            0, 0, 0, 3, 24, 1, 2, 3,
1845            0, 0, 0, 4, 24, 1, 2, 4,
1846        ];
1847
1848        let parser = Parser::from_ref(&raw);
1849        let iter = NlriIter::ipv4_unicast_addpath(parser);
1850        assert_eq!(iter.count(), 4);
1851
1852        let iter = NlriIter::ipv4_unicast_addpath(parser);
1853        for n in iter.map(|e| e.unwrap().prefix()) {
1854            dbg!(&n);
1855        }
1856    }
1857
1858    #[test]
1859    fn iter_addpath_alternative() {
1860        let raw = vec![
1861            0, 0, 0, 1, 24, 1, 2, 1,
1862            0, 0, 0, 2, 24, 1, 2, 2,
1863            0, 0, 0, 3, 24, 1, 2, 3,
1864            0, 0, 0, 4, 24, 1, 2, 4,
1865        ];
1866
1867        let parser = Parser::from_ref(&raw);
1868        let iter = NlriIter::ipv6_unicast_addpath(parser);
1869        //assert_eq!(iter.count(), 4);
1870        for n in iter {
1871            eprintln!("{}", n.unwrap());
1872        }
1873    }
1874
1875    #[test]
1876    fn iter_with() {
1877        let raw = vec![
1878            0, 0, 0, 1, 24, 1, 2, 1,
1879            0, 0, 0, 2, 24, 1, 2, 2,
1880            0, 0, 0, 3, 24, 1, 2, 3,
1881            0, 0, 0, 4, 24, 1, 2, 4,
1882        ];
1883
1884        let parser = Parser::from_ref(&raw);
1885        let iter = NlriIter::ipv6_unicast_addpath(parser);
1886        //while let Some(x) = iter.next_with(|e| format!("IPv6!!!: {:?}", e).to_string()) {
1887        //    dbg!(x);
1888        //}
1889
1890        for x in  iter.map(|e| format!("IPv6!!!: {:?}", e).to_string()) {
1891            dbg!(x);
1892        }
1893
1894    }
1895
1896    #[test]
1897    fn roundtrip_into_from_addpath() {
1898        let raw = vec![
1899            24, 1, 2, 1,
1900            24, 1, 2, 2,
1901            24, 1, 2, 3,
1902            24, 1, 2, 4,
1903        ];
1904
1905        let parser = Parser::from_ref(&raw);
1906        let iter = NlriIter::ipv6_unicast(parser);
1907        for (idx, n) in iter.enumerate() {
1908            dbg!(
1909                Ipv6UnicastNlri::from(
1910                    dbg!(n.unwrap().into_addpath(PathId(idx.try_into().unwrap())))
1911                )
1912            );
1913        }
1914    }
1915
1916}