Path Trace Guide

Introduction

Path trace is the feature in Catalyst Center that allows you to execute a trace between two devices in your network. It is possible to get device and interface statistics, QoS details and/or ACLs traces and do it using different ports and protocols.

Use it to troubleshoot network problems like packet loss and traffic not reaching its destination due to ACLs or routing issues.

Goal

The goals of this guide are:

  1. Retrieve a list of previously executed path traces.
  2. Execute a path trace.
  3. Obtain the path trace result.
  4. Delete the path trace.

Path trace workflow

Endpoints and methods used

  • POST /dna/system/api/v1/auth/token
  • GET /dna/intent/api/v1/network-device
  • GET /dna/intent/api/v1/flow-analysis
  • POST /dna/intent/api/v1/flow-analysis
  • GET /dna/intent/api/v1/flow-analysis/{flowAnalysisId}
  • DELETE /dna/intent/api/v1/flow-analysis/{flowAnalysisId}

Prerequisites

For this guide, we recommend that the developer becomes familiar with authenticating and obtaining the device ID of the target devices.

Environment

This guide was developed using:

Authentication

First, we must authenticate and retrieve a token from the API.

Notes: Do not use verify=False or urllib3.disable_warnings() if you are not sure of its purpose. Read Authentication and Authorization.

import requests
from requests.auth import HTTPBasicAuth
import urllib3
urllib3.disable_warnings()

BASE_URL = 'https://<IP Address>'
AUTH_URL = '/dna/system/api/v1/auth/token'
USERNAME = '<USERNAME>'
PASSWORD = '<PASSWORD>'

response = requests.post(BASE_URL + AUTH_URL, auth=HTTPBasicAuth(USERNAME, PASSWORD), verify=False)
token = response.json()['Token']
headers = {'X-Auth-Token': token, 'Content-Type': 'application/json'}

Get Devices' IPs

With the token, we can proceed to query the devices API using the hostnames of the two devices we want to use for the path trace.

headers = {'X-Auth-Token': token, 'Content-Type': 'application/json'}
DEVICES_URL = '/dna/intent/api/v1/network-device'
src_ip_address = ''
query_string_params = {'hostname': 'CSR1Kv-01.devnet.local'}
response = requests.get(BASE_URL + DEVICES_URL, headers = headers, params=query_string_params, verify=False)
src_ip_address = response.json()['response'][0]['managementIpAddress']

dst_ip_address = ''
query_string_params = {'hostname': 'CSR1Kv-09.devnet.local'}
response = requests.get(BASE_URL + DEVICES_URL, headers = headers, params=query_string_params, verify=False)
dst_ip_address = response.json()['response'][0]['managementIpAddress']

Path Trace API

The Path Trace API consists of four endpoints for creating a path trace, getting the result, deleting it, or getting a summary of all path traces in the system.

This API lets a user execute a path trace between two devices that are known by Catalyst Center. Path trace is asynchronous, so results aren't obtained immediately. Check the async guide for more information.

Generate a new Path trace

With the IPs, we can create a new path trace. Source and destination IPs are mandatory. It is possible to ask for more details using the inclusions list with one or several of the following options:

  • INTERFACE-STATS
  • DEVICE-STATS
  • ACL-TRACE
  • QOS-STATS

The following snippet shows the path trace creation:

PATH_TRACE_URL = '/dna/intent/api/v1/flow-analysis'
path_trace_payload = {
    'sourceIP': src_ip_address,
    'destIP': dst_ip_address,
    'inclusions': [
        'INTERFACE-STATS',
        'DEVICE-STATS',
        'ACL-TRACE',
        'QOS-STATS'
        ],
    'protocol': 'icmp'
}
response = requests.post(BASE_URL + PATH_TRACE_URL, headers=headers, json=path_trace_payload, verify=False)
flow_analysis_id = response.json()['response']['flowAnalysisId']

Get path trace result

Query the result of the path trace from the API:

PATH_TRACE_ID_URL = '/dna/intent/api/v1/flow-analysis/{flow_analysis_id}'
response = requests.get(BASE_URL + PATH_TRACE_ID_URL.format(flow_analysis_id=flow_analysis_id), headers=headers, verify=False)
print(response.json['response'])

Get path trace summary

It is also possible to get a summary of all the path traces in the system, filtered by different parameters, for example, destination IP address.

