In this example I want to connect to a router in cisco sandbox and get the interface gig1 data.

If we want to use the Python we should install ncclient library at first with pip install ncclient. on the router netconf ans ssh in enabled. I would also use xmltodict library in order to be able to convert the xml data format to python dictionary. and in order to convert the xml string into xml object I use etree module from lxml library so that we can make an xml object to sent to the device. xml.dom.minidom is for have a pretty view of the xml output.

from ncclient import manager
import xmltodict
from lxml import etree
import xml.dom.minidom

I am goning to use a dictionary for user credentials here for our test.

IOS_XE_LAB = {
    "HOST" : "10.10.20.48",
    "PORT" : 830,
    "USER" : "developer",
    "PASS" : "C1sco12345"

}

On order to get, edit, delete or.. we need to specify that. The way to do this is using filter in NETCONF. So for example here we want to get the interface Gig1 of the router. In netconf filter we should specify the Data model (YANG), container and also Module name and .

filter_str = """
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
  <interface>
    <name>GigabitEthernet1</name>
  </interface>
</interfaces>
"""

Now with this code we are connecting to the device using ncclient Manager module. We are sending the User Credentials to make a Netconf session which is a SSH connection on port 830. Then we are saving the get method output in result. Filter is used as a input in get method.

with manager.connect(host=IOS_XE_LAB["HOST"], port=IOS_XE_LAB["PORT"], username=IOS_XE_LAB["USER"],
                     password=IOS_XE_LAB["PASS"], hostkey_verify=False) as m:
    # Retrieve the operational data
    result = m.get(filter=('subtree', etree.fromstring(filter_str)))


    Pretty_xml = xml.dom.minidom.parseString(result.xml).toprettyxml()

print(Pretty_xml)
Output:

<?xml version="1.0" ?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:ad59644e-b1fb-4b8f-97ca-28847aef11af">
        <data>
                <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
                        <interface>
                                <name>GigabitEthernet1</name>
                                <description>MANAGEMENT INTERFACE - DON'T TOUCH ME</description>
                                <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd</type>
                                <enabled>true</enabled>
                                <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
                                        <address>
                                                <ip>10.10.20.48</ip>
                                                <netmask>255.255.255.0</netmask>
                                        </address>
                                </ipv4>
                                <ipv6 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"/>
                        </interface>
                </interfaces>
        </data>
</rpc-reply>


Now if we want to add an ip address on interface Gig 2 and also turn the interface on we can use the same filter but instead of the GET request we should use edit.

Current Status:
cat8000v#sh ip int brie
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
GigabitEthernet2       unassigned      YES NVRAM  administratively down down
GigabitEthernet3       unassigned      YES NVRAM  administratively down down
Loopback0              10.0.0.1        YES NVRAM  up                    up
Loopback10             unassigned      YES unset  up                    up
Loopback109            10.255.255.9    YES NVRAM  up                    up
VirtualPortGroup0      192.168.1.1     YES NVRAM  up                    up

config_payload = """
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
    <interface>
      <name>GigabitEthernet2</name>
      <enabled>true</enabled>
      <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
        <address>
          <ip>1.1.1.1</ip>
          <netmask>255.255.255.0</netmask>
        </address>
      </ipv4>
    </interface>
  </interfaces>
</config>
"""

with manager.connect(host=IOS_XE_LAB["HOST"], port=IOS_XE_LAB["PORT"], username=IOS_XE_LAB["USER"],
                     password=IOS_XE_LAB["PASS"], hostkey_verify=False) as m:
    # Retrieve the operational data
    result = m.edit_config(target="running", config=config_payload)

As you can see this time we are using edit_config method to edit the running configuration based on the config payload. hostkey_verify=False is for not asking the ssh key verification when it wants to do ssh.

Output:

<?xml version="1.0" ?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:7e3b35f5-21d7-4a19-9310-22a6b6023aa5">
        <ok/>
</rpc-reply>

On the router:

*Jan 31 11:22:58.393: %SYS-5-CONFIG_P: Configured programmatically by process io                               sp_dmiauthd_conn_100001_vty_100001 from console as developer on vty4294966926
*Jan 31 11:22:58.379: %DMI-5-CONFIG_I: R0/0: dmiauthd: Configured from NETCONF/R                               ESTCONF by developer, transaction-id 25
cat8000v#

cat8000v#sh ip int brie
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
GigabitEthernet2       1.1.1.1         YES other  down                  down
GigabitEthernet3       unassigned      YES NVRAM  administratively down down
Loopback0              10.0.0.1        YES NVRAM  up                    up
Loopback10             unassigned      YES unset  up                    up
Loopback109            10.255.255.9    YES NVRAM  up                    up
VirtualPortGroup0      192.168.1.1     YES NVRAM  up                    up
cat8000v#

With the same code and the config below we can set the secondary IP address on the interface:

