Skip to content

Commit

Permalink
Merge 7c0d416 into 511efd6
Browse files Browse the repository at this point in the history
  • Loading branch information
bewing committed Feb 14, 2020
2 parents 511efd6 + 7c0d416 commit c278a1b
Show file tree
Hide file tree
Showing 25 changed files with 606 additions and 21 deletions.
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@
METHOD_ALIASES = {
"get_config_filtered": "get_config",
"get_arp_table_with_vrf": "get_arp_table",
"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 @@ -1003,14 +1003,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
18 changes: 18 additions & 0 deletions napalm/base/test/getters.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,24 @@ 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
53 changes: 41 additions & 12 deletions napalm/eos/eos.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,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 @@ -1160,7 +1160,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 @@ -1183,12 +1183,17 @@ 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
"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 @@ -1223,14 +1228,38 @@ 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", {})
Expand Down
5 changes: 4 additions & 1 deletion napalm/ios/ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -2819,7 +2819,7 @@ def _get_bgp_route_attr(self, destination, vrf, next_hop, ip_version=4):
bgp_attr["remote_as"] = napalm.base.helpers.as_number(bgpras)
return bgp_attr

def get_route_to(self, destination="", protocol=""):
def get_route_to(self, destination="", protocol="", longer=False):
"""
Only IPv4 is supported
VRFs are supported
Expand Down Expand Up @@ -2854,6 +2854,9 @@ def get_route_to(self, destination="", protocol=""):
}
"""

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

output = []
# Placeholder for vrf arg
vrf = ""
Expand Down
5 changes: 4 additions & 1 deletion napalm/iosxr/iosxr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1626,13 +1626,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, str):
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 @@ -1600,13 +1600,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, str):
raise TypeError("Please specify a valid destination!")

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

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

Expand Down
4 changes: 3 additions & 1 deletion napalm/nxos_ssh/nxos_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -1317,10 +1317,12 @@ def _get_bgp_route_attr(self, destination, vrf, next_hop, ip_version=4):
bgp_attr["remote_as"] = 0 # 0? , locally sourced
return bgp_attr

def get_route_to(self, destination="", protocol=""):
def get_route_to(self, destination="", protocol="", longer=False):
"""
Only IPv4 supported, vrf aware, longer_prefixes parameter ready
"""
if longer:
raise NotImplementedError("Longer prefixes not yet supported for NXOS")
longer_pref = "" # longer_prefixes support, for future use
vrf = ""

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 @@ -86,12 +86,12 @@ 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 str(excinfo.value)
d.get_route_to(1, 2, 3, 4)
assert "get_route_to: expected at most 4 arguments, got 5" in str(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 str(excinfo.value)
d.get_route_to(1, 1, 1, protocol=2)
assert "get_route_to: expected at most 4 arguments, got 4" in str(excinfo.value)

with pytest.raises(TypeError) as excinfo:
d.get_route_to(proto=2)
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
}
}
}
Loading

0 comments on commit c278a1b

Please sign in to comment.