Python Scripting – Cisco VoIP Phone

I recently decided to start looking into scripting and automation for our network at work. We never did anything like this, at least not that was ever discussed or shared with the team, so I decided to take this initiative.

The Decision

So what is a common task that a Network Admin routinely does that we can script? For me, it was the deployment of Cisco VoIP phones across our campus. It is not a hard task and we will often go days without setting up a phone. However, we do have quite a bit of department or office moves that occur every couple of weeks throughout the university. This can mean dozens of ports will need to be configured for the VoIP phones.

Some of you might be thinking, why not just configure every port to be capable of using VoIP. This is something that has been discussed internally but we haven’t come to a conclusion just yet. Some think it will be fine and there is no risk, while others question the security of having the voice network tagged on every port. I am more on the fence that this can be a risk because anyone with the right knowledge might be able to install network drivers that can process tagged traffic. This may or may not be a threat and one day I plan to test whether or not it is possible to hop onto our voice network to gain access to certain parts of the network.

The Beginning

Having some Python experience, this was my go to language to write this script. I found the language to be fairly easy to understand, and it can do amazing things. There is a wonderful Python library for handling SSH connections through multiple vendors called Netmiko. This makes network scripting a lot easier and faster to diving into shoving commands down to your equipment. Since this blog is about the script for configuring VoIP ports, I won’t cover how to install Netmiko but it is honestly really easy.

Now where do we start? Let’s verify we can connect to our network equipment first since that is the most important part of the script. The script won’t do anything if you can’t get the commands to the device after all.

Here is the basic script to establish an SSH session to our switch:

from netmiko import ConnectHandler
import getpass

# Enter IP to connect to
ip_add = input("IP: ")

# Enter username and password
username = input("Username: ")
password = getpass.getpass()

# Device group information

cisco = {
    'device_type': 'cisco_ios',
    'ip':   ip_add,
    'username': username,
    'password': password,
}
# Establishes the SSH session using the Cisco device group defined above
net_connect = ConnectHandler(**cisco)
output = net_connect.send_command('show version')
print(output)
net_connect.disconnect()

As explained earlier, this post is to just show the process of scripting, not to teach what each and every command does. There is a huge amount of resources online to learn this stuff, and they will teach you better than I can anyway 🙂

When running this we should receive the output from the Cisco switch displaying the version information. If we receive output then we have successfully connected to our switch via SSH and ran a command on it.

The Result

As you can see we were able to establish an SSH session and sent a simple command. Expanding upon this we can just keep sending commands to configure the device how we like. I took it a little further and added vendor detection and a menu. It also loops so you don’t have to keep running the script if you want to make a quick change to any of the variables.

Below is the final script, which is available for download on the Downloads page.

# The purpose of this script is to configure a Cisco VoIP
# phone on the Cisco, Extreme, and Enterasys switch families
# Adding vendors should be fairly easy and you just need to 
# create a new device group and add it to the selection menu.
# 
# ----- INSTRUCTIONS -----
# 1. Enter the switch family you are working on
# 2. Enter the IP address for the switch you want to configure the VoIP phone on
# 3. Use login information for an account that has RW privileges
# 4. Start the VoIP configuration process
# 
# Created by Alex Roland
# alex.roland@peacefulnetworks.com

from netmiko import ConnectHandler
import getpass

# Script Menu
def menu():
        print("\n", 20 * "-" , "MENU" , 20 * "-")
        print("1. Vendor") # This will determine the network OS to run the commands on
        print("2. Switch IP") # The specific switch you want to configure the VoIP phone on. Currently limit
ed to only one IP at a time.
        print("3. Username and password")
        print("4. Process VoIP request") # Asks for the port and voice VLAN of the chosen switch, then confi
gures the port with that information
        print("5. Exit") # Terminates the loop, resulting in the program closing
        print(46 * "-")

loop = True # Sets the variable to start the loop

while loop:
        menu() # Display menu selection
        choice = int(input("Enter your selection [1-5]: "))

        if choice == 1: # Enter device type
                vendor = input("NOS (exos, eos, cisco): ")
        elif choice == 2: # Enter IP to connect to
                ip_add = input("IP: ")
        elif choice == 3: # Enter username and password
                username = input("Username: ")
                password = getpass.getpass()
        elif choice == 4:
                # Device group information
                exos = {
                        'device_type': 'extreme_exos',
                        'ip':   ip_add,
                        'username': username,
                        'password': password,
                }

                eos = {
                        'device_type': 'enterasys',
                        'ip':   ip_add,
                        'username':     username,
                        'password':     password,
                }

                cisco = {
                        'device_type': 'cisco_ios',
                        'ip':   ip_add,
                        'username':     username,
                        'password':     password,
                }

                # EXOS: : The below commands will configure the VoIP phone
                if vendor == "exos":
                        net_connect = ConnectHandler(**exos) # Uses the Netmiko connection handler to establ
ish the SSH session to the switch
                        show_vlans = 'show vlan description'
                        output = net_connect.send_command(show_vlans) # Shows available VLANs to choose from

                        print(output)
                        print("Port format example: 1 or 1:1")
                        port = input("Enter VoIP port: ")
                        voice_vlan = input("Enter VoIP VLAN: ")
                        assign_voice = 'configure vlan {} add ports {} tagged'.format(voice_vlan, port) # Ad
