Skip to main content

bgpkit_parser/parser/iters/
default.rs

1/*!
2Default iterator implementations that skip errors and return successfully parsed items.
3*/
4use crate::error::ParserError;
5use crate::models::*;
6use crate::parser::iters::{record_matches_filters, write_mrt_core_dump};
7use crate::parser::BgpkitParser;
8use crate::{Elementor, Filterable};
9use log::{error, warn};
10use std::io::Read;
11
12/*********
13MrtRecord Iterator
14**********/
15
16pub struct RecordIterator<R> {
17    pub parser: BgpkitParser<R>,
18    pub count: u64,
19    elementor: Elementor,
20}
21
22impl<R> RecordIterator<R> {
23    pub(crate) fn new(parser: BgpkitParser<R>) -> Self {
24        RecordIterator {
25            parser,
26            count: 0,
27            elementor: Elementor::new(),
28        }
29    }
30}
31
32impl<R: Read> Iterator for RecordIterator<R> {
33    type Item = MrtRecord;
34
35    fn next(&mut self) -> Option<MrtRecord> {
36        // Text-dump parsers have no MRT-record representation; short-circuit
37        // instead of spinning forever on Unsupported errors from next_record().
38        if self.parser.text_dump_iter.is_some() {
39            return None;
40        }
41        self.count += 1;
42        loop {
43            return match self.parser.next_record() {
44                Ok(v) => {
45                    if record_matches_filters(&v, &self.parser.filters, &mut self.elementor) {
46                        Some(v)
47                    } else {
48                        continue;
49                    }
50                }
51                Err(e) => {
52                    match e.error {
53                        ParserError::TruncatedMsg(err_str) | ParserError::Unsupported(err_str) => {
54                            if self.parser.options.show_warnings {
55                                warn!("parser warn: {}", err_str);
56                            }
57                            write_mrt_core_dump(self.parser.core_dump, e.bytes);
58                            continue;
59                        }
60                        ParserError::ParseError(err_str) => {
61                            error!("parser error: {}", err_str);
62                            write_mrt_core_dump(self.parser.core_dump, e.bytes);
63                            if self.parser.core_dump {
64                                None
65                            } else {
66                                continue;
67                            }
68                        }
69                        ParserError::EofExpected => {
70                            // normal end of file
71                            None
72                        }
73                        ParserError::IoError(err) | ParserError::EofError(err) => {
74                            // when reaching IO error, stop iterating
75                            error!("{:?}", err);
76                            write_mrt_core_dump(self.parser.core_dump, e.bytes);
77                            None
78                        }
79                        #[cfg(feature = "oneio")]
80                        ParserError::OneIoError(_) => None,
81                        ParserError::FilterError(_) => {
82                            // this should not happen at this stage
83                            None
84                        }
85                        // Labeled NLRI parsing errors - treat as malformed and skip
86                        ParserError::InvalidLabeledNlriLength
87                        | ParserError::TruncatedLabeledNlri
88                        | ParserError::TruncatedPrefix
89                        | ParserError::MaxLabelStackDepthExceeded
90                        | ParserError::PeerMaxLabelsExceeded
91                        | ParserError::InvalidPrefix => {
92                            if self.parser.options.show_warnings {
93                                warn!("parser warn: labeled NLRI parsing error: {:?}", e.error);
94                            }
95                            continue;
96                        }
97                    }
98                }
99            };
100        }
101    }
102}
103
104/*********
105BgpElem Iterator
106**********/
107
108pub struct ElemIterator<R> {
109    cache_elems: Vec<BgpElem>,
110    record_iter: RecordIterator<R>,
111    elementor: Elementor,
112    count: u64,
113}
114
115impl<R> ElemIterator<R> {
116    pub(crate) fn new(parser: BgpkitParser<R>) -> Self {
117        ElemIterator {
118            record_iter: RecordIterator::new(parser),
119            count: 0,
120            cache_elems: vec![],
121            elementor: Elementor::new(),
122        }
123    }
124}
125
126impl<R: Read> Iterator for ElemIterator<R> {
127    type Item = BgpElem;
128
129    fn next(&mut self) -> Option<BgpElem> {
130        self.count += 1;
131
132        loop {
133            // Fast path: drain streaming text-dump elems directly, with filter support.
134            if let Some(iter) = &mut self.record_iter.parser.text_dump_iter {
135                for elem in iter.by_ref() {
136                    if elem.match_filters(&self.record_iter.parser.filters) {
137                        return Some(elem);
138                    }
139                }
140                return None;
141            }
142
143            if self.cache_elems.is_empty() {
144                // refill cache elems
145                loop {
146                    match self.record_iter.next() {
147                        None => {
148                            // no more records
149                            return None;
150                        }
151                        Some(r) => {
152                            let mut elems = self.elementor.record_to_elems(r);
153                            if elems.is_empty() {
154                                // somehow this record does not contain any elems, continue to parse next record
155                                continue;
156                            } else {
157                                elems.reverse();
158                                self.cache_elems = elems;
159                                break;
160                            }
161                        }
162                    }
163                }
164                // when reaching here, the `self.cache_elems` has been refilled with some more elems
165            }
166
167            // popping cached elems. note that the original elems order is preseved by reversing the
168            // vector before putting it on to cache_elems.
169            let elem = self.cache_elems.pop()?;
170            if elem.match_filters(&self.record_iter.parser.filters) {
171                return Some(elem);
172            }
173        }
174    }
175}