napalm-automation / napalm

Network Automation and Programmability Abstraction Layer with Multivendor support
Apache License 2.0
2.24k stars 551 forks source link

Some IOS devices don't support ttl and timeout traceroute arguments #450

Open mirceaulinic opened 6 years ago

mirceaulinic commented 6 years ago

Description of Issue/Question

napalm-ios version

(Paste verbatim output from pip freeze | grep napalm-ios between quotes below)

napalm-ios==0.5.0

IOS version

(Paste verbatim output from show version between quotes below)

Cisco IOS Software, IOS-XE Software, Catalyst L3 Switch Software (CAT3K_CAA-UNIVERSALK9-M), Version 03.06.04.E RELEASE SOFTWARE (fc2)

Steps to Reproduce the Issue

On at least this version of IOS, traceroute doesn't support the ttl and timeout arguments:

#traceroute ?                    
  WORD       Trace route to destination address or hostname
  appletalk  AppleTalk Trace
  clns       ISO CLNS Trace
  ip         IP Trace
  ipv6       IPv6 Trace
  ipx        IPX Trace
  mac        Trace Layer2 path between 2 endpoints
  oldvines   Vines Trace (Cisco)
  vines      Vines Trace (Banyan)
  vrf        Select VPN routing instance
  <cr>

But napalm sets defaults at: TRACEROUTE_TTL = 255 and TRACEROUTE_TIMEOUT = 2 in constants.py. So even if the user doesn't set any ttl or timeout, it will add them to the command, resulting in an issue:

>> device.traceroute(destination='8.8.8.8')
Command ran on the device
traceroute 8.8.8.8 ttl 0 255 timeout 2
Which is not supported:
#traceroute 8.8.8.8 ttl 0 255 timeout 2
                                      ^
% Invalid input detected at '^' marker.
(note that the marker point at the "ttl" term)

Issue moved from https://github.com/napalm-automation/napalm-ios/issues/101

brandomando commented 5 years ago

As a workaround if the extended commands are required, there is the option to use extended traceroute:

LABSWI01#traceroute
Protocol [ip]:
Target IP address: 8.8.8.8
Source address:
Numeric display [n]:
Timeout in seconds [3]:
Probe count [3]:
Minimum Time to Live [1]:
Maximum Time to Live [30]:
Port Number [33434]:
Loose, Strict, Record, Timestamp, Verbose[none]:

This could be handled using Netmiko expect_string arguments for the ':' prompts for the extended commands. I was able to make this work on a handful of devices in the lab using the following:

        def _get_command(output):
            output = output.split('\n')[-1]

            if re.search("Protocol", output):
                command = "\n"

            elif re.search("Target IP", output):
                command = f"{destination}\n"

            elif re.search("Source", output):
                command = f"{source}\n"

            elif re.search("Numeric", output):
                command = "\n"

            elif re.search("Timeout", output):
                command = f"{str(timeout)}\n"

            elif re.search("Probe count", output):
                command = f"\n"

            elif re.search("Minimum Time to Live", output):
                command = "\n"

            elif re.search("Maximum Time to Live", output):
                command = f"{ttl}\n"

            elif re.search("Port Number", output):
                command = "\n"

            elif re.search("Loose, Strict", output):
                command = "\n"

            return command

        if vrf:
            output = self.device.send_command(f"traceroute {vrf}", expect_string=':')

        else:
            output = self.device.send_command("traceroute", expect_string=':')

        try:
            while True:
                if output.strip().endswith(":"):
                    command = _get_command(output)
                    output = self.device.send_command(command, expect_string='(:|#)', expect_all_output=True)

                else:
                    break