Skip to content

Commit 11799c8

Browse files
committed
Merge pull request #141 from tehhobbit/bgp_fix
Changes to get_bgp_neighbors for eos
2 parents e6c250a + 1f9b250 commit 11799c8

8 files changed

+175
-275
lines changed

napalm/eos.py

Lines changed: 118 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -232,92 +232,126 @@ def get_interfaces_counters(self):
232232

233233
return interface_counters
234234

235+
@staticmethod
236+
def _parse_neigbor_info(line):
237+
m = re.match('BGP neighbor is (?P<neighbor>.*?), remote AS (?P<as>.*?), .*', line)
238+
return m.group('neighbor'), m.group('as')
239+
240+
@staticmethod
241+
def _parse_rid_info(line):
242+
m = re.match('.*BGP version 4, remote router ID (?P<rid>.*?), VRF (?P<vrf>.*?)$', line)
243+
return m.group('rid'), m.group('vrf')
244+
245+
@staticmethod
246+
def _parse_desc(line):
247+
m = re.match('\s+Description: (?P<description>.*?)', line)
248+
if m:
249+
return m.group('description')
250+
else:
251+
return None
252+
253+
@staticmethod
254+
def _parse_local_info(line):
255+
m = re.match('Local AS is (?P<as>.*?),.*', line)
256+
return m.group('as')
257+
258+
@staticmethod
259+
def _parse_prefix_info(line):
260+
m = re.match('(\s*?)(?P<af>IPv[46]) Unicast:\s*(?P<sent>\d+)\s*(?P<received>\d+)', line)
261+
return m.group('sent'), m.group('received')
262+
235263
def get_bgp_neighbors(self):
264+
NEIGHBOR_FILTER = 'bgp neighbors vrf all | include remote AS | remote router ID |^\s*IPv[46] Unicast:.*[0-9]+|^Local AS|Desc'
265+
output_summary_cmds = self.device.run_commands(
266+
['show ipv6 bgp summary vrf all', 'show ip bgp summary vrf all'],
267+
encoding='json')
268+
output_neighbor_cmds = self.device.run_commands(
269+
['show ip ' + NEIGHBOR_FILTER, 'show ipv6 ' + NEIGHBOR_FILTER],
270+
encoding='text')
271+
272+
bgp_counters = defaultdict(lambda: dict(peers=dict()))
273+
for summary in output_summary_cmds:
274+
"""
275+
Json output looks as follows
276+
"vrfs": {
277+
"default": {
278+
"routerId": 1,
279+
"asn": 1,
280+
"peers": {
281+
"1.1.1.1": {
282+
"msgSent": 1,
283+
"inMsgQueue": 0,
284+
"prefixReceived": 3926,
285+
"upDownTime": 1449501378.418644,
286+
"version": 4,
287+
"msgReceived": 59616,
288+
"prefixAccepted": 3926,
289+
"peerState": "Established",
290+
"outMsgQueue": 0,
291+
"underMaintenance": false,
292+
"asn": 1
293+
}
294+
}
295+
}
296+
}
297+
"""
298+
for vrf, vrf_data in summary['vrfs'].iteritems():
299+
bgp_counters[vrf]['router_id'] = vrf_data['routerId']
300+
for peer, peer_data in vrf_data['peers'].iteritems():
301+
peer_info = {
302+
'is_up': peer_data['peerState'] == 'Established',
303+
'is_enabled': peer_data['peerState'] == 'Established' or peer_data['peerState'] == 'Active',
304+
'uptime': int(peer_data['upDownTime'])
305+
}
306+
bgp_counters[vrf]['peers'][peer] = peer_info
307+
lines = []
308+
[lines.extend(x['output'].splitlines()) for x in output_neighbor_cmds]
309+
for line in lines:
310+
"""
311+
Raw output from the command looks like the following:
312+
313+
BGP neighbor is 1.1.1.1, remote AS 1, external link
314+
Description: Very info such descriptive
315+
BGP version 4, remote router ID 1.1.1.1, VRF my_vrf
316+
IPv4 Unicast: 683 78
317+
IPv6 Unicast: 0 0
318+
Local AS is 2, local router ID 2.2.2.2
319+
"""
320+
if line is '':
321+
continue
322+
neighbor, r_as = self._parse_neigbor_info(lines.pop(0))
323+
# this line can be either description or rid info
324+
next_line = lines.pop(0)
325+
desc = self._parse_desc(next_line)
326+
if desc is None:
327+
rid, vrf = self._parse_rid_info(next_line)
328+
desc = ''
329+
else:
330+
rid, vrf = self._parse_rid_info(lines.pop(0))
331+
332+
v4_sent, v4_recv = self._parse_prefix_info(lines.pop(0))
333+
v6_sent, v6_recv = self._parse_prefix_info(lines.pop(0))
334+
local_as = self._parse_local_info(lines.pop(0))
335+
data = {
336+
'remote_as': int(r_as),
337+
'remote_id': unicode(rid),
338+
'local_as': int(local_as),
339+
'description': unicode(desc),
340+
'address_family': {
341+
'ipv4': {
342+
'sent_prefixes': int(v4_sent),
343+
'received_prefixes': int(v4_recv),
344+
'accepted_prefixes': -1
345+
},
346+
'ipv6': {
347+
'sent_prefixes': int(v6_sent),
348+
'received_prefixes': int(v6_recv),
349+
'accepted_prefixes': -1
350+
}
351+
}
352+
}
353+
bgp_counters[vrf]['peers'][neighbor].update(data)
236354