config_payload = """
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
    <interface>
      <name>GigabitEthernet2</name>
      <enabled>true</enabled>

      <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
        <!-- Primary IP -->
        <address>
          <ip>1.1.1.1</ip>
          <netmask>255.255.255.0</netmask>
        </address>

        <!-- Secondary IP (2nd address on same interface) -->
        <address>
          <ip>2.2.2.2</ip>
          <netmask>255.255.255.0</netmask>
        </address>
      </ipv4>

    </interface>
  </interfaces>
</config>
"""

Output:
<?xml version="1.0" ?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:847272bd-10da-4b73-8cf0-a5183300f27b">
        <ok/>
</rpc-reply>

and on the router:
cat8000v#
*Jan 31 11:31:35.734: %DMI-5-AUTH_PASSED: R0/0: dmiauthd: User 'developer' authenticated successfully from 192.168.254.11:52608  for netconf over ssh. External groups: PRIV15
*Jan 31 11:31:37.484: %SYS-5-CONFIG_P: Configured programmatically by process iosp_dmiauthd_conn_100001_vty_100001 from console as developer on vty4294966926
*Jan 31 11:31:37.476: %DMI-5-CONFIG_I: R0/0: dmiauthd: Configured from NETCONF/RESTCONF by developer, transaction-id 37
cat8000v#
cat8000v#sh run int GigabitEthernet2
Building configuration...

Current configuration : 161 bytes
!
interface GigabitEthernet2
 description Network Interface
 ip address 2.2.2.2 255.255.255.0 secondary
 ip address 1.1.1.1 255.255.255.0
 negotiation auto
end

cat8000v#

If we want to delete the secodary IP address we can use the operation in xml code:

config_payload = """
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
    <interface>
      <name>GigabitEthernet2</name>
      <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
        <address nc:operation="delete"
                 xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
          <ip>2.2.2.2</ip>
          <netmask>255.255.255.0</netmask>
        </address>
      </ipv4>
    </interface>
  </interfaces>
</config>
"""


We can also get the Data from the user, for example to creating a new loop back, we can use input function and save the Data then with format method insert them in the xml string.


# ---- Ask user for values ----
loop_num = input("Which Loopback number to add? (e.g. 10): ").strip()
desc = input("Description (optional): ").strip()
ip_addr = input("IPv4 address (e.g. 10.10.10.10): ").strip()
mask = input("Netmask (e.g. 255.255.255.255): ").strip()


# XML template with placeholders (similar to your screenshot)
netconf_interface_template = """
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
    <interface>
      <name>{name}</name>

      <!-- REQUIRED for new interfaces -->
      <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">
        ianaift:softwareLoopback
      </type>

      <description>{desc}</description>
      <enabled>true</enabled>

      <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
        <address>
          <ip>{ip}</ip>
          <netmask>{mask}</netmask>
        </address>
      </ipv4>
    </interface>
  </interfaces>
</config>
"""

# Build the final XML payload
payload = netconf_interface_template.format(
    name=f"Loopback{loop_num}",
    desc=desc,
    enabled="true",
    ip=ip_addr,
    mask=mask
)

Output:

Which Loopback number to add? (e.g. 10): 11
Description (optional): 11
IPv4 address (e.g. 10.10.10.10): 11.11.11.11
Netmask (e.g. 255.255.255.255): 255.255.255.0
<?xml version="1.0" ?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:0d1140cd-3456-4ad7-b2f4-59dfcb96dd72">
        <ok/>
</rpc-reply>


*Jan 31 12:00:05.129: %DMI-5-AUTH_PASSED: R0/0: dmiauthd: User 'developer' authenticated successfully from 192.168.254.11:53103  for netconf over ssh. External groups: PRIV15
*Jan 31 12:00:07.465: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback11, changed state to up
*Jan 31 12:00:07.497: %SYS-5-CONFIG_P: Configured programmatically by process iosp_dmiauthd_conn_100001_vty_100001 from console as developer on vty4294966926
*Jan 31 12:00:07.484: %DMI-5-CONFIG_I: R0/0: dmiauthd: Configured from NETCONF/RESTCONF by developer, transaction-id 45
cat8000v#
cat8000v#
cat8000v#sh ip int brie
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
GigabitEthernet2       1.1.1.1         YES other  up                    up
GigabitEthernet3       unassigned      YES NVRAM  administratively down down
Loopback0              10.0.0.1        YES NVRAM  up                    up
Loopback10             unassigned      YES unset  up                    up
Loopback11             11.11.11.11     YES other  up                    up
Loopback109            10.255.255.9    YES NVRAM  up                    up



With shh on port 830 we can sent/receive the xml config file to the device.

ssh -s developer@10.10.20.48 -p 830 netconf
after 
]]>]]> 
we can paste the xml string.

<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
  <edit-config>
    <target>
      <running/>
    </target>
    <config>
      <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
        <interface>
          <name>Loopback11</name>

          <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">
            ianaift:softwareLoopback
          </type>

          <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
            <address>
              <ip>22.22.22.22</ip>
              <netmask>255.255.255.255</netmask>
            </address>
          </ipv4>

        </interface>
      </interfaces>
    </config>
  </edit-config>
</rpc>
]]>]]>

Posted in

Leave a comment