Skip to content

Commit

Permalink
Merge e3a424c into 45aabaf
Browse files Browse the repository at this point in the history
  • Loading branch information
bewing committed Sep 18, 2018
2 parents 45aabaf + e3a424c commit cf62f5c
Show file tree
Hide file tree
Showing 23 changed files with 610 additions and 25 deletions.
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@

METHOD_ALIASES = {
'get_config_filtered': 'get_config',
'get_route_to_longer': 'get_route_to',
}


Expand Down
3 changes: 2 additions & 1 deletion napalm/base/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -966,14 +966,15 @@ def get_mac_address_table(self):
"""
raise NotImplementedError

def get_route_to(self, destination='', protocol=''):
def get_route_to(self, destination='', protocol='', longer=False):

"""
Returns a dictionary of dictionaries containing details of all available routes to a
destination.
:param destination: The destination prefix to be used when filtering the routes.
:param protocol (optional): Retrieve the routes only for a specific protocol.
:param longer (optional): Retrieve more specific routes as well.
Each inner dictionary contains the following fields:
Expand Down
16 changes: 16 additions & 0 deletions napalm/base/test/getters.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,22 @@ def test_get_route_to(self, test_case):

return get_route_to

@wrap_test_cases
def test_get_route_to_longer(self, test_case):
"""Test get_route_to with longer=True"""
destination = '1.0.4.0/24'
protocol = 'bgp'

get_route_to = self.device.get_route_to(destination=destination, protocol=protocol, longer=True)

assert len(get_route_to) > 0

for prefix, routes in get_route_to.items():
for route in routes:
assert helpers.test_model(models.route, route)

return get_route_to

@wrap_test_cases
def test_get_snmp_information(self, test_case):
"""Test get_snmp_information."""
Expand Down
69 changes: 51 additions & 18 deletions napalm/eos/eos.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

# third party libs
import pyeapi
from pyeapi.eapilib import ConnectionError
from pyeapi.eapilib import ConnectionError, CommandError

# NAPALM base
import napalm.base.helpers
Expand Down Expand Up @@ -1051,7 +1051,7 @@ def get_mac_address_table(self):

return mac_table

def get_route_to(self, destination='', protocol=''):
def get_route_to(self, destination='', protocol='', longer=False):
routes = {}

# Placeholder for vrf arg
Expand All @@ -1076,14 +1076,18 @@ def get_route_to(self, destination='', protocol=''):

commands = []
for _vrf in vrfs:
commands.append('show ip{ipv} route vrf {_vrf} {destination} {protocol} detail'.format(
ipv=ipv,
_vrf=_vrf,
destination=destination,
protocol=protocol,
))
commands.append(
'show ip{ipv} route vrf {_vrf} {destination} {longer} {protocol} detail'.format(
ipv=ipv,
_vrf=_vrf,
destination=destination,
longer='longer-prefixes' if longer else '',
protocol=protocol,
),
)

commands_output = self.device.run_commands(commands)
vrf_cache = {}

for _vrf, command_output in zip(vrfs, commands_output):
if ipv == 'v6':
Expand Down Expand Up @@ -1116,22 +1120,51 @@ def get_route_to(self, destination='', protocol=''):
nexthop_ip = napalm.base.helpers.ip(next_hop.get('nexthopAddr'))
nexthop_interface_map[nexthop_ip] = next_hop.get('interface')
metric = route_details.get('metric')
command = 'show ip{ipv} bgp {destination} detail vrf {_vrf}'.format(
ipv=ipv,
destination=prefix,
_vrf=_vrf
)
vrf_details = self.device.run_commands([command])[0].get(
'vrfs', {}).get(_vrf, {})
if _vrf not in vrf_cache.keys():
try:
command = 'show ip{ipv} bgp {dest} {longer} detail vrf {_vrf}'.format(
ipv=ipv,
dest=destination,
longer='longer-prefixes' if longer else '',
_vrf=_vrf
)
vrf_cache.update(
{
_vrf: self.device.run_commands(
[command]
)[0].get('vrfs', {}).get(_vrf, {}),
}
)
except CommandError:
# Newer EOS can't mix longer-prefix and detail
command = 'show ip{ipv} bgp {dest} {longer} vrf {_vrf}'.format(
ipv=ipv,
dest=destination,
longer='longer-prefixes' if longer else '',
_vrf=_vrf
)
vrf_cache.update(
{
_vrf: self.device.run_commands(
[command]
)[0].get('vrfs', {}).get(_vrf, {}),
}
)