ds the voice VLAN as tagged on the selected port
                        lldp_enable = 'enable lldp ports {}'.format(port)
                        lldp_port_desc = 'configure lldp port {} advertise port-description'.format(port)
                        lldp_system_name = 'configure lldp port {} advertise system-name'.format(port)
                        lldp_system_cap = 'configure lldp port {} advertise system-capabilities'.format(port
)
                        lldp_mgmt_add = 'configure lldp port {} advertise management-address'.format(port)
                        lldp_vs_dot3 = 'configure lldp port {} advertise vendor-specific dot3 power-via-mdi 
with-classification'.format(port)
                        lldp_vs_med_cap = 'configure lldp port {} advertise vendor-specific med capabilities
'.format(port)
                        lldp_policy = 'configure lldp port {} advertise vendor-specific med policy applicati
on voice vlan {} dscp 46'.format(port, voice_vlan)
                        output = net_connect.send_command(assign_voice)
                        output = net_connect.send_command('show ports {} vlan'.format(port))
                        print(output) # Outputs the VLAN information for the selected port so you can see if
 the VLAN is properly tagged
                        output = net_connect.send_command(lldp_enable)
                        output = net_connect.send_command(lldp_port_desc)
                        output = net_connect.send_command(lldp_system_name)
                        output = net_connect.send_command(lldp_system_cap)
                        output = net_connect.send_command(lldp_mgmt_add)
                        output = net_connect.send_command(lldp_vs_dot3)
                        output = net_connect.send_command(lldp_vs_med_cap)
                        output = net_connect.send_command(lldp_policy)
                        # Show the port LLDP settings to confirm script took
                        output = net_connect.send_command('show configuration | i "lldp port {}"'.format(por
t))
                        print(output)
                        # Save config
                        output = net_connect.send_command('save')
                        print(output)
                        net_connect.disconnect() # Closes the SSH connection

                # Enterasys: The below commands will configure the VoIP phone
                elif vendor == "eos":
                        net_connect = ConnectHandler(**eos) # Uses the Netmiko connection handler to establi
sh the SSH session to the switch
                        show_vlans = 'show config vlan'
                        output = net_connect.send_command(show_vlans) # Shows available VLANs to choose from

                        print(output)
                        print("Port format example: ge.1.1")
                        port = input("Enter VoIP port: ")
                        voice_vlan = input("Enter VoIP VLAN: ")
                        assign_voice = ('set vlan egress {} {} tagged').format(voice_vlan, port)
                        config_ciscodp = ('set ciscodp port vvid {} {}').format(voice_vlan, port)
                        output = net_connect.send_command(assign_voice) # Adds the voice VLAN as tagged on t
he selected port
                        output = net_connect.send_command(config_ciscodp)
                        output = net_connect.send_command(show_vlans)
                        print(output)
                        output = net_connect.send_command('show config ciscodp')
                        print(output)
                        net_connect.disconnect() # Closes the SSH connection

                # Cisco: The below commands will configure the VoIP phone
                elif vendor == "cisco":
                        net_connect = ConnectHandler(**cisco) # Uses the Netmiko connection handler to estab
lish the SSH session to the switch
                        show_vlans = 'show vlan br'
                        output = net_connect.send_command(show_vlans) # Shows available VLANs to choose from

                        print(output)
                        print("Port format example: fa0/1 or gi0/1")
                        port = input("Enter VoIP port: ")
                        voice_vlan = input("Enter VoIP VLAN: ")
                        config_mode = 'config t'
                        interface_mode = 'int {}'.format(port)
                        assign_voice = 'switchport voice vlan {}'.format(voice_vlan)
                        exec_return = 'end'
                        output = net_connect.send_command(config_mode) # Enters global configuration mode
                        output = net_connect.send_command(interface_mode) # Enters the port interface
                        output = net_connect.send_command(assign_voice) # Adds the voice VLAN as tagged on t
he selected port
                        output = net_connect.send_command(exec_return) # Returns back to the main interface 
so commands can be performed without do
                        verify_voice = 'show run int {}'.format(port)
                        output = net_connect.send_command(verify_voice) # Displays the configuration of the 
selected port to verify commands took
                        print(output)
                        output = net_connect.send_command('wr mem') # Saves the configuration on the Cisco s
witch
                        print(output)
                        net_connect.disconnect() # Closes the SSH connection

                else:
                        print("Invalid selection")
        elif choice == 5:
                loop = False # Terminate the loop
        else:
                input("Invalid selection, please try again...")

If you need assistance adding support for more vendors or have any feedback on the script (good or bad) just leave a comment.

Looking Ahead

For our campus network, we use Extreme Management Center to centrally manage our network equipment. This server has built in support for Python scripts and the usability is fantastic when writing scripts like this one. In my next post I will cover to process and experience of migrating the script into XMC and the additional features opened up from doing so.

Thank you everyone and remember to keep your networks happy!

-Nefario

Leave a Reply

Your email address will not be published. Required fields are marked *