query_string_params = {'destIP': dst_ip_address}
response = requests.get(BASE_URL + PATH_TRACE_URL, params=query_string_params, headers=headers, verify=False)
print(response.json())

Delete path trace

Finally, we can delete our path trace if we want to.

response = requests.delete(BASE_URL + PATH_TRACE_ID_URL.format(flow_analysis_id=flow_analysis_id), headers=headers, verify=False)

Code

The repository for this guide is here.

# Modules import
import requests
from requests.auth import HTTPBasicAuth
import sys
import time

# Disable SSL warnings. Not needed in production environments with valid certificates
import urllib3
urllib3.disable_warnings()

# Authentication
BASE_URL = 'https://<IP Address>'
AUTH_URL = '/dna/system/api/v1/auth/token'
USERNAME = '<USERNAME>'
PASSWORD = '<PASSWORD>'

# URLs
DEVICES_URL = '/dna/intent/api/v1/network-device'
PATH_TRACE_URL = '/dna/intent/api/v1/flow-analysis'
PATH_TRACE_ID_URL = '/dna/intent/api/v1/flow-analysis/{flow_analysis_id}'

def get_dnac_jwt_token():
    response = requests.post(BASE_URL + AUTH_URL,
                             auth=HTTPBasicAuth(USERNAME, PASSWORD),
                             verify=False)
    token = response.json()['Token']
    return token

# Get list of devices
def get_devices(headers, query_string_params):
    response = requests.get(BASE_URL + DEVICES_URL,
                            headers = headers,
                            params = query_string_params,
                            verify=False)
    return response.json()['response']

# Create path trace
def create_path_trace(headers, path_trace_payload):
    response = requests.post(BASE_URL + PATH_TRACE_URL, headers=headers,
                             json=path_trace_payload, verify=False)
    return response.json()['response']

# Get path trace result
def get_path_trace_by_id(headers, flow_analysis_id):
    response = requests.get(BASE_URL + PATH_TRACE_ID_URL.format(flow_analysis_id=flow_analysis_id),
                            headers=headers, verify=False)
    return response.json()['response']

# Get path trace summary
def get_path_traces_summary(headers, query_string_params):
    response = requests.get(BASE_URL + PATH_TRACE_URL,
                            params=query_string_params,
                            headers=headers, verify=False)
    return response.json()['response']

# Delete path trace
def delete_path_trace(headers, flow_analysis_id):
    response = requests.delete(BASE_URL + PATH_TRACE_ID_URL.format(flow_analysis_id=flow_analysis_id),
                               headers=headers, verify=False)
    return response

def main():
    # obtain the Catalyst Center Auth Token
    token = get_dnac_jwt_token()
    headers = {'X-Auth-Token': token, 'Content-Type': 'application/json'}

    # Get src device IP
    print('Printing source device IP ...')
    query_string_params = {'hostname': 'CSR1Kv-01.devnet.local'}
    response = get_devices(headers, query_string_params)
    src_ip_address = response[0]['managementIpAddress']
    print(src_ip_address)

    # print devices list
    print('\nPrinting destination device IP ...')
    query_string_params = {'hostname': 'CSR1Kv-09.devnet.local'}
    response = get_devices(headers, query_string_params)
    dst_ip_address = response[0]['managementIpAddress']
    print(dst_ip_address)

    # Generate a new path trace
    print('\nPrinting flow analysis id ...')
    path_trace_payload = {
        'sourceIP': src_ip_address,
        'destIP': dst_ip_address,
        'inclusions': [
            'INTERFACE-STATS',
            'DEVICE-STATS',
            'ACL-TRACE',
            'QOS-STATS'
        ],
        'protocol': 'icmp'
    }
    response = create_path_trace(headers, path_trace_payload)
    flow_analysis_id = response['flowAnalysisId']
    print(flow_analysis_id)

    # Waiting until the path trace is done
    time.sleep(10)

    # Get path trace result
    print('\nPrinting path trace result ...')
    response = get_path_trace_by_id(headers, flow_analysis_id)
    print(response)

    # Get path traces summary
    print('\nPrinting path trace summary...')
    query_string_params = {'destIP': dst_ip_address, 'limit': 2}
    response = get_path_traces_summary(headers,  query_string_params)
    print(response)

    # Delete path trace summary
    print('\nPrinting path trace delete status code ...')
    response = delete_path_trace(headers, flow_analysis_id)
    print(response.status_code)


if __name__ == "__main__":
    main()