vrf_details = vrf_cache.get(_vrf)
local_as = vrf_details.get('asn')
bgp_routes = vrf_details.get(
'bgpRouteEntries', {}).get(prefix, {}).get('bgpRoutePaths', [])
for bgp_route_details in bgp_routes:
bgp_route = route.copy()
as_path = bgp_route_details.get('asPathEntry', {}).get('asPath', u'')
remote_as = int(as_path.strip("()").split()[-1])
remote_address = napalm.base.helpers.ip(bgp_route_details.get(
'routeDetail', {}).get('peerEntry', {}).get('peerAddr', ''))
stripped_path = as_path.translate({ord(c): None for c in "()ie?"})
remote_as = int(stripped_path.split()[-1])
try:
remote_address = napalm.base.helpers.ip(bgp_route_details.get(
'routeDetail', {}).get('peerEntry', {}).get('peerAddr', ''))
except AddrFormatError:
remote_address = None
local_preference = bgp_route_details.get('localPreference')
next_hop = napalm.base.helpers.ip(bgp_route_details.get('nextHop'))
active_route = bgp_route_details.get('routeType', {}).get('active', False)
Expand Down
5 changes: 4 additions & 1 deletion napalm/iosxr/iosxr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1291,13 +1291,16 @@ def get_mac_address_table(self):

return mac_table

def get_route_to(self, destination='', protocol=''):
def get_route_to(self, destination='', protocol='', longer=False):

routes = {}

if not isinstance(destination, py23_compat.string_types):
raise TypeError('Please specify a valid destination!')

if longer:
raise NotImplementedError("Longer prefixes not yet supported for IOS-XR")

protocol = protocol.lower()
if protocol == 'direct':
protocol = 'connected'
Expand Down
5 changes: 4 additions & 1 deletion napalm/junos/junos.py
Original file line number Diff line number Diff line change
Expand Up @@ -1534,13 +1534,16 @@ def get_mac_address_table(self):

return mac_address_table

def get_route_to(self, destination='', protocol=''):
def get_route_to(self, destination='', protocol='', longer=False):
"""Return route details to a specific destination, learned from a certain protocol."""
routes = {}

if not isinstance(destination, py23_compat.string_types):
raise TypeError('Please specify a valid destination!')

if longer:
raise NotImplementedError("Longer prefixes not yet supported on JunOS")

if protocol and isinstance(destination, py23_compat.string_types):
protocol = protocol.lower()

Expand Down
8 changes: 4 additions & 4 deletions test/base/test_mock_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ def test_arguments(self):
d.open()