237-
commands_json = list()
238-
commands_txt = list()
239-
commands_json.append('show ip bgp summary vrf all')
240-
commands_json.append('show ipv6 bgp summary vrf all')
241-
commands_txt.append('show ip bgp neighbors vrf all | include remote AS|remote router ID|Description|^ *IPv[4-6] Unicast:')
242-
commands_txt.append('show ipv6 bgp neighbors vrf all | include remote AS|remote router ID|Description|^ *IPv[4-6] Unicast:')
243-
244-
output_summary = self.device.run_commands(commands_json, encoding='json')
245-
output_neighbors = self.device.run_commands(commands_txt, encoding='text')
246-
247-
##########################################
248-
# no JSON available for show ip bgp neigh
249-
# Using 'show ipv[4-6] bgp neighbors vrf all | i remote AS|remote router ID|Description|^ *IPv[4-6] Unicast:'
250-
# NOTE: if there is no description, EOS does not print the line.
251-
252-
253-
# Regex the output from show ip bgp neigh
254-
def get_bgp_neighbor(needed_peer, vrf, output_to_parse):
255-
import re
256-
257-
bgp_neighbors = dict()
258-
bgp_peer = dict()
259-
neighbor_regexp = re.compile('BGP neighbor is (.*?),')
260-
description_regexp = re.compile('Description: (.*?)$')
261-
remote_id_regexp = re.compile('remote router ID (.*?),')
262-
vrf_regexp = re.compile('VRF (.*?)$')
263-
IPv4_sent_regexp = re.compile('IPv4 Unicast: ( *)(\d*) ')
264-
IPv6_sent_regexp = re.compile('IPv6 Unicast: ( *)(\d*) ')
265-
266-
for line in output_to_parse.splitlines():
267-
if re.search(neighbor_regexp, line):
268-
peer = re.search(neighbor_regexp, line).group(1)
269-
bgp_neighbors[peer] = dict()
270-
bgp_neighbors[peer]['description'] = ''
271-
continue
272-
elif re.search(description_regexp, line):
273-
bgp_neighbors[peer]['description'] = re.search(description_regexp, line).group(1)
274-
continue
275-
elif re.search(remote_id_regexp, line):
276-
bgp_neighbors[peer]['remote_id'] = re.search(remote_id_regexp, line).group(1)
277-
bgp_neighbors[peer]['vrf'] = re.search(vrf_regexp, line).group(1)
278-
continue
279-
elif re.search(IPv4_sent_regexp, line):
280-
bgp_neighbors[peer]['ipv4'] = re.search(IPv4_sent_regexp, line).group(2)
281-
continue
282-
elif re.search(IPv6_sent_regexp, line):
283-
bgp_neighbors[peer]['ipv6'] = re.search(IPv6_sent_regexp, line).group(2)
284-
continue
285-
try:
286-
peer = next(peer for peer in bgp_neighbors if peer == needed_peer)
287-
except StopIteration:
288-
raise Exception("Peer %s not found in show bgp neighbors" % needed_peer)
289-
if bgp_neighbors[peer]['vrf'] == vrf:
290-
bgp_peer['remote_id'] = bgp_neighbors[peer]['remote_id']
291-
bgp_peer['description'] = bgp_neighbors[peer]['description']
292-
bgp_peer['ipv4'] = bgp_neighbors[peer]['ipv4']
293-
bgp_peer['ipv6'] = bgp_neighbors[peer]['ipv6']
294-
return bgp_peer
295-
296-
bgp_counters = defaultdict(dict)
297-
for output_id in [0, 1]:
298-
for vrf in output_summary[output_id]['vrfs']:
299-
bgp_counters[vrf]['router_id'] = unicode(output_summary[output_id]['vrfs'][vrf]['routerId'])
300-
bgp_counters[vrf]['peers'] = dict()
301-
for peer in output_summary[output_id]['vrfs'][vrf]['peers']:
302-
bgp_counters[vrf]['peers'][peer] = dict()
303-
bgp_counters[vrf]['peers'][peer]['local_as'] = int(output_summary[output_id]['vrfs'][vrf]['asn'])
304-
bgp_counters[vrf]['peers'][peer]['remote_as'] = int(output_summary[output_id]['vrfs'][vrf]['peers'][peer]['asn'])
305-
peerState = output_summary[output_id]['vrfs'][vrf]['peers'][peer]['peerState']
306-
bgp_counters[vrf]['peers'][peer]['is_up'] = peerState == 'Established'
307-
if 'peerStateIdleReason' in output_summary[output_id]['vrfs'][vrf]['peers'][peer]:
308-
bgp_counters[vrf]['peers'][peer]['is_enabled'] = False
309-
else:
310-
bgp_counters[vrf]['peers'][peer]['is_enabled'] = peerState == 'Established' or peerState == 'Active'
311-
bgp_counters[vrf]['peers'][peer]['uptime'] = int(output_summary[output_id]['vrfs'][vrf]['peers'][peer]['upDownTime'])
312-
bgp_peer = get_bgp_neighbor(peer, vrf, output_neighbors[output_id]['output'])
313-
bgp_counters[vrf]['peers'][peer]['remote_id'] = unicode(bgp_peer['remote_id'])
314-
bgp_counters[vrf]['peers'][peer]['description'] = unicode(bgp_peer['description'])
315-
bgp_counters[vrf]['peers'][peer]['address_family'] = dict()
316-
for family in ['ipv4', 'ipv6']:
317-
bgp_counters[vrf]['peers'][peer]['address_family'][family] = dict()
318-
bgp_counters[vrf]['peers'][peer]['address_family'][family]['received_prefixes'] = int(output_summary[output_id]['vrfs'][vrf]['peers'][peer]['prefixReceived'])
319-
bgp_counters[vrf]['peers'][peer]['address_family'][family]['accepted_prefixes'] = int(output_summary[output_id]['vrfs'][vrf]['peers'][peer]['prefixAccepted'])
320-
bgp_counters[vrf]['peers'][peer]['address_family'][family]['sent_prefixes'] = int(bgp_peer[family])
321355
if 'default' in bgp_counters.keys():
322356
bgp_counters['global'] = bgp_counters.pop('default')
323357
return bgp_counters

