In this post I will be taking a deeper look at the ios_interface module. This module is used to configure individual interfaces on a Cisco IOS device. The documentation for the module is located here. In this module I did have to dig into the actual Python file, and that is located here.

This module does not configure the layer 2 or layer 3 information on an interface. There are other modules that are used for configuring these particular pieces.

A look at the Parameters

Required Parameters

This module only has a single required module.

  • name: Name of the interface that is being configured, such as GigabitEthernet0/0/0

Using the module with just the one required item of name is pretty uneventful. If you wish to see the output I’m going to put that at the very bottom as an Appendix type item if you wish to see that output.

Optional Parameters

  • aggregate: This is what you will need to use if you want to configure multiple interfaces within the same task execution (or a loop of course)
  • delay: Time to wait before checking the state of an interface, defaults to 10 seconds
  • description: Interface description, follows the Cisco command description under the interface configuration
  • duplex: (full/half/auto) duplex settings in the interface configuration
  • enabled: (yes/no) interface link status, should it be enabled/disabled
  • mtu: MTU setting, follows the mtu configuration under the interface configuration
  • neighbors: Checking for the operational state, using LLDP information, either with the sub-parameter host or port
  • rx_rate: Stated as Receiver rate in bits per second, not sure what this does
  • speed: Interface speed in Mbps, corresponds to the Cisco command speed under interface configuration
  • tx_rate: Stated as Transmit rate in bits per second, not sure what it does

Note - Operational State

As I’m writing (and not having tested yet) the operational state if you are configuring an interface and looking to validate the neighbors, you may want to up the delay time based on the LLDP neighbor timers. These timers may be longer than the default 10 seconds.

rx_rate and tx_rate

From the documentation on the module this appears to perhaps to be related to the actual interface transmit and receive rates that is being reported by the device. The documentation has some references to ge and le which would be comparisons. Based on the Python file and the variables named want_tx_rate and want_rx_rate within the Python file, this does in fact appear to be related to the interface traffic amount.

Parameter Details: Aggregate

This is what I will say is a group of interfaces to configure within a single task. This is where you will configure multiples of the ios_interface task. To leverage this you will need to create a dictionary (Array) with the required parameters for the module.

A look at the module in action

First, jumping deep in. Going to take a look at what it looks like to configure interfaces using the aggregate parameter. This is going to configure specific details about two interfaces on the switch itself.

Pre-Change Config

Before the change there is just the media-type and the negotiation set to auto. These are default out of the box.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sw19#show run int gig0/1
Building configuration...

Current configuration : 71 bytes
!
interface GigabitEthernet0/1
 media-type rj45
 negotiation auto
end

sw19#show run int gig0/2
Building configuration...

Current configuration : 71 bytes
!
interface GigabitEthernet0/2
 media-type rj45
 negotiation auto
end

Playbook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
# yamllint disable rule:truthy
# yamllint disable rule:line-length
- name: Switch config
  connection: network_cli
  hosts: sw19
  gather_facts: no
  become: yes
  become_method: enable

  tasks:

    - name: IOS >> VLAN Updates
      ios_interface:
        aggregate:
          - {name: GigabitEthernet0/1, description: "First Ansible Configured Interface", enabled: no}
          - {name: GigabitEthernet0/2, description: "Second Ansible Configured Interface", enabled: yes}
        speed: 100
        duplex: full
      register: output

    - name: DEBUG >> output
      debug:
        msg: "{{ output }}"

Ansible Output

Here we see that the commands being sent to the device are to set the speed, duplex to full, interface description, and then shutting down the interface that was set to disabled.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
PLAY [Switch config] ***********************************************************

TASK [IOS >> VLAN Updates] *****************************************************
changed: [sw19]

TASK [DEBUG >> output] *********************************************************
ok: [sw19] => {
    "msg": {
        "changed": true, 
        "commands": [
            "interface GigabitEthernet0/1", 
            "speed 100", 
            "description First Ansible Configured Interface", 
            "duplex full", 
            "shutdown", 
            "interface GigabitEthernet0/2", 
            "speed 100", 
            "description Second Ansible Configured Interface", 
            "duplex full"
        ], 
        "failed": false
    }
}

PLAY RECAP *********************************************************************
sw19                       : ok=2    changed=1    unreachable=0    failed=0   

Post Execution Configuration

Working through this, it looks like the speed cannot be configured as autonegotation is set on the interface. I believe that this is something that is primarily set because of using a virtualized switch platform. I plan to open up a bug report on this soon. We see exactly what we expect in the configuration after the Ansible output. We see interface description configured on each interface, the interface shutdown or enabled.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
sw19#show run int gig0/1
Building configuration...

Current configuration : 129 bytes
!
interface GigabitEthernet0/1
 description First Ansible Configured Interface
 shutdown
 media-type rj45
 negotiation auto
end

sw19#show run int gig0/2
Building configuration...

Current configuration : 120 bytes
!
interface GigabitEthernet0/2
 description Second Ansible Configured Interface
 media-type rj45
 negotiation auto
end

Creating a Loopback Interface

In the second example of the playbook we will create additional Loopback addresses.

Pre-Change Configuration

Here is the output of the show ip int breif of the switch before adding loopbacks.

1
2
3
4
5
6
7
8
9
10
11
12
13
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet0/0     unassigned      YES unset  up                    up      
GigabitEthernet0/1     unassigned      YES unset  administratively down down    
GigabitEthernet0/2     unassigned      YES unset  up                    up      
GigabitEthernet0/3     unassigned      YES unset  up                    up      
GigabitEthernet1/0     unassigned      YES unset  up                    up      
GigabitEthernet1/1     unassigned      YES unset  up                    up      
GigabitEthernet1/2     unassigned      YES unset  up                    up      
GigabitEthernet1/3     unassigned      YES unset  up                    up      
Loopback0              10.100.100.100  YES manual up                    up      
Port-channel5          unassigned      YES unset  down                  down    
Port-channel6          unassigned      YES unset  down                  down    
Vlan2                  172.16.1.2      YES manual up                    up   