with pytest.raises(TypeError) as excinfo:
d.get_route_to(1, 2, 3)
assert "get_route_to: expected at most 3 arguments, got 4" in py23_compat.text_type(
d.get_route_to(1, 2, 3, 4)
assert "get_route_to: expected at most 4 arguments, got 5" in py23_compat.text_type(
excinfo.value)

with pytest.raises(TypeError) as excinfo:
d.get_route_to(1, 1, protocol=2)
assert "get_route_to: expected at most 3 arguments, got 3" in py23_compat.text_type(
d.get_route_to(1, 1, 1, protocol=2)
assert "get_route_to: expected at most 4 arguments, got 4" in py23_compat.text_type(
excinfo.value)

with pytest.raises(TypeError) as excinfo:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"1.0.4.0/25": [{"next_hop": "192.168.0.1", "preference": 200, "protocol": "eBGP", "selected_next_hop": true, "current_active": true, "routing_table": "TEST", "protocol_attributes": {"remote_as": 43515, "as_path": "1299 15169 43515", "local_preference": 50, "remote_address": "192.168.0.1", "preference2": 0, "metric": 0, "communities": ["1299:1234", "1299:5678", "1299:91011", "1299:12134"], "local_as": 13335}, "outgoing_interface": "Port-Channel2", "last_active": true, "inactive_reason": "", "age": 0}, {"next_hop": "192.168.0.1", "preference": 200, "protocol": "eBGP", "selected_next_hop": true, "current_active": true, "routing_table": "default", "protocol_attributes": {"remote_as": 43515, "as_path": "1299 15169 43515", "local_preference": 50, "remote_address": "192.168.0.1", "preference2": 0, "metric": 0, "communities": ["1299:1234", "1299:5678", "1299:91011", "1299:12134"], "local_as": 13335}, "outgoing_interface": "Port-Channel2", "last_active": true, "inactive_reason": "", "age": 0}], "1.0.4.128/25": [{"next_hop": "192.168.0.5", "preference": 200, "protocol": "eBGP", "selected_next_hop": true, "current_active": true, "routing_table": "TEST", "protocol_attributes": {"remote_as": 43515, "as_path": "1299 15169 43515", "local_preference": 50, "remote_address": "192.168.0.5", "preference2": 0, "metric": 0, "communities": ["1299:1234", "1299:5678", "1299:91011", "1299:12134"], "local_as": 13335}, "outgoing_interface": "Port-Channel1", "last_active": true, "inactive_reason": "", "age": 0}, {"next_hop": "192.168.0.5", "preference": 200, "protocol": "eBGP", "selected_next_hop": true, "current_active": true, "routing_table": "default", "protocol_attributes": {"remote_as": 43515, "as_path": "1299 15169 43515", "local_preference": 50, "remote_address": "192.168.0.5", "preference2": 0, "metric": 0, "communities": ["1299:1234", "1299:5678", "1299:91011", "1299:12134"], "local_as": 13335}, "outgoing_interface": "Port-Channel1", "last_active": true, "inactive_reason": "", "age": 0}]}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"vrfs": {
"TEST": {
"routerId": "192.168.256.1",
"vrf": "default",
"bgpRouteEntries": {
"1.0.4.0/25": {
"totalPaths": 1,
"bgpAdvertisedPeerGroups": {},
"totalAdvertisedPeers": 0,
"maskLength": 20,
"bgpRoutePaths": [
{
"asPathEntry": {
"asPathType": "External",
"asPath": "1299 15169 43515"
},
"med": 0,
"localPreference": 50,
"weight": 0,
"nextHop": "192.168.0.1",
"routeType": {
"atomicAggregator": false,
"valid": true,
"ecmpContributor": false,
"active": true,
"backup": false,
"stale": false,
"suppressed": false,
"ecmpHead": false,
"queued": false,
"ecmp": false
},
"routeDetail": {
"origin": "Igp",
"peerEntry": {
"peerRouterId": "192.168.256.1",
"peerAddr": "192.168.0.1"
},
"extCommunityList": [],
"communityList": [
"1299:1234",
"1299:5678",
"1299:91011",
"1299:12134"
],
"recvdFromRRClient": false
}
}
],
"address": "1.0.4.0"
},
"1.0.4.128/25": {
"totalPaths": 1,
"bgpAdvertisedPeerGroups": {},
"totalAdvertisedPeers": 0,
"maskLength": 20,
"bgpRoutePaths": [
{
"asPathEntry": {
"asPathType": "External",
"asPath": "1299 15169 43515"
},
"med": 0,
"localPreference": 50,
"weight": 0,
"nextHop": "192.168.0.5",
"routeType": {
"atomicAggregator": false,
"valid": true,
"ecmpContributor": false,
"active": true,
"backup": false,
"stale": false,
"suppressed": false,
"ecmpHead": false,
"queued": false,
"ecmp": false
},
"routeDetail": {
"origin": "Igp",
"peerEntry": {
"peerRouterId": "192.168.256.1",
"peerAddr": "192.168.0.5"
},
"extCommunityList": [],
"communityList": [
"1299:1234",
"1299:5678",
"1299:91011",
"1299:12134"
],
"recvdFromRRClient": false
}
}
],
"address": "1.0.4.128"
}
},
"asn": 13335
}
}
}

0 comments on commit cf62f5c

Please sign in to comment.