Elementary BGP with YDK + OpenConfig
Now that you have a basic understanding of YANG models and YDK, let's start to put this together such that we use OpenConfig models to retrieve operational data from your devices. In this module you will connect to a device and attempt to read in BGP neighbor state data using the pre-built OpenConfig models that are included as part of YDK.
Device Configuration
We have to learn to walk before we can run, so in this example we will start with the simplest of the simplest in
terms of configuration to see how the model ties back to the device configuration.
Type xr
to enter your XRv device and configure BGP on your XRv device as follows:
conf
router bgp 65002
neighbor 10.1.1.1
commit
end
Your XR config is about as simple as it could possibly be. We set the AS and defined one neighbor, and added nothing else. Let's see if OpenConfig's YANG models from YDK yield the same operational data when reading it using NETCONF and the Python bindings.
Create New Python File
Return to Visual Studio Code and create a new Python file called
ydk_get_bgp.py
. You can copy this file name below for ease.
ydk_get_bgp.py
YDK Imports
For this exercise, you need to import the openconfig_bgp
model, the CRUDService
for performing the model reads,
and also the NetconfServiceProvider
for the connector of the model data between the Python client and the device.
from ydk.models.openconfig import openconfig_bgp
from ydk.services import CRUDService
from ydk.providers import NetconfServiceProvider
Instantiate the NetconfServiceProvider
To interact with the device, we will use the NetconfServiceProvider
that is packaged within ydk.providers.
The service provider acts as the mediator of the model data between the device and our client using NETCONF
for transport operations.
# Mapping of device names to IPs
duts = {
"xrv": '10.2.100.12',
}
# User the XRV for this simple exercise.
ip = duts['xrv']
# Get the provider and CRUD for the device.
# create NETCONF session
provider = NetconfServiceProvider(address=ip, port=830, username='admin', password='cisco.123', protocol='ssh')
Enable Full Debug Logging
YDK has the a built-in ability to enable debug logging. Enable and attach to debug logging to see what's going on under the hood inside YDK.
# Attach to the YDK Logger
import logging
logger = logging.getLogger("ydk")
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
formatter = logging.Formatter(("%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
handler.setFormatter(formatter)
logger.addHandler(handler)
Instantiate the CRUD Service
The CRUD service (Create, Read, Update, Delete) is the object that takes the underlying provider and YANG model desired and interacts with the device.
# Instantiate the CRUD service to be used for interacting with devvice.
crud = CRUDService()
Instantiate the BGP Model
In order to use the OpenConfig BGP models that come with YDK, we must first instantiate a new instance of the top-level model.
# Create BGP model from OpenConfig
bgp_model = openconfig_bgp.Bgp()
Populate the BGP Model Instance
With the model instantiated, we now use all three components together to read the operational data from the device. The CRUD service takes a provider, and a model such that the service reads the requested model data (BGP) over the specified transport mechanism (NETCONF).
# Get the BGP data from the device
bgp = crud.read(provider, bgp_model)
At this point in your code during runtime, the "bgp" instance that we instantiated earlier will have been popualted with the operational data from the device.
Check Global AS
Recall that we configured the global AS to the value of 12345. Let's see if we can observe this from our populated model. Place this print statement after the crud.read() operation so that you can verify this operational data:
# Check the global AS number as reported by YDK
print("Global AS:" + bgp.global_.state.as_)
Upon execution of your Python code, the model should report the same AS number that you configured over CLI.
Iterate Configured Neighbors
To confirm that we were able to read BGP operational data using OpenConfig and YANG models from YDK, we can iterate the neighbors attribute of BGP using a for loop.
# Print each neighbor and their addresses.
for neighbor in bgp.neighbors.neighbor:
print(f"Neighbor: {neighbor.state.neighbor_address}, State: {neighbor.state.session_state}")
The Full Script
Your script should look like this:
from ydk.models.openconfig import openconfig_bgp
from ydk.services import CRUDService
from ydk.providers import NetconfServiceProvider
# Mapping of device names to IPs
duts = {
"xrv": '10.2.100.12',
}
# User the XRV for this simple exercise.
ip = duts['xrv']
# Get the provider and CRUD for the device.
# create NETCONF session
provider = NetconfServiceProvider(address=ip, port=830, username='admin', password='cisco.123', protocol='ssh')
# Attach to the YDK Logger
import logging
logger = logging.getLogger("ydk")
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
formatter = logging.Formatter(("%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
handler.setFormatter(formatter)
logger.addHandler(handler)
# Instantiate the CRUD service to be used for interacting with devvice.
crud = CRUDService()
# Create BGP model from OpenConfig
bgp_model = openconfig_bgp.Bgp()
# Get the BGP data from the device
bgp = crud.read(provider, bgp_model)
# Check the global AS number as reported by YDK
print("Global AS:" + bgp.global_.state.as_)
# Print each neighbor and their addresses.
for neighbor in bgp.neighbors.neighbor:
print(f"Neighbor: {neighbor.state.neighbor_address}, State: {neighbor.state.session_state}")
Execute Python Script
Remember to save your new Python script with Ctrl+s
, then return to your container environment in Terminal to execute you new script.
cd /workspace/
python3.6 ydk_get_bgp.py
Observe YANG Data Read via YDK
If all steps were followed, you should see that the BGP model reports the BGP ASN and 1 neighbor as being configured, with a state of None (because this is an example with no peer on the other end).
There will be a ton of debug output from YDK corresponding to each of the internal RPCs performed by YDK as it interacts
with the device to carry out your request using it's CRUD engine. Near the bottom of the output you should see
text similar to the following where you'll see the Global AS
and Neighbor
:
2018-06-10 03:58:49,003 - ydk - DEBUG - Creating entity leaf neighbor-address of value '10.1.1.1' in parent /openconfig-bgp:bgp/neighbors/neighbor[neighbor-address='10.1.1.1']/state
2018-06-10 03:58:49,003 - ydk - DEBUG - Created leaf
Global AS:65002
Neighbor: 10.1.1.1, State: None
2018-06-10 03:58:49,003 - ydk - INFO - Disconnected from device
2018-06-10 03:58:49,003 - ydk - DEBUG - Trace: Writing message (session 655893890): <?xml version="1.0" encoding="UTF-8"?>
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="2">
<close-session/>
</rpc>
2018-06-10 03:58:49,003 - ydk - DEBUG - Trace: Received message (session 655893890): <?xml version="1.0"?>
<rpc-reply message-id="2" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<ok/>
</rpc-reply>
[root@eb7f7fa515f6 workspace]#
To summarize, in this module we imported the Openconfig BGP model that is included in YDK, instantiated a NetconfServiceProvider pointing at a device, instantiated a CRUD service for mediating model operations, and instantiated the model that we wanted to interact with. Once those components were all instantiated, we performed a READ operation, supplying the CRUD service the provider and model we wanted to read data from, and printed basic data as reported by the populated data model.
Cleanup
Log back into the XRv instance using xe
and remove the BGP configuration that was applied at the beginning of the lab.
conf
no router bgp 65002
commit
end
With fundamentals out of the way, let's move on to more advanced and useful examples where you'll now configure BGP on using YDK-Python.