Here we only see one loopback address, Loopback0.

Playbook

The playbook I’m going to add a loopback interface, but there will not be an address configured on it, you will need to use ios_l3_interface in conjunction with this if using ios_interface for loopbacks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
# yamllint disable rule:truthy
# yamllint disable rule:line-length
- name: Switch config
  connection: network_cli
  hosts: sw19
  gather_facts: no
  become: yes
  become_method: enable

  tasks:

    - name: IOS >> VLAN Updates
      ios_interface:
        name: Loopback5
      register: output

    - name: DEBUG >> output
      debug:
        msg: "{{ output }}"

Ansible Output

I expect to see the configuration of just creating a loopback address. This is in fact what is seen upon executing the command.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PLAY [Switch config] ***********************************************************

TASK [IOS >> VLAN Updates] *****************************************************
changed: [sw19]

TASK [DEBUG >> output] *********************************************************
ok: [sw19] => {
    "msg": {
        "changed": true, 
        "commands": [
            "interface Loopback5"
        ], 
        "failed": false
    }
}

PLAY RECAP *********************************************************************
sw19                       : ok=2    changed=1    unreachable=0    failed=0  

Switch Post Run

Now on the switch as expected we see another Loopback address added.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sw19#show ip int brie
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet0/0     unassigned      YES unset  up                    up      
GigabitEthernet0/1     unassigned      YES unset  administratively down down    
GigabitEthernet0/2     unassigned      YES unset  up                    up      
GigabitEthernet0/3     unassigned      YES unset  up                    up      
GigabitEthernet1/0     unassigned      YES unset  up                    up      
GigabitEthernet1/1     unassigned      YES unset  up                    up      
GigabitEthernet1/2     unassigned      YES unset  up                    up      
GigabitEthernet1/3     unassigned      YES unset  up                    up      
Loopback0              10.100.100.100  YES manual up                    up      
Loopback5              unassigned      YES unset  up                    up      
Port-channel5          unassigned      YES unset  down                  down    
Port-channel6          unassigned      YES unset  down                  down    
Vlan2                  172.16.1.2      YES manual up                    up   

Summary

Earlier in the week I started using this module in a production environment. I had been using just ios_config and moving down into the interface and issuing the shutdown or no shutdown of an interface. After coming across a couple of errors I decided to try the ios_interface module for the playbook. This worked out much better. Digging through this module further with this post I am finding that ios_interface is really good for interface state of up/down and the description of the interface. So you will want to use this in conjunction with the ios_l3_interface and ios_l2_interface to get the complete interface configuration with the modules.

Appendix

Task with only the required Parameters (Loopback10)

First taking a look at the play with using a Loopback10 interface. There was previously no Loopback10 interface configured. The play looks like the following:

Play

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
# yamllint disable rule:truthy
# yamllint disable rule:line-length
- name: Switch config
  connection: network_cli
  hosts: sw19
  gather_facts: no
  become: yes
  become_method: enable

  tasks:

    - name: IOS Interface >> Configure Loopback10
      ios_interface:
        name: Loopback10
      register: output

    - name: DEBUG >> output
      debug:
        msg: "{{ output }}"

Play Output

On the output front, nothing surprising.

The commands sent to the device essentially are:

config t interface Loopback10

This creates the interface that was not there previously and does not provide any other configuration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PLAY [Switch config] ***********************************************************

TASK [IOS >> VLAN Updates] *****************************************************
changed: [sw19]

TASK [DEBUG >> output] *********************************************************
ok: [sw19] => {
    "msg": {
        "changed": true, 
        "commands": [
            "interface Loopback10"
        ], 
        "failed": false
    }
}

PLAY RECAP *********************************************************************
sw19                       : ok=2    changed=1    unreachable=0    failed=0   

Task with only the required Parameters (GigabitEthernet0/1)

In this play the interface being configured will be moved from a Loopback interface to one of the physical interfaces on the device. There will once again be no parameters.

Play

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
# yamllint disable rule:truthy
# yamllint disable rule:line-length
- name: Switch config
  connection: network_cli
  hosts: sw19
  gather_facts: no
  become: yes
  become_method: enable

  tasks:

    - name: IOS Interface >> Configure Gig0/1
      ios_interface:
        name: GigabitEthernet0/1
      register: output

    - name: DEBUG >> output
      debug:
        msg: "{{ output }}"

Output

The Ansible module appears to check the running configuration as expected before stepping through. The output shows no commands being applied as the configuration on the interface already has the desired configuration (blank).

Pre-Configuration

1
2
3
4
5
6
7
8
9
#show run int gig0/1
Building configuration...

Current configuration : 71 bytes
!
interface GigabitEthernet0/1
 media-type rj45
 negotiation auto
end

There are no pieces that need to be configured, so the output from the playbook execution is below. With no other parameters defined the module does nothing.

Play Execution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PLAY [Switch config] ***********************************************************

TASK [IOS >> VLAN Updates] *****************************************************
ok: [sw19]

TASK [DEBUG >> output] *********************************************************
ok: [sw19] => {
    "msg": {
        "changed": false, 
        "commands": [], 
        "failed": false
    }
}

PLAY RECAP *********************************************************************
sw19                       : ok=2    changed=0    unreachable=0    failed=0   

A