test/unit/TestEOSDriver.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from napalm import eos
1818
from base import TestConfigNetworkDriver, TestGettersNetworkDriver
1919
import json
20+
import re
2021

2122

2223
class TestConfigEOSDriver(unittest.TestCase, TestConfigNetworkDriver):
@@ -72,6 +73,7 @@ def run_commands(self, command_list, encoding='json'):
7273
if encoding == 'json':
7374
result.append(self.read_json_file('eos/mock_data/{}.json'.format(command.replace(' ', '_'))))
7475
else:
75-
result.append({'output': self.read_txt_file('eos/mock_data/{}.txt'.format(command.replace(' ', '_')))})
76+
cmd = re.sub(r'[\[\]\*\^\+\s\|]', '_', command)
77+
result.append({'output': self.read_txt_file('eos/mock_data/{}.txt'.format(cmd))})
7678

7779
return result
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
BGP neighbor is 192.168.56.2, remote AS 65002, external link
2+
BGP version 4, remote router ID 192.168.56.2, VRF default
3+
IPv4 Unicast: 0 0
4+
IPv6 Unicast: 0 0
5+
Local AS is 65001, local router ID 192.168.56.3
6+
BGP neighbor is 192.168.56.4, remote AS 65001, external link
7+
BGP version 4, remote router ID 192.168.56.3, VRF default
8+
IPv4 Unicast: 0 0
9+
IPv6 Unicast: 0 0
10+
Local AS is 65002, local router ID 192.168.56.2

test/unit/eos/mock_data/show_ip_bgp_neighbors_vrf_all_|_include_remote_AS|remote_router_ID|Description|^_*IPv[4-6]_Unicast:.txt

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)