diff --git a/pybird/__init__.py b/pybird/__init__.py index 69d2c93..3436c4b 100644 --- a/pybird/__init__.py +++ b/pybird/__init__.py @@ -457,6 +457,89 @@ def _parse_peer_data(self, data, data_contains_detail): return peers + def get_rpki_status(self, peer_name=None): + """Get the status of all peers or a specific peer. + + Optional argument: peer_name: case-sensitive full name of a peer, + as configured in BIRD. + + If no argument is given, returns a list of peers - each peer represented + by a dict with fields. See README for a full list. + + If a peer_name argument is given, returns a single peer, represented + as a dict. If the peer is not found, returns a zero length array. + """ + if peer_name: + query = 'show protocols all "%s"' % self._clean_input(peer_name) + else: + query = "show protocols all" + + data = self._send_query(query) + if not self.socket_file: + return data + + peers = self._parse_rpki_data(data=data, data_contains_detail=True) + + if not peer_name: + return peers + + if len(peers) == 0: + return [] + elif len(peers) > 1: + raise ValueError( + "Searched for a specific peer, but got multiple returned from BIRD?" + ) + else: + return peers[0] + + def _parse_rpki_data(self, data, data_contains_detail): + """Parse the data from BIRD to find peer information.""" + lineiterator = iter(data.splitlines()) + peers = [] + + peer_summary = None + + for line in lineiterator: + line = line.strip() + (field_number, line) = self._extract_field_number(line) + + if field_number in self.ignored_field_numbers: + continue + + if field_number == 1002: + peer_summary = self._parse_peer_summary(line) + if peer_summary["protocol"] != "RPKI": + peer_summary = None + continue + + # If there is no detail section to be expected, + # we are done. + if not data_contains_detail: + peers.append_peer_summary() + continue + + peer_detail = None + if field_number == 1006: + if not peer_summary: + # This is not detail of a BGP peer + continue + + # A peer summary spans multiple lines, read them all + peer_detail_raw = [] + while line.strip() != "": + peer_detail_raw.append(line) + line = next(lineiterator) + + peer_detail = self._parse_peer_detail(peer_detail_raw) + + # Save the summary+detail info in our result + peer_detail.update(peer_summary) + peers.append(peer_detail) + # Do not use this summary again on the next run + peer_summary = None + + return peers + def _parse_peer_summary(self, line): """Parse the summary of a peer line, like: PS1 BGP T_PS1 start Jun13 Passive