Sei sulla pagina 1di 161

NSO300

CISCO NETWORK SERVICES


ORCHESTRATOR (NSO)
ADVANCED DESIGN - PYTHON
Version 2.0

Lab Guide
Text Part Number: NSO30020
Americas Headquarters Asia Pacific Headquarters Europe Headquarters
Cisco Systems, Inc. Cisco Systems (USA) Pte. Ltd. Cisco Systems International BV
San Jose, CA Singapore Amsterdam,
The Netherlands

Cisco has more than 200 offices worldwide. Addresses, phone numbers, and fax numbers are listed on the Cisco Website
at www.cisco.com/go/offices.

© 2017 Cisco and/or its affiliates. All rights reserved. Cisco and the Cisco logo are trademarks or registered trademarks of
Cisco and/or its affiliates in the U.S. and other countries. Cisco and the Cisco logo are trademarks or registered trademarks
of Cisco and/or its affiliates in the U.S. and other countries. To view a list of Cisco trademarks, go to this URL:
www.cisco.com/go/trademarks. Third party company names, trademarks, and logos referenced in these materials are the
property of their respective owners and their use does not constitute or imply an endorsement, sponsorship, affiliation,
association or approval by the third parties of these materials or with Cisco. The use of the word partner does not imply a
partnership relationship between Cisco and any other company.

DISCLAIMER WARRANTY: THIS CONTENT IS BEING PROVIDED "AS IS" AND AS SUCH MAY INCLUDE
TYPOGRAPHICAL, GRAPHICS, OR FORMATTING ERRORS. CISCO MAKES AND YOU RECEIVE NO WARRANTIES IN
CONNECTION WITH THE CONTENT PROVIDED HEREUNDER, EXPRESS, IMPLIED, STATUTORY OR IN ANY OTHER
PROVISION OF THIS CONTENT OR COMMUNICATION BETWEEN CISCO AND YOU. CISCO SPECIFICALLY
DISCLAIMS ALL IMPLIED WARRANTIES, INCLUDING WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT
AND FITNESS FOR A PARTICULAR PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE
PRACTICE. This learning product may contain early release content, and while Cisco believes it to be accurate, it falls
subject to the disclaimer above.
Contents
Overview for All Labs......................................................................................1–1
Command Syntax Reference .................................................................................... 1–3

Lab 1: Layer 3 MPLS VPN Service ..............................................................1–4


Task 1: Connect to the Lab ........................................................................1–6
Task 2: Choose a Programming Language ..............................................1–10
Task 3: Analyze the Layer 3 MPLS VPN Service Model ........................1–12
Task 4: Harden the Layer 3 MPLS VPN Service Model .........................1–18
Task 5: Optimize Layer 3 MPLS VPN Implementation .........................1–29
Task 6: Add Layer 3 MPLS VPN Support for
an Additional Device Type .......................................................................1–35

Lab 2: Layer 2 VPN Service Enhancements ..............................................2–1


Task 1: Prepare the Simulated Network Environment ............................2–3
Task 2: Create an L2VPN Service Skeleton ..............................................2–4
Task 3: Implement Python-Based Mapping Logic ....................................2–8
Task 4: Change the YANG Model to Support Reactive FASTMAP .......2–19
Task 5: Implement Pseudowire ID Provisioning
with Reactive FASTMAP .........................................................................2–21
Task 6: Using the ID Allocator Package (Optional) ................................2–28
Task 7: Add Support for Juniper Devices (Optional) ..............................2–32

Lab 3: Creating a Simple Cloud Service Bundle .......................................3–1


Task 1: Create a vRouter Service ..............................................................3–4
Task 2: Create a vFirewall Service ............................................................3–8
Task 3: Create a Cloud Service ................................................................3–18
Task 4: Implement NFV for the Cloud Service .......................................3–26
Task 5: Implement a ping Action .............................................................3–41

Answer Key..........................................................................................................1
Lab 1 .............................................................................................................................. 1

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide iii


This document is for training purposes only. All content is subject to change without notice.
Lab 2 ............................................................................................................................ 11
Lab 3 ............................................................................................................................ 22

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide iv


This document is for training purposes only. All content is subject to change without notice.
Overview for All Labs

Overview
This guide presents the instructions and other information concerning the lab activities
for this course. The activities follow the topics presented in lessons for which you were
provided with the necessary information in order to be able to complete these lab
exercises. You can find the solutions to these lab exercises in the lab activity Answer Key.

Outline
This guide includes these activities and the corresponding lessons:
 Lab 1-1: Layer 3 MPLS VPN Service
Module 1, Lesson 1: Service Applications
 Lab 2-1: Layer 2 VPN Service Enhancements
Module 1, Lesson 1: Service Applications
 Lab 3-1: Creating a Simple Cloud Service Bundle
Module 2, Lesson 3: Service Chaining Design

Required Resources
The following resources and equipment are required for completing the activities in this
lab guide:
 Cisco CCO account to access dCloud
 PC or laptop with a web browser (Internet Explorer or Mozilla Firefox),
Cisco AnyConnect software, and terminal application (Telnet, PuTTY, and
so on) installed
 Access to the Internet

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–1


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Job Aids
The following job aids are available to help you complete the lab activities:
 NSO300_4-3 Network Services Orchestrator (NSO) Advanced Design
Student Guide
 The workstation in the lab contains three documents on the desktop:
 Cisco NSO Getting Started Guide
 Cisco NSO Installation Guide
 Cisco NSO User Guide

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–2


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Command Syntax Reference


This lab guide uses the following conventions for command syntax:

boldface Commands are in boldface and Courier New typeface.


Courier New
Example: Type show running config

Example: Use the name command.

Example: Save your current configuration as the default


startup config.
Router Name# copy running startup

brackets ([ ]) Indicates optional element. You can choose one of the options.
Example:
(config-if)# frame-relay lmi-type
{ansi|cisco|q933a}

italics font Arguments for which you supply values are in italics.
Example: Open file ip tcp window-size bytes

angle brackets (<>) In contexts that do not allow italics, arguments for which you
supply values are enclosed in angle brackets [<>]. Do not type the
brackets when entering the command.
Example: If the command syntax is ping <ip_address>, you
enter ping 192.32.10.12

String A non-quoted set of characters. Type the characters as-is.


Example: (config)# hostname MyRouter

vertical line (|) Indicates that you enter one of the choices. The vertical line
separates choices. Do not type the vertical line when entering the
command.
Example: If the command syntax is show ip route|arp, you
enter either show ip route or show ip arp, but not both.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–3


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Lab 1: Layer 3 MPLS VPN Service

Description
Complete this lab exercise to practice what you learned in the the “Service Applications”
lesson of the “Service Provider VPN Service Design with Cisco NSO” module of this
course.

Activity Objective
You have inherited an implementation of a Layer 3 MPLS VPN service from the service
architect. Unfortunately, the service architect did not implement any validations within
the YANG model and did not include Cisco IOS XR support. Because you are responsible
for the implementation of the service in production, you must make sure that the
appropriate validation is added and that additional device types are supported.
In this activity, you will learn how to use YANG and Python to improve and optimize an
existing Layer 3 MPLS VPN service model. After completing this activity, you will be
able to meet these objectives:
 Use advanced YANG modeling techniques
 Use Python with MAAGIC API to implement advanced service models

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–4


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Visual Objective

The graphic above provides a visual aid for this activity.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–5


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Task 1: Connect to the Lab


The purpose of this task is to connect to the lab environment. Use these steps if you are
using the Cisco dCloud environment. Refer to the separately provided instruction if you
are using another lab environment. (The topology and content of the lab should be the
same.)

Activity Procedure
Complete these steps:
Step 1 Connect to the lab, using one of the available mechanisms.
Step 2 Use a web browser to connect to https://dcloud.cisco.com, and
log in using your CCO account. When asked, choose the Americas
region.
Step 3 Click the My Dashboard link at the top-right corner of the page to
access the lab that has been shared with you.
Step 4 Click the Schedule demo link, and choose the time range for the lab.
Make sure that the lab is scheduled until at least 18:00 (6 P.M.).
Step 5 After the lab starts, click the View Demo link to connect to the lab.
Step 6 Click the Connect Laptop via AnyConnect link and follow the steps
to complete the establishment of a secure session to the lab. Navigate to
Session Details to get the AnyConnect link and credentials.
___________________ Note ________________________________
You must have the Cisco AnyConnect client installed on your PC.
______________________________________________________________

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–6


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Step 7 After the session is established, you can start connecting to lab devices:
 Workstation: Click the Workstation icon in the Topology view.
Then click the Remote Desktop link to open a new browser
window with an RDP session to the Windows desktop. Log in with
the username Administrator and the password C1sco12345.
Alternatively, you can use an arbitrary RDP client, such as
mstsc.exe, to connect to the workstation by using the IP address
198.18.133.253.

 Cisco NSO (Tail-F NCS): If you have an SSH client installed on


your PC, you can access the server directly by using the IP address
of the server (198.18.134.4). Alternatively, you can access the
server from within the RDP session to the workstation where you
have PuTTY shortcuts available on the desktop.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–7


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Step 8 Inspect the topology illustrated in the figure that follows:


 Workstation: The purpose of this Windows desktop is to serve as
the desktop for managing the environment. The workstation
contains desktop shortcuts to access Cisco NSO via SSH, to open
Eclipse for service creation, or to use a browser or SSH client to
connect to the Cisco NSO web UI or CLI (after you have installed
them).
 Cisco NSO: This is a Linux server that will host the Cisco NSO
system.
 DNS: The DNS server is part of the lab but will not be actively used
in any of the labs.

Step 9 Log in to the shell of the NSO system with the username cisco and
the password cisco. Start Cisco NSO if it has not been started
already.
cisco@ncs:~$ source nso-4.2/ncsrc
cisco@ncs:~$ cd ncs-run
cisco@ncs:~/ncs-run$ ncs

Step 10 Start the netsim lab devices if the simulated environment has not
been started already.

cisco@ncs:~$ cd /opt/lab
cisco@ncs:/opt/lab$ ncs-netsim start
DEVICE PE11 OK STARTED
DEVICE PE12 OK STARTED
DEVICE PE31 OK STARTED
DEVICE CE11 OK STARTED
DEVICE CE12 OK STARTED
DEVICE CE21 OK STARTED
DEVICE CE31 OK STARTED
DEVICE PE21 OK STARTED
cisco@ncs:~$

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–8


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Step 11 Log in to the Cisco NSO CLI, using a new SSH session from the
workstation by connecting to TCP port 2024. Alternatively, you can use
the ncs_cli command to log in to the CLI from the Linux shell. Use
the username admin and the password admin to log in to the Cisco
NSO CLI.

cisco@ncs:~$ ncs_cli –u admin

admin connected from 192.168.89.1 using ssh on NCS


admin@ncs#

You are now ready to start the lab tasks.

Activity Verification
You have completed this task when you attain these results:
 You have successfully logged in to the Cisco NSO CLI.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–9


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Task 2: Choose a Programming Language


The purpose of this task is to choose which programming language you will use for the
implementation of the mapping logic. The existing l3mplsvpn service package contains
equivalent implementations in both Java and Python. The two implementations register
to the same service callback.

Activity Procedure
Complete these steps:
Step 1 Edit the file package-meta-data.xml in the l3mplsvpn package
folder in your favorite text editor. Uncomment the second component
with the name l3mplsvpn-python.
<ncs-package xmlns="http://tail-f.com/ns/ncs-packages">
<name>l3mplsvpn</name>
<package-version>1.0</package-version>
<description>Generated Python package</description>
<ncs-min-version>4.2</ncs-min-version>
<component>
<name>l3mplsvpn-python</name>
<application>
<python-class-
name>com.example.l3mplsvpn.l3mplsvpnRFS</python-class-name>
</application>
</component>
</ncs-package>

Step 2 Reload the packages in Cisco NSO.


admin@ncs# packages reload
reload-result {
package cisco-ios
result true
}
reload-result {
package cisco-iosxr
result true
}
reload-result {
package l3mplsvpn
result true
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–10


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Step 3 In the Cisco NSO CLI, examine the operational data for the l3mplsvpn
package with the show packages package l3mplsvpn command.
Verify that the Python component for the l3mplsvpn package is
successfully loaded.
admin@ncs# show packages package l3mplsvpn
packages package l3mplsvpn
package-version 1.0
description "Generated Python package"
ncs-min-version [ 4.2 ]
directory ./state/packages-in-use/1/l3mplsvpn
templates [ l3mplsvpn-iosxr-template l3mplsvpn-ios-
template ]
component l3mplsvpn-python
application python-class-name l3mplsvpn.L3MplsVpn
application start-phase phase2
oper-status up

Activity Verification
You have completed this task when you attain these results:
 The Python component for the l3mplsvpn package is successfully loaded.

 There are no errors in ncs-python-vm- l3mplsvpn.log.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–11


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Task 3: Analyze the Layer 3 MPLS VPN Service Model


The purpose of this task is to analyze an existing deployment of a Layer 3 MPLS VPN
service model:
 Identify possible limitations in the existing Layer 3 MPLS VPN service
model
 Identify functional deficiencies of the existing Layer 3 MPLS VPN service
implementation

Activity Procedure
Complete these steps:
Step 1 Log in to the shell of the Cisco NSO system, using the username cisco
and the password cisco. View the directories and files in the ncs-
run/packages directory.

cisco@ncs:~$ cd ncs-run/packages
cisco@ncs:~/ncs-run/packages$ ls -l

Step 2 Review the current service model for the l3mplsvpn service package
located in the ~/ncs-run/packages/l3mplsvpn/src/yang
directory.

module l3mplsvpn {
namespace "http://com/example/l3mplsvpn";
prefix l3mplsvpn;

import ietf-inet-types { prefix inet; }


import tailf-ncs { prefix ncs; }
import tailf-common { prefix tailf; }

augment /ncs:services {
leaf l3mplsvpn-id-cnt {
description "Provides a unique 32-bit number used
as VPN instance identifier";
type uint32;
default 1;
}
}

augment /ncs:services {
list l3mplsvpn {
tailf:info "Layer-3 MPLS VPN Service";
key vpn-name;

uses ncs:service-data;
© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–12
This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

ncs:servicepoint "l3mplsvpn-servicepoint";

leaf vpn-name {
tailf:info "Service Instance Name";
type string;
}

leaf vpn-id {
tailf:info "Service Instance ID (1 to 65535)";
type uint32;
}

leaf link-id-cnt {
description "Provides a unique 32-bit number
used as site identifier";
default 1;
type uint64;
}

leaf customer {
tailf:info "VPN Customer";
type leafref {
path "/ncs:customers/ncs:customer/ncs:id";
}
}

// Each VPN service instance can have one or more


interfaces
list link {
tailf:info "PE-CE Attachment Point";
key link-name;

leaf link-name {
tailf:info "Link Name";
type string;
}

leaf link-id {
tailf:info "Link ID (1 to 65535)";
type uint32;
}

leaf device {
tailf:info "PE Router";
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}

leaf pe-ip {

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–13


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

tailf:info "PE-CE Link IP Address";


type string;
}

leaf ce-ip {
tailf:info "CE Neighbor IP Address";
type string;
}

leaf interface {
tailf:info "Customer Facing Interface";
type string;
}

leaf routing-protocol {
tailf:info "Routing option for the PE-CE
link";
type enumeration {
enum bgp;
enum rip;
}
}
}
}
}
}

The following table describes the meaning of some of the leafs in the model:

Leaf Description
vpn-name A descriptive name of the VPN instance with no other
functionality.

vpn-id An identifier that is used in the configuration of MP-BGP


to construct the route distinguisher (RD) and route target
(RT) values, using the following formula:
64499:<vpn-id>
The possible values are from 1 to 65535 in order to support
IP 4-byte ASN-based formats.

customer Allocation of a service instance to an existing customer.

link-name A descriptive name of the service link with no other


functionality.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–14


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Leaf Description
link-id An identifier of each link. Currently not used for any
functional purpose.

device Defines the PE device to which the customer site is


connected via the configured service link.

interface Defines the customer-facing interface on the selected


device.

pe-ip The IP address assigned to the PE router on the customer-


facing interface.

ce-ip The IP address assigned to the CE router on the PE-CE


link; used on the PE router to configure the BGP neighbor
if BGP is used for peering.

routing- Allows the selection of one of the two currently supported


protocol PE-CE routing protocols: BGP and RIP.

Step 3 Provision a service instance, using the Cisco NSO CLI:


services l3mplsvpn vpn1
customer ACME
vpn-id 1
link site1
link-id 1
device PE11
interface 0/8
pe-ip 172.31.1.1
ce-ip 172.31.1.2
routing-protocol bgp
exit
!
link site2
link-id 2
device PE31
interface 0/8
pe-ip 172.31.2.1
ce-ip 172.31.2.2
routing-protocol bgp
exit
!
exit
!

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–15


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Step 4 Use the following table to note the problems that you have identified
with the current design and implementation:

Issue Description

Step 5 To help identify some of the issues with the design and
implementation, try to add a third link, using the following CLI
commands:

services l3mplsvpn vpn1


link site3
link-id 1
device PE11
interface 0/0/0/8
pe-ip 172.31.2.1
ce-ip 300.31.2.2
exit

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–16


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

!
exit
services l3mplsvpn vpn2
vpn-id 1
link site1
link-id 1
device CE11
interface 0/5
exit
!
exit

The model allows you to enter a new link with the same link ID that
another link uses. The same applies to the VPN identifier. The model
allows you to do the following:
 Assign the same interface to multiple service links
 Enter the same IP addresses to multiple interfaces
 Not specify the routing option which may result in no connectivity
between customer site
The IP addresses can be omitted, which will not result in a successful
device configuration. IP addresses can be any strings that will not result in
a successful device configuration. You can choose CE devices when
configuring PE functionality.
______________________ Note ________________________________
The lack of a proper data model and the lack of controls in the Python
code can result in Python exceptions or possible misconfiguration of
devices.
_________________________________________________________________

Activity Verification
You have completed this task when you attain these results:
 You have successfully identified possible limitations in the existing Layer 3
MPLS VPN service model.
 You have successfully identified functional deficiencies of the existing Layer 3
MPLS VPN service implementation.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–17


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Task 4: Harden the Layer 3 MPLS VPN Service Model


The purpose of this task is to analyze an existing deployment of a Layer 3 MPLS VPN
service and to design a more reliable solution. You will also implement improvements
based on the identified limitations of the original service model.

Activity Procedure
Complete these steps:
Step 1 Redesign the YANG service model, based on your own list of identified
issues and based on the requirements listed in the following table.
Requirement Suggestions

Limit VPN ID and Site ID values and enforce uniqueness.


Leafs: vpn-id and link-id Use the following YANG statements
to accomplish the required items:
 Ensure uniqueness of
values.  Use the unique statement.

 Limit the values to the  Use the range statement.


range 1 to 65535.
 Use the error-message
 Provide a descriptive statement to provide a
error message in case of a meaningful message in case of
wrong input. a validation failure.
Example:
list l3mplsvpn {
tailf:info "Layer-3 MPLS VPN Service";
key vpn-name;
unique vpn-id;
...

leaf vpn-id {
type uint32 {
range "1..65535" {
error-message "VPN ID is out of range. Should be between 1 and
65535.";
}
}
}
...
list link {
tailf:info "PE-CE Attachment Point";
key link-name;
unique "link-id";
...
leaf link-id {
type uint32 {
range "1..65535" {
error-message "Link ID is out of range. Should be between 1
and 65535.";
}
}
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–18


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Requirement Suggestions

Prevent reuse of interfaces.


Leaf: interface Use the following YANG statements
to accomplish the required items:
 Prevent reuse of interface
on multiple service links.  Use the must statement to
validate the selected interface
 Make the parameter against the currently
mandatory. allocated interfaces on the
selected device.
 Use the mandatory
statement to ensure that the
interface is defined.
 Use the error-message
statement to provide a
meaningful message in case of
a validation failure.
 Use the show running-
config services
l3mplsvpn | display
xpath | display prefix
command to see the data
structure for the existing
service instances in XPath
format.
 If you have issues, you can
troubleshoot your XPath
expression using the
xpath.trace log file.

Example:
 The following printout illustrates how to inspect the current data
structure in XPath format, including the prefix.
admin@ncs# show running-config services l3mplsvpn | display xpath |
display prefix
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-name='vpn1']/l3mplsvpn:vpn-id 33
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-name='vpn1']/l3mplsvpn:customer ACME
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-
name='vpn1']/l3mplsvpn:link[l3mplsvpn:link-name='site1']/l3mplsvpn:link-id 1
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-
name='vpn1']/l3mplsvpn:link[l3mplsvpn:link-name='site1']/l3mplsvpn:device PE11
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-
name='vpn1']/l3mplsvpn:link[l3mplsvpn:link-name='site1']/l3mplsvpn:interface 0/8
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-
name='vpn1']/l3mplsvpn:link[l3mplsvpn:link-name='site1']/l3mplsvpn:pe-ip 172.31.1.1

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–19


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Requirement Suggestions
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-
name='vpn1']/l3mplsvpn:link[l3mplsvpn:link-name='site1']/l3mplsvpn:ce-ip 172.31.1.2
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-
name='vpn1']/l3mplsvpn:link[l3mplsvpn:link-name='site1']/l3mplsvpn:routing-protocol
bgp
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-
name='vpn1']/l3mplsvpn:link[l3mplsvpn:link-name='site2']/l3mplsvpn:link-id 1
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-
name='vpn1']/l3mplsvpn:link[l3mplsvpn:link-name='site2']/l3mplsvpn:device PE21
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-
name='vpn1']/l3mplsvpn:link[l3mplsvpn:link-name='site2']/l3mplsvpn:interface 0/0/0/8
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-
name='vpn1']/l3mplsvpn:link[l3mplsvpn:link-name='site2']/l3mplsvpn:pe-ip 172.31.2.1
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-
name='vpn1']/l3mplsvpn:link[l3mplsvpn:link-name='site2']/l3mplsvpn:ce-ip 172.31.2.2
/ncs:services/l3mplsvpn:l3mplsvpn[l3mplsvpn:vpn-
name='vpn1']/l3mplsvpn:link[l3mplsvpn:link-name='site2']/l3mplsvpn:routing-protocol
bgp

 The following example illustrates the must statement that


verifies that the newly provisioned interfaces are not already in
use.
list link {
tailf:info "PE-CE Attachment Point";
key link-name;
unique "link-id";
unique "device interface";
...

leaf interface {
tailf:info "Customer Facing Interface";
mandatory true;
type string;
must "count(../../../l3mplsvpn[vpn-name != current()/../../vpn-
name]" +
"/link[device = current()/../device][interface = current()]) =
0" {
error-message "Interface is already used for another link.";
}
}
...

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–20


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Requirement Suggestions

Restrict IP addresses to 172.16.0.0/12.


Leaf: pe-ip, ce ip and rip- Use the following YANG statements
net to accomplish the required items:
 Restrict IP addresses to  Use the inet:ipv4-address
the range 172.16.0.0/12. data type to ensure the proper
IPv4 address format.
 Make the parameter
mandatory.  Use the pattern statement
with a regular expression to
limit the range.
 Use the mandatory
statement to ensure that the
interface is defined.
 Use the error-message
statement to provide a
meaningful message in the
case of a validation failure.
Example of the pe-ip leaf:

leaf pe-ip {
tailf:info "PE Interface IP Address";
mandatory true;
type inet:ipv4-address {
pattern "172\.([1][6-9]|[2][0-9]|3[0-1])\..*" {
error-message "Invalid IP address. IP address should be in the
172.16.0.0/12 range.";
}
}
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–21


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Requirement Suggestions

Restrict device list to PE routers.


Leaf: device Use the following YANG statements
to accomplish the required items:
 Restrict devices to PE
routers.  Use the must statement with
the starts-with XPath
 Make the parameter
function to check if the name
mandatory.
starts with “PE” (all PE
routers’ names start this
way). Alternatively, you could
group devices into device
groups and then access them
through a device group
defined for PE routers.
 Use the mandatory
statement to ensure that the
interface is defined.
 Use the error-message
statement to provide a
meaningful message in case of
a validation failure.
Example:

leaf device {
tailf:info "PE Router";
mandatory true;
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
must "starts-with(current(),'PE')" {
error-message "Only PE devices can be selected.";
}
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–22


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Requirement Suggestions

Ensure that at least one link is associated with a VPN.


List: link Use the following YANG statements
to accomplish the required tasks:
 Ensure that there is at
least one link assigned to  Use the min-elements
a VPN instance. statement to define the
minimum number of entries
in a list.
Example:

list link {
tailf:info "PE-CE Attachment Point";
key link-name;
unique "link-id";
unique "device interface";
min-elements 1;

...

Control the validity and visibility of IP address leafs.


Leafs: ce-ip, rip net Use the following YANG statements to
accomplish the required tasks:
 pe-ip is always valid.
 Use the when statement to
 ce-ip is valid only control the visibility of the IP
when BGP is selected. address leafs based on the value
 rip-net is valid only of the routing-protocol leaf.
when RIP is selected.  Use the mandatory statement
to ensure that the IP address is
provided.
Example:
leaf pe-ip {
tailf:info "PE Interface IP Address";
...
}

leaf ce-ip {
tailf:info "CE Interface IP Address";
when "../routing-protocol='bgp'";
mandatory true;
...
}

leaf rip-net {
tailf:info "IP network for RIP";
when "../routing-protocol='rip'";
mandatory true;
...

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–23


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Requirement Suggestions

Add default values where appropriate.


Leaf: routing-protocol Use the following YANG statements to
accomplish the required tasks:
 Make BGP the default
routing protocol if no  Use the default statement to
selection is made. specify the default leaf value.
Example:

leaf routing-protocol {
tailf:info "Routing option for the PE-CE link";
type enumeration {
enum bgp;
enum rip;
}
default bgp;
}

Hide leafs that should not be accessible to the operator.

Leafs: l3mplsvpn-id-cnt Use the following YANG statements to


and link-id-cnt, vpn-id accomplish the required tasks:
and link id
 Use the tailf:hidden
 Hide the IDs and the statement to hide the leaf from
counters for automatic the northbound interfaces.
provisioning of IDs from
Note: You may have noticed that the
the CLI and web UI.
vpn-id and link-id values are
ignored. This is due to the automatic
assignment of these two values using
Python code that you will also modify
in a later task.
Example:

leaf link-id-cnt {
description "Provides a unique 32-bit number used as site
identifier";
tailf:hidden "Counter";
default 1;
type uint64 { range "1..65535"; }
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–24


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Step 2 Compile the l3mplsvpn package by using the make command.


cisco@NCS:~/ncs-run/packages/l3mplsvpn/src$ make
cd java && ant -q all

BUILD SUCCESSFUL
Total time: 0 seconds
cisco@NCS:~/ncs-run/packages/l3mplsvpn/src$

Step 3 Reload the packages. Your package should be successfully loaded.


admin@ncs# packages reload
reload-result {
package cisco-ios
result true
}
reload-result {
package cisco-iosxr
result true
}
reload-result {
package iosxe
result true
}
reload-result {
package l3mplsvpn
result true
}
admin@ncs#

Step 4 Verify the prevention of interface reuse in your model by trying to


deploy the following service instance.

services l3mplsvpn vpn111


customer ACME
link site1
device PE11
interface 0/9
pe-ip <IP>
ce-ip <IP>
routing-protocol bgp
exit
link site2
device PE11
interface 0/9
pe-ip <IP>
ce-ip <IP>
routing-protocol bgp
top
commit

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–25


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

The verification should fail and display your error messages:


admin@ncs# conf
Entering configuration mode terminal
admin@ncs(config)# services l3mplsvpn vpn111
admin@ncs(config-l3mplsvpn-vpn111)# customer ACME
admin@ncs(config-l3mplsvpn-vpn111)# link site1
admin@ncs(config-link-site1)# device PE11
admin@ncs(config-link-site1)# interface 0/9
admin@ncs(config-link-site1)# routing-protocol bgp
admin@ncs(config-link-site1)# exit
admin@ncs(config-l3mplsvpn-vpn111)# link site2
admin@ncs(config-link-site2)# device PE11
admin@ncs(config-link-site2)# interface 0/9
admin@ncs(config-link-site2)# routing-protocol bgp
admin@ncs(config-link-site2)# top
admin@ncs(config)# validate
Aborted: values are not unique: PE11, 0/9
'services l3mplsvpn vpn111 link site1 device'
'services l3mplsvpn vpn111 link site1 interface'
'services l3mplsvpn vpn111 link site2 device'
'services l3mplsvpn vpn111 link site2 interface'
admin@ncs(config)#

Question: Which mechanism prevented this instance from being


accepted?
Step 5 Verify the prevention of interface reuse again in your model by trying
to deploy the following service instance.

services l3mplsvpn vpn121


customer ACME
link site1
device PE11
interface 0/8
routing-protocol bgp
top

The verification should fail and display your error messages:

admin@ncs# conf
Entering configuration mode terminal
admin@ncs(config)# services l3mplsvpn vpn121
admin@ncs(config-l3mplsvpn-vpn121)# customer ACME
admin@ncs(config-l3mplsvpn-vpn121)# link site1
admin@ncs(config-link-site1)# device PE11
admin@ncs(config-link-site1)# interface 0/8
admin@ncs(config-link-site1)# routing-protocol bgp
admin@ncs(config-link-site1)# top
admin@ncs(config)# validate
Aborted: 'services l3mplsvpn vpn121 link site1 interface'
(value "0/8"): Interface is already used for another link.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–26


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

admin@ncs(config)#

Question: Which mechanism prevented this instance from being


accepted this time?
Step 6 Verify the IP address verification for the three statically assigned IP
addresses by trying to deploy the following service instance.

services l3mplsvpn vpn121


customer ACME
link site1
device PE11
interface 0/9
routing-protocol rip
pe-ip 172.50.100.1
ce-ip 172.50.100.2
rip-net 172.50.100.0
top
commit

The verification should fail and display your error messages:

admin@ncs(config)# services l3mplsvpn vpn121


admin@ncs(config-l3mplsvpn-vpn121)# customer ACME
admin@ncs(config-l3mplsvpn-vpn121)# link site1
admin@ncs(config-link-site1)# device PE11
admin@ncs(config-link-site1)# interface 0/9
admin@ncs(config-link-site1)# pe-ip 172.50.100.1
------------------------------------^
syntax error: Invalid IP address. IP address should be in
the 172.16.0.0/12 range.
admin@ncs(config-link-site1)# ce-ip 172.50.100.2
------------------------------^
syntax error: unknown command
admin@ncs(config-link-site1)# rip-net 172.50.100.0
------------------------------^
syntax error: unknown command
admin@ncs(config-link-site1)# routing-protocol rip
admin@ncs(config-link-site1)# top
admin@ncs(config)#

Question: Why is there a difference in where Cisco NSO is pointing to


a mistake?
____________________________ Note ________________________________
The PE IP address should be rejected because of the IP address. The CE IP
and the RIP network should be rejected because the default routing protocol is
BGP, which prevents these two parameters from being used. Putting the
routing-protocol rip command ahead would solve this problem, but then
all of the IP parameters would fail the IP range check.
________________________________________________________________________

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–27


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Step 7 Verify the following other functions:


 Visibility of VPN and link IDs: they should no longer be available.
 Visibility of PE routers only.

admin@ncs# conf
Entering configuration mode terminal
admin@ncs(config)# services l3mplsvpn test
admin@ncs(config-l3mplsvpn-test)# ?
Possible completions:
check-sync Check if device config is according to
the service
commit-queue
customer VPN Customer
deep-check-sync Check if device config is according to
the service
get-modifications Get the configuration data this
service created
link PE-CE Attachment Point
re-deploy Run/Dryrun the service logic again
un-deploy Undo the effects of this service to
the network
---

commandadmin@ncs(config-l3mplsvpn-test)# link site1
admin@ncs(config-link-site1)# ?
Possible completions:
device PE Router
interface Customer Facing Interface
pe-ip PE Interface IP Address
routing-protocol Routing option for the PE-CE link
---

admin@ncs(config-link-site1)# device ?
Possible completions:
PE11 PE12 PE21 PE31
admin@ncs(config-link-site1)# device

Activity Verification
You have completed this task when you attain these results:
 You have successfully analyzed an existing deployment of a Layer 3 MPLS
VPN service and have designed a more reliable solution.
 You have successfully implemented improvements based on the identified
limitations of the original service model.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–28


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Task 5: Optimize Layer 3 MPLS VPN Implementation


The purpose of this task is to analyze an existing deployment of a Layer 3 MPLS VPN
service and to design an optimized solution:
 Automate allocation of PE-CE IP address (pe-ip)

 Automate allocation of CE neighbor address (ce-ip)

Activity Procedure
Complete these steps:
Step 1 Use the existing service framework to add the required automation
techniques. Use your preferred editor to edit the Python code:
 vim or nano on a Linux server (NSO)
 PyCharm from the workstation
 Notepad++ from the workstation (has YANG and Python syntax
highlighting). Note that there is a share available on the
workstation to access the files on a Linux server (NSO).
 Notepad from the workstation
Open Python file ~/ncs- run/packages/
l3mplsvpn/python/l3mplsvpn_callbacks.py.

Step 2 Note that the Python service module contains a class with the name
ServiceCallbacks. The implemented service callbacks for this
service are as follows:
 Pre-modification: Used to handle automatic assignment of VPN
ID and Link ID
 Create: Used to configure devices based on service model and
configuration data
# -*- mode: python; python-indent: 4 -*-
import _ncs
from ncs.application import Service
import ncs.template

TYPE_CISCO_IOS = '{tailf-ned-cisco-ios}'
TYPE_CISCO_IOSXR = '{tailf-ned-cisco-ios-xr}'

# ------------------------
# SERVICE CALLBACK EXAMPLE
# ------------------------
class ServiceCallbacks(Service):

# The create() callback is invoked inside NCS FASTMAP


and

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–29


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

# must always exist.


@Service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=',
service._path, ')')

# Implementation omitted from listing for brevity

@Service.pre_modification
def cb_pre_modification(self, tctx, op, kp, root,
proplist):
self.log.info('Service premod(service=', kp, ')')

# Implementation omitted from listing for brevity

def _get_device_type(root, device):


# Return module used by device, to determine device type
modules = root.devices.device[device].module.keys()
return str(modules[0])

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–30


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Step 3 Implement the following changes to optimize the service model:


 Ensure that manual entry of IP address parameters is still allowed
and that existing service instances can retain existing values. Find
the existing code that reads the IP address parameters from the
service input parameters using the Maagic API.
@Service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=',
service._path, ')')

vpn_id = [x[1] for x in proplist if x[0] == 'vpn-


id'][0]

tvars = ncs.template.Variables()
template = ncs.template.Template(service)
tvars.add('VPNID', vpn_id)

for link in service.link:


device_type = _get_device_type(root,
link.device)

# Allow manual entry from YANG model


link_ip = link.pe_ip
peer_ip = link.ce_ip
rip_net = link.rip_net

link_id = int([x[1] for x in proplist if x[0] ==


'link-id-'+link.link_name][0])

 Automate the calculation of all IP addresses based on the per-


service unique and automatically generated link-id parameter if
they are not manually defined:
− pe-ip: 172.<o2>.<o3>.<o4_pe>
− ce-ip: 172. <o2>.<o3>.<o4_ce>
− rip-net: 172. <o2>.<o3>.0
− Link subnet mask is fixed at /30.
The following sample code performs the preceding calculation (add after
link_id = … line):
# Calculate IP address from unique site ID: 172.x.y.z
pe_ip_o2 = 31 - (link_id * 4) % 4096 # Second octet
pe_ip_o3 = ((link_id * 4) % 4096) / 64 # Third octet
pe_ip_o4 = ((link_id * 4) % 4096) % 64 + 1 # Fourth octet
ce_ip_o4 = pe_ip_o4 + 1 # Fourth octet
for CE side

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–31


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

 Ensure that manual entry of IP address parameters is still allowed


and that existing service instances can retain existing values
(manual entry overrides the calculated value). Check to see if the
service input parameters were set, and use calculated values if none
were provided:
if not link_ip:
link_ip = '172.{}.{}.{}'.format(pe_ip_o2, pe_ip_o3,
pe_ip_o4)
if not peer_ip:
peer_ip = '172.{}.{}.{}'.format(pe_ip_o2, pe_ip_o3,
ce_ip_o4)
if not rip_net:
rip_net = '172.{}.0.0'.format(pe_ip_o2)

 In the previous task, you made the IP address parameters


mandatory. Now you need to remove that restriction, because you
will create code that automatically assigns IP addresses.

leaf pe-ip {
mandatory false;
}

leaf ce-ip {
mandatory false;
}

leaf rip-net {
mandatory false;
}

Step 4 Compile the l3mplsvpn package.


cisco@NCS:~/ncs-run/packages/l3mplsvpn/src$ make
cd java && ant -q all

BUILD SUCCESSFUL
Total time: 0 seconds
pylint --disable=R,C --reports=n ../python/__init__.py ||
(test $? -ge 4)
No config file found, using default configuration
************* Module python
W: 1, 0: Relative import 'l3mplsvpn', should be
'python.l3mplsvpn' (relative-import)
pylint --disable=R,C --reports=n
../python/l3mplsvpn_callbacks.py || (test $? -ge 4)
No config file found, using default configuration
************* Module python.l3mplsvpn_callbacks
W: 18,49: Access to a protected member _path of a client
class (protected-access)
pylint --disable=R,C --reports=n ../python/l3mplsvpn.py ||
(test $? -ge 4)
No config file found, using default configuration

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–32


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

************* Module python.l3mplsvpn


W: 4, 0: Relative import 'l3mplsvpn_callbacks', should be
'python.l3mplsvpn_callbacks' (relative-import)
cisco@NCS:~/ncs-run/packages/l3mplsvpn/src$

Step 5 Reload the packages. Your package should be loaded successfully.


admin@ncs# packages reload
reload-result {
package cisco-ios
result true
}
reload-result {
package cisco-iosxr
result true
}
reload-result {
package iosxe
result true
}
reload-result {
package l3mplsvpn
result true
}
admin@ncs#

Step 6 Deploy a new service instance without specifying the IP addresses.

services l3mplsvpn vpn41


customer ACME
link site1
device PE11
interface 0/15
routing-protocol bgp
exit
link site2
device PE31
interface 0/15
routing-protocol bgp
top

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–33


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Step 7 Perform a dry-run commit command to inspect the configuration.


admin@ncs(config)# commit dry-run outformat native
device PE11
vrf definition vpn4
description L3 MPLS VPN for customer ACME
rd 1:4
address-family ipv4
exit-address-family
!
route-target export 1:4
route-target import 1:4
!
interface GigabitEthernet0/15
ip address 172.31.0.5 255.255.255.252
exit
router bgp 1
address-family ipv4 unicast vrf vpn4
neighbor 172.31.0.6 remote-as 65001
redistribute connected
redistribute static
exit-address-family
!
!
device PE31
vrf definition vpn4
description L3 MPLS VPN for customer ACME
rd 1:4
address-family ipv4
exit-address-family
!
route-target export 1:4
route-target import 1:4
!
interface GigabitEthernet0/15
ip address 172.31.0.9 255.255.255.252
exit
router bgp 1
address-family ipv4 unicast vrf vpn4
neighbor 172.31.0.10 remote-as 65001
redistribute connected
redistribute static
exit-address-family
!
!
admin@ncs(config)# commit
Commit complete.
admin@ncs(config)#

Activity Verification
You have completed this task when you attain these results:
 You have successfully analyzed an existing deployment of a Layer 3 MPLS
VPN service and designed an optimized solution.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–34


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

Task 6: Add Layer 3 MPLS VPN Support for an Additional


Device Type
The purpose of this task is to analyze the existing deployment of a Layer 3 MPLS VPN
service and to design and augment the solution according to the following requirements:
 Add Layer 3 MPLS VPN support for Cisco IOS XR devices.

Activity Procedure
Complete these steps:
Step 1 Augment the existing functionality to add another device type. Create a
test service instance named vpn2 by using PE21 as one of the devices.
services l3mplsvpn vpn2
customer ACME
link site1
device PE12
interface 0/7
routing-protocol bgp
exit
link site2
device PE21
interface 0/0/0/8
routing-protocol bgp
top

______________________ Note ________________________________


The PE21 router in the lab is a Cisco IOS XR router. So far, no
configuration could be pushed to this router.
_________________________________________________________________
Step 2 The following printout illustrates the native configuration of a sample
Layer 3 MPLS VPN instance.

vrf vpn10001 ! Leaf: vpn-id


address-family ipv4 unicast
import route-target 1:10001 ! Leaf: vpn-id
export route-target 1:10001 ! Leaf: vpn-id
!
interface GigabitEthernet0/0/0/1
vrf vpn10001 ! Leaf: vpn-id
ipv4 address 172.31.1.5 255.255.255.252 ! Leaf: pe-ip
!
router bgp 1
vrf vpn10001 ! Leaf: vpn-id
rd 1:10001 ! Leaf: vpn-id
address-family ipv4 unicast
redistribute connected
redistribute static
!

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–35


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

neighbor 172.31.1.6 ! Leaf: ce-ip


remote-as 65001
address-family ipv4 unicast
route-policy pass in
allowas-in 3
route-policy pass out
as-override
default-originate
route-policy pass
pass
end-policy
!

______________________ Note ________________________________


You may notice that RIP configuration is missing from the Cisco IOS
XR sample configuration output. The development NEDs that we use in
the labs do not support RIP configuration commands. Of course, the
latest production-grade NED has support for RIP on Cisco IOS XR as
well.
_________________________________________________________________
As you can see from the configuration, the Cisco IOS XR device requires
the same set of parameters as Cisco IOS devices. The main difference is
in the CLI, which results in a different NED data model.
You can accomplish this task in two ways:
 Directly write configuration parameters into the NED’s data
structure (the same way that it is done for Cisco IOS devices).
 Alternatively, you can use templates to simplify implementation
and maintenance of the configuration. The following printout
illustrates the XML version of the preceding configuration.
Step 3 To get an XML version of a configuration, you should configure s
service instance through the Cisco NSO CLI directly on a Cisco IOS XR
device and then issue the commit dry run outformat xml command
to get the XML version of the native configuration.

<vrf xmlns="http://tail-f.com/ned/cisco-ios-xr">
<vrf-list>
<name>vpn10001</name>
<address-family>
<ipv4>
<unicast>
<import>
<route-target>
<address-list>
<name>1:10001</name>
</address-list>
</route-target>
</import>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–36


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

<export>
<route-target>
<address-list>
<name>1:10001</name>
</address-list>
</route-target>
</export>
</unicast>
</ipv4>
</address-family>
</vrf-list>
</vrf>
<router xmlns="http://tail-f.com/ned/cisco-ios-xr">
<bgp>
<bgp-no-instance>
<id>1</id>
<vrf>
<name>vpn10001</name>
<neighbor>
<id>172.31.1.6</id>
<remote-as>65001</remote-as>
<address-family>
<ipv4>
<unicast>
<route-policy>
<direction>in</direction>
<name>pass</name>
</route-policy>
<route-policy>
<direction>out</direction>
<name>pass</name>
</route-policy>
<as-override/>
<default-originate/>
</unicast>
</ipv4>
</address-family>
</neighbor>
<address-family>
<ipv4>
<unicast>
<redistribute>
<connected/>
<static/>
</redistribute>
</unicast>
</ipv4>
</address-family>
<rd>1:10001</rd>
</vrf>
</bgp-no-instance>
</bgp>
<static>
<address-family>
<ipv4>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–37


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

<unicast>
<routes>
<net>192.168.21.0/24</net>
<interface>GigabitEthernet0/0/0/1</interface>
<address>172.31.1.6</address>
</routes>
</unicast>
</ipv4>
</address-family>
</static>
</router>
<interface xmlns="http://tail-f.com/ned/cisco-ios-xr">
<GigabitEthernet>
<id>0/0/0/1</id>
<ipv4>
<address>
<mask>255.255.255.252</mask>
<ip>172.31.1.5</ip>
</address>
</ipv4>
<vrf>vpn10001</vrf>
</GigabitEthernet>
</interface>
<route-policy xmlns="http://tail-f.com/ned/cisco-ios-xr"
tags="merge">
<name>pass</name>
<cmd>
<value>pass</value>
</cmd>
</route-policy>

Step 4 Replace the specific parameters in the preceding template with


variables in the form of “$VARNAME” and create a configuration
template:

<config-template xmlns="http://tail-f.com/ns/config/1.0"
servicepoint="l3mplsvpn">
<devices xmlns="http://tail-f.com/ns/ncs">
<device tags="nocreate">
<name>{$DEVICE}</name>
<config>
<vrf xmlns="http://tail-f.com/ned/cisco-ios-xr"
tags="merge">
<vrf-list>
<name>vpn{$VPNID}</name>
<address-family>
<ipv4>
<unicast>
<import>
<route-target>
<address-list>
<name>1:{$VPNID}</name>
</address-list>
</route-target>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–38


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

</import>
<export>
<route-target>
<address-list>
<name>1:{$VPNID}</name>
</address-list>
</route-target>
</export>
</unicast>
</ipv4>
</address-family>
</vrf-list>
</vrf>
<router xmlns="http://tail-f.com/ned/cisco-ios-xr"
tags="merge">
<bgp>
<bgp-no-instance>
<id>1</id>
<vrf>
<name>vpn{$VPNID}</name>
<neighbor>
<id>{$CEIP}</id>
<remote-as>65001</remote-as>
<address-family>
<ipv4>
<unicast>
<route-policy>
<direction>in</direction>
<name>pass</name>
</route-policy>
<route-policy>
<direction>out</direction>
<name>pass</name>
</route-policy>
<as-override/>
<default-originate/>
</unicast>
</ipv4>
</address-family>
</neighbor>
<address-family>
<ipv4>
<unicast>
<redistribute>
<connected/>
<static/>
</redistribute>
</unicast>
</ipv4>
</address-family>
<rd>1:{$VPNID}</rd>
</vrf>
</bgp-no-instance>
</bgp>
</router>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–39


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

<interface xmlns="http://tail-f.com/ned/cisco-ios-xr"
tags="merge">
<GigabitEthernet>
<id>{$INTERFACE}</id>
<ipv4>
<address>
<mask>255.255.255.252</mask>
<ip>{$PEIP}</ip>
</address>
</ipv4>
<vrf>vpn{$VPNID}</vrf>
</GigabitEthernet>
</interface>
<route-policy xmlns="http://tail-f.com/ned/cisco-ios-
xr" tags="merge">
<name>pass</name>
<cmd>
<value>pass</value>
</cmd>
</route-policy>
</config>
</device>
</devices>
</config-template>

Step 5 Create a templates subdirectory in your l3mplsvpn package


directory.
Step 6 Store the XML configuration template in the templates subdirectory
of the l3mplsvpn package, using l3mpls-iosxr-template.xml as
the filename.
Step 7 Implement the service parameter to template variable mapping in your
Python code, as shown in the example below.
if device_type == TYPE_CISCO_IOS:
self.log.info('Applying IOS template for device ',
link.device)
template.apply('l3mplsvpn-ios-template', tvars)
elif device_type == TYPE_CISCO_IOSXR:
self.log.info('Applying IOS-XR template for device ',
link.device)
template.apply('l3mplsvpn-iosxr-template', tvars)
else:
raise Exception('Unknown device type ' + device_type)

Step 8 Compile the l3mplsvpn package.


cisco@NCS:~/ncs-run/packages/l3mplsvpn/src$ make
cd java && ant -q all

BUILD SUCCESSFUL
Total time: 0 seconds

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–40


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

pylint --disable=R,C --reports=n ../python/__init__.py || (($? >=


4))
No config file found, using default configuration
************* Module python
W: 1, 0: Relative import 'l3mplsvpn', should be
'python.l3mplsvpn' (relative-import)
pylint --disable=R,C --reports=n ../python/l3mplsvpn.py || (($?
>= 4))
No config file found, using default configuration
************* Module python.l3mplsvpn
W: 4, 0: Relative import 'l3mplsvpn_callbacks', should be
'python.l3mplsvpn_callbacks' (relative-import)
pylint --disable=R,C --reports=n ../python/l3mplsvpn_callbacks.py
|| (($? >= 4))
No config file found, using default configuration
************* Module python.l3mplsvpn_callbacks
W: 18,49: Access to a protected member _path of a client class
(protected-access)

Step 9 Reload the packages. Your package should be loaded successfully.


admin@ncs# packages reload
reload-result {
package cisco-ios
result true
}
reload-result {
package cisco-iosxr
result true
}
reload-result {
package iosxe
result true
}
reload-result {
package l3mplsvpn
result true
}
admin@ncs#

Step 10 Redeploy the existing service vpn2 instance that makes use of router
PE21. You should now see that Cisco NSO has detected that the service
requires configuration also on device PE21, which was initially not
configured because this device type was not supported.

admin@ncs# services l3mplsvpn vpn2 re-deploy dry-run


cli {
device {
name PE21
data config {
cisco-ios-xr:interface {
GigabitEthernet 0/0/0/8 {
ipv4 {
address {

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–41


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

+ ip 172.31.2.1;
+ mask 255.255.255.252;
}
}
+ vrf vpn2;
}
}
cisco-ios-xr:router {
bgp {
bgp-no-instance 1 {
+ vrf vpn2 {
+ rd 1:2;
+ address-family {
+ ipv4 {
+ unicast {
+ redistribute
{
+ connected
{
+ }
+ static {
+ }
+ }
+ }
+ }
+ }
+ neighbor 172.31.0.10 {
+ remote-as 65001;
+ address-family {
+ ipv4 {
+ unicast {
+ route-
policy in {
+ pass;
+ }
+ route-
policy out {
+ pass;
+ }
+ as-
override {
+ }
+ default-
originate {
+ }
+ }
+ }
+ }
+ }
+ }
}
}
}
cisco-ios-xr:vrf {
+ vrf-list vpn2 {

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–42


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 3 MPLS VPN Service

+ address-family {
+ ipv4 {
+ unicast {
+ import {
+ route-target {
+ address-list
1:2;
+ }
+ }
+ export {
+ route-target {
+ address-list
1:2;
+ }
+ }
+ }
+ }
+ }
+ }
}
}

}
}
admin@ncs#
admin@ncs# services l3mplsvpn vpn2 check-sync
in-sync true
admin@ncs#

Activity Verification
You have completed this task when you attain these results:
 You have successfully analyzed the existing deployment of a Layer 3 MPLS
VPN service and have added Layer 3 MPLS VPN support for Cisco IOS XR
devices.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 1–43


This document is for training purposes only. All content is subject to change without notice.
Lab 2: Layer 2 VPN Service
Enhancements

Description
Complete this lab exercise to practice what you learned in the “Service Applications”
lesson of the “Service Provider VPN Service Design with Cisco NSO” module of this
course.

Activity Objective
In this activity, you will learn how to use Python to implement the mapping logic, which
maps service attributes to device parameters. After completing this activity, you will be
able to meet these objectives:
 Use Maagic API
 Use Python to implement mappings

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–1


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Visual Objective

The graphic above provides a visual aid for this activity.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–2


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Task 1: Prepare the Simulated Network Environment


The purpose of this task is to prepare the simulated network environment. This lab uses
the same simulated network environment as Lab 1. If you are starting this course with
this lab, be sure to follow the steps to start the netsim simulated devices in the first part
of the lab guide.

Activity Procedure
Complete these steps:
Step 1 Log in to the shell of the Cisco NSO system with the username cisco
and the password cisco, and start Cisco NSO if it is not running
already.

cisco@ncs:~$ source nso-4.2/ncsrc


cisco@ncs:~$ cd ncs-run
cisco@ncs:~/ncs-run$ ncs

Step 2 Start the netsim lab devices if the simulated devices have not been
started.

cisco@ncs:~$ cd /opt/lab
cisco@ncs:/opt/lab$ ncs-netsim start
DEVICE PE11 OK STARTED
DEVICE PE12 OK STARTED
DEVICE PE31 OK STARTED
DEVICE CE11 OK STARTED
DEVICE CE12 OK STARTED
DEVICE CE21 OK STARTED
DEVICE CE31 OK STARTED
DEVICE PE21 OK STARTED
cisco@ncs:~$

Activity Verification
You have completed this task when you attain these results:
 Cisco NSO and netsim are running in the lab environment.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–3


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Task 2: Create an L2VPN Service Skeleton


The purpose of this task is to create a Python-based service skeleton for an L2VPN
service.

Activity Procedure
Complete these steps:
Step 1 Use the SSH connection to the Cisco NSO server from the previous
task.
Step 2 Navigate to the Cisco NSO running directory.

Parameter Value Comment


Location of /home/cisco Equals the environment variable
installation package $HOME when logged in as user
cisco.
Cisco NSO local Local installation is recommended
installation type for all purposes except the final
production deployment.
Installation directory $HOME/nso-VERSION Replace the VERSION field with the
NSO version as seen from the
installation file.
This directory will be available in
the $NCS_DIR environment variable
after you use the source ncsrc
command in the next step.
Running directory $HOME/ncs-run The running directory is a
subdirectory of the $HOME directory.

Step 3 Change to the directory $HOME/ncs-run/packages. Use ncs-make-


package ¬ help or man ncs-make-package to learn how to create
packages that use Python mappings. Use l2vpn as the name of the
new service.
ncs-make-package --python-skeleton --service-example --
component-name L2vpn l2vpn

Step 4 For this service, reuse the l2vpn YANG model, which can be found in
the /opt/resources/lab2/ folder. Copy the YANG model to the
$HOME/ncs-run/packages/l2vpn/src/yang folder and replace the
one that was created as a part of the service skeleton. Alternatively,
you can also open both files in your favorite text editor and replace the
contents of the service skeleton YANG model with the one provided in
the /opt/resources folder.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–4


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Step 5 Make sure that you add the following highlighted lines to the Makefile
located in the src folder of the l2vpn package. Because your package
has dependencies on other YANG models, you need to specify where
those can be found. Otherwise, your package will fail at the compile
stage.

SRC = $(wildcard yang/*.yang)
FXS = $(SRC:yang/%.yang=../load-dir/%.fxs)

YANGPATH ?= --yangpath yang


YANGPATH += --yangpath ../../cisco-ios/src/ncsc-
out/modules/yang
YANGPATH += --yangpath ../../cisco-iosxr/src/ncsc-
out/modules/yang

fxs: $(FXS)

Step 6 Optionally, add some instruction to the Makefile that will allow you to
check the syntax and style of your Python code. You can do this by
running the pylint tool on all Python source files. The tool has already
been installed in the lab environment but is not bundled by default
with Cisco NSO installation.
all: fxs pylint

SRC = $(wildcard yang/*.yang)


FXS = $(SRC:yang/%.yang=../load-dir/%.fxs)

YANGPATH ?= --yangpath yang


YANGPATH += --yangpath ../../cisco-ios/src/ncsc-
out/modules/yang
YANGPATH += --yangpath ../../cisco-iosxr/src/ncsc-
out/modules/yang

PYLINT = pylint
PYLINTFLAGS = --disable=R,C --reports=n
PYDIR = ../python
PYTHONFILES = $(wildcard $(PYDIR)/*.py)

pylint: $(patsubst %.py,%.pylint,$(PYTHONFILES))

%.pylint:
$(PYLINT) $(PYLINTFLAGS) $*.py || (test $$? -ge 4)

fxs: $(FXS)

Step 7 Compile the l2vpn package. This will ensure that the YANG model
and any included code are valid.
cisco@NCS:~/ncs-run/packages/l2vpn/src$ make
/home/cisco/nso-4.2/bin/ncsc `ls l2vpn-ann.yang >
/dev/null 2>&1 && echo "-a l2vpn-ann.yang"` \

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–5


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

--yangpath yang --yangpath ../../cisco-


ios/src/ncsc-out/modules/yang --yangpath ../../cisco-
iosxr/src/ncsc-out/modules/yang -c -o ../load-dir/l2vpn.fxs
yang/l2vpn.yang

pylint --disable=R,C --reports=n ../python/l2vpn.py || (test


$? -ge 4)
No config file found, using default configuration
************* Module l2vpn
W: 16,49: Access to a protected member _path of a client
class (protected-access)

cisco@NCS:~/ncs-run/packages/l2vpn/src$

Step 8 Verify that you have a directory structure and Python files for the
L2VPN service.
cisco@nso:$~/ncs-run/# cd packages/l2vpn/
cisco@nso:$~/ncs-run/packages/l2vpn# dir
load-dir package-meta-data.xml python src
cisco@nso:$~/ncs-run/packages/l2vpn# cd src/
root@ubuntu:/home/ncs/packages/l2vpn/src# dir
Makefile yang

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–6


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Step 9 Verify that your YANG model structure mirrors the one below.

Activity Verification
You have completed this task when you attain these results:
 You have successfully created a Python-based service skeleton for an
L2VPN service.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–7


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Task 3: Implement Python-Based Mapping Logic


The purpose of this task is to implement the mapping logic for the L2VPN service. You
will use XML configuration templates to store the device configuration, and apply the
templates using Python. You will use the Maagic and Template Python APIs to
accomplish this task.

Activity Procedure
Complete these steps:
Step 1 To help with service development, you will find PyCharm IDE on the
workstation desktop. You can access files on the NCS server from
within the IDE, which can help you with writing your code and can be
used for syntax highlighting and debugging. Open the PyCharm IDE or
your favorite Python editor. The current Cisco NSO project (in ~/ncs-
run) is already imported into PyCharm.

Step 2 Open and edit the l2vpn.py file located in the


packages/l2vpn/python folder.

Step 3 In the code, find the cb_create() method where you must put your
mapping code. Your coding entry point is marked below.
# -*- mode: python; python-indent: 4 -*-
import ncs
from ncs.application import Service
# import ncs.template

# ------------------------
# SERVICE CALLBACK EXAMPLE
# ------------------------
class ServiceCallbacks(Service):

# The create() callback is invoked inside NCS FASTMAP


and
# must always exist.
@Service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=',
service._path, ')')

# DO STUFF HERE.....

# Example:
# vars = ncs.template.Variables()
# vars.add('MAGIC', "42")
# template = ncs.template.Template(service)
# template.apply('foo-template1', vars)

# ---------------------------------------------
# COMPONENT THREAD THAT WILL BE STARTED BY NCS.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–8


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

# ---------------------------------------------
# omitted

Step 4 The following table describes the service characteristics and


requirements. Use this information, along with the L2VPN YANG
model, as a starting point to determine which parameters must be set
on devices.

Parameter Description

VPN Instance This is a unique identifier describing an instance of a


Name deployed point-to-point Layer 2 MPLS VPN.
It is used to provide a descriptive name for the service
instance.
Pseudowire This is a unique number that is used to identify the
Identifier pseudowire connection across MPLS between two PE
routers.
Attachment A point-to-point Layer 2 MPLS VPN consists of two
Circuit 1 ends. We may call them attachment circuits or links,
or some other name can be assigned to them.
Attachment
Circuit 2
Device Each attachment circuit is connected to a device (PE
router).
Currently, there are two device types used for PE
routers:
- Cisco IOS routers
- Cisco IOS XR routers
Interface Each attachment circuit contains an interface or a
subinterface.
Currently, only Gigabit Ethernet interfaces are used
for the service.
Loopback Each attachment circuit uses a loopback interface to
Interface connect to the other end.
The interface ID represents the local loopback to use
when configuring the neighboring device.

_________________________________________________________________

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–9


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Step 5 Use the Cisco NSO CLI to obtain the configuration in the XML format,
to be used in the config template. Use the following configuration for
L2VPN on Cisco IOS and IOS XR devices.
! Cisco IOS
interface GigabitEthernet0/9
description Link to CE11
xconnect 10.0.0.21 1001121 encapsulation mpls

! Cisco IOS XR
l2vpn
xconnect group ACME
p2p CE11-to-CE21
interface GigabitEthernet0/0/0/9 neighbor 10.0.0.11 pw-id
1001121
!
interface GigabitEthernet0/0/0/9
description Link to CE21
l2transport

Step 6 Use the commit dry-run outformat xml CLI command to obtain
the configuration in XML format, and place the XML for both device
types into a single l2vpn-template.xml file, in the templates
directory (the directory must be created manually) of your l2vpn
service package.
Step 7 Parameterize the XML template. Identify the four dummy values used
in the sample configuration, and replace them with XPath variables.

Variable Description

$DEVICE Device name

$INTERFACE-ID Interface ID (0/0/0/1)

$PW-ID Pseudowire ID

$REMOTE-IP Remote loopback IP

$CUSTOMER Customer name

$SERVICE Service instance name

<config-template xmlns="http://tail-f.com/ns/config/1.0">
<devices xmlns="http://tail-f.com/ns/ncs">
<device tags="nocreate">
<name>{$DEVICE}</name>
<config>
<interface xmlns="urn:ios">

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–10


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

<GigabitEthernet>
<name>{$INTERFACE-ID}</name>
<xconnect tags="merge">
<encapsulation>mpls</encapsulation>
<vcid>{$PW-ID}</vcid>
<address>{$REMOTE-IP}</address>
</xconnect>
</GigabitEthernet>
</interface>
<l2vpn xmlns="http://tail-f.com/ned/cisco-ios-xr"
tags="merge">
<xconnect>
<group>
<name>{$CUSTOMER}</name>
<p2p>
<name>{$SERVICE}</name>
<neighbor>
<address>{$REMOTE-IP}</address>
<pw-id>{$PW-ID}</pw-id>
</neighbor>
<interface>
<name>GigabitEthernet{$INTERFACE-ID}</name>
</interface>
</p2p>
</group>
</xconnect>
</l2vpn>
<interface xmlns="http://tail-f.com/ned/cisco-ios-xr">
<GigabitEthernet>
<id>{$INTERFACE-ID}</id>
<l2transport tags="merge">
</l2transport>
</GigabitEthernet>
</interface>
</config>
</device>
</devices>
</config-template>

____________________________ Note ________________________________


The service configuration template in this example contains device
configurations for both device types in a single file. You could also split the
configuration into multiple-feature XML templates and apply them as needed.
________________________________________________________________________
Step 8 Use the Maagic API to reference leaf nodes in the service model. Use
the code snippet below to access the VPN instance name, customer, and
pseudowire identifier (snippet SERVICE-PARAMETERS).
@Service.create
def cb_create(self, tctx, root, service, proplist):

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–11


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

self.log.info('Service create(service=', service._path,


')')

vpn_name = service.name
customer = service.customer
pw_id = service.pw_id

______________________ Note ________________________________


Snippets (referenced with CAPITAL-LETTERS) are also contained in
the /opt/resources/ lab2/lab2-task3-snippets-python.txt
file.
_________________________________________________________________
_______________________ Note _______________________________
Indentation is very important in Python, because it is used to structure
code blocks. All code in this task will be a part of the cb_create
method.
_________________________________________________________________
Step 9 For each attachment circuit configuration on the device, we must
configure the remote IP address of the neighbor device. We will use the
loopback-interface leaf to read the IP address of the desired
loopback interface directly from device configuration, because it is
already stored in the CDB. The code for reading the device
configuration based on device type is already provided in a separate
device_helper.py module. Copy the module from the solutions
directory and study the contents.
cisco@nso-stack:~/ncs-run$ cp /opt/resources/lab2/lab2-
task3-end-python/device_helper.py packages/l2vpn/python/

Step 10 Import the helper module into the l2vpn.py module by adding an
import statement at the beginning of the file. Uncomment the
ncs.template import.
# -*- mode: python; python-indent: 4 -*-
import ncs
from ncs.application import Service
import ncs.template
import device_helper

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–12


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Step 11 Loop through all entries in the link list. For each entry, determine the
type of the device, and read the IP address of the loopback interface
directly from device configuration, using the device-specific device
model. Store this data in an auxiliary list named links_data, to be
used later in providing the service instance configuration. An example
of the final data structure is displayed below. The list contains
dictionaries with the fields device, intf-number, loopback-
address.
In [5]: pprint.pprint(links_data)
[{'device': 'PE11', 'intf-number': '0/1', 'loopback-
address': '10.0.0.1'},
{'device': 'PE21', 'intf-number': '0/0/0/1', 'loopback-
address': '10.0.0.2'}]

Step 12 Prepare an empty list, and add an entry for each attachment circuit
containing the device name (snippet PREPARE-LINKS-DATA).
vpn_name = service.name
customer = service.customer
pw_id = service.pw_id

links_data = []
for link in service.link:
link_data = {'device': link.device}

links_data.append(link_data)

Step 13 Add data to the dictionary. Use helper methods from the
device_helper module to determine the device type, and read the
value of the IP address from the device configuration (snippet READ-
LINK-INTERFACE-DATA). Read the value of the customer-facing
intf-number interface from the device-specific container (ios or ios-xr)
and store it in the intf-number entry.
links_data = []
for link in service.link:
link_data = {'device': link.device}
device_type =
device_helper.get_device_type(root, link.device)
self.log.info('Normalizing data for device {} of
type {}'
.format(link.device, device_type))
device_type_container = getattr(link,
device_helper.DEVICE_LOOKUP[device_type])

link_data['intf-number'] =
device_type_container.intf_number
link_data['loopback-address'] = \
device_helper.get_loopback_address(root,

link.device,

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–13


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

device_type,

device_type_container.loopback_interface)

links_data.append(link_data)

Step 14 With the data prepared, you can now configure the devices. In the
cb_create method, loop through the auxiliary list links_data and
apply the configuration template that you prepared at the beginning of
the task. Recall the variables names that you used, and provide the
values with a new variables object (snippet APPLY-TEMPLATE).

links_data.append(link_data)

for index, link in enumerate(links_data):


self.log.info('Configuring device
{}'.format(link['device']))
tvars = ncs.template.Variables()
tvars.add('SERVICE', vpn_name)
tvars.add('CUSTOMER', customer)
tvars.add('PW-ID', pw_id)
tvars.add('DEVICE', link['device'])
tvars.add('INTERFACE-ID', link['intf-number'])
tvars.add('REMOTE-IP', links_data[1-
index]['loopback-address'])

template = ncs.template.Template(service)
template.apply('l2vpn-template', tvars)

______________________ Note ________________________________


When providing the value for the REMOTE-IP variable, we need to use
the loopback IP address of the neighboring device. Note the index
inversion when reading the loopback-address field.
_________________________________________________________________
Step 15 After you finish writing your Python code, compile the whole package.
You can do this by navigating to $HOME/ncs-
run/packages/l2vpn/src/ and running the make command from
there.
cisco@ncs:~/ncs-run/packages/l2vpn/src# make
pylint --disable=R,C --reports=n ../python/l2vpn.py || (test
$? -ge 4)
No config file found, using default configuration
************* Module l2vpn
W: 17,49: Access to a protected member _path of a client
class (protected-access)
pylint --disable=R,C --reports=n ../python/device_helper.py
|| (test $? -ge 4)

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–14


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

No config file found, using default configuration#

___________________ Note ________________________________


You may see various warnings when compiling the YANG module
or checking the Python modules with pylint. If there are no errors
in the output, you can still proceed with the task.
______________________________________________________________
Step 16 After the package is compiled successfully, reload the packages in Cisco
NSO by using the reload packages command.
admin@ncs# packages reload

>>> System upgrade is starting.


>>> Sessions in configure mode must exit to operational
mode.
>>> No configuration changes can be performed until upgrade
has completed.

Step 17 Make sure that your netsim devices are still running (see the previous
Lab – Task 1).
Step 18 Make sure that Cisco NSO is running and that the devices are synced
with Cisco NSO. If they are not synced, sync them with Cisco NSO.
admin@ncs# devices sync-from
sync-result {
device CE11
result true
}
sync-result {
device CE12
result true
}
sync-result {
device CE21
result true
}
sync-result {
device CE31
result true
}
sync-result {
device PE11
result true
}
sync-result {
device PE12
result true
}
sync-result {
device PE21
result true
© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–15
This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

}
sync-result {
device PE31
result true
}

Step 19 Deploy an instance of an L2VPN service between PE1 and PE2.


admin@ncs(config)# services l2vpn PE11-PE21
Value for 'customer' [ACME]: ACME
admin@ncs(config-l2vpn-PE11-PE21)# pw-id 123
admin@ncs(config-l2vpn-PE11-PE21)# link PE11 intf-number 0/5
admin@ncs(config-link-PE11)# exit
admin@ncs(config-l2vpn-PE11-PE21)# link PE21 intf-number
0/0/0/6
admin@ncs(config-link-PE12)# exit
admin@ncs(config)# commit dry-run outformat native
native {
device {
name PE11
data interface GigabitEthernet0/5
xconnect 10.0.0.21 123 encapsulation mpls
exit
}
device {
name PE21
data interface GigabitEthernet 0/0/0/6
l2transport
exit
exit
l2vpn
xconnect group ACME
p2p PE11-PE21
interface GigabitEthernet0/0/0/6
neighbor 10.0.0.11 pw-id 123
exit
exit
exit
exit
}
}
admin@ncs(config-link-PE21)# commit

Step 20 Now delete this service instance from Cisco NSO.


admin@ncs(config)# no services l2vpn PE11-PE21
admin@ncs(config)# commit dry-run
cli devices {
device PE11 {
config {
ios:interface {
GigabitEthernet 0/5 {
xconnect {
- address 10.0.0.21;
- vcid 123;

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–16


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

- encapsulation mpls;
}
}
}
}
}
device PE21 {
config {
cisco-ios-xr:interface {
GigabitEthernet 0/0/0/6 {
- l2transport {
- }
}
}
cisco-ios-xr:l2vpn {
xconnect {
- group ACME {
- p2p PE11-PE21 {
- interface
GigabitEthernet0/0/0/6;
- neighbor 10.0.0.11 123;
- }
- }
}
}
}
}
}
services {
- l2vpn PE11-PE21 {
- customer ACME;
- pw-id 123;
- link PE11 {
- ios {
- intf-number 0/5;
- }
- }
- link PE21 {
- iosxr {
- intf-number 0/0/0/6;
- }
- }
- }
admin@ncs(config)# commit

____________________________ Note ________________________________


If you encounter problems and do not know how to approach debugging, you
can start at the NCS Python VM log for the l2vpn component. Go to the
~/ncs-run/logs folder and check the contents of the ncs-python-vm-
l2vpn.log file. Check for errors and hints for what went wrong in your
Python code. If there is a syntax error in your modules, the error may also be
visible in the ncs-python-vm.log general log.
________________________________________________________________________

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–17


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

____________________________ Note ________________________________


If you encounter errors when applying the template, due to missing variables,
you can get the debug output from XPath expression resolution in the NSO
CLI, using the | debug template output – for example, with the commit
dry-run | debug template command.
________________________________________________________________________

Activity Verification
You have completed this task when you attain these results:
 You have a directory structure and Python files for the L2VPN service.
 You have successfully compiled the L2VPN service package.
 You have successfully created and deleted an L2VPN service instance in
your lab network.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–18


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Task 4: Change the YANG Model to Support Reactive FASTMAP


The purpose of this task is to alter the existing YANG model to support pseudowire ID
allocation for the PW ID attribute using reactive FASTMAP. You will use Java to
implement a service application that allocates and deallocates pseudowire ID for the
L2VPN service PW ID parameter.

Visual Objective

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–19


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Activity Procedure
Complete these steps:
Step 1 Examine the current model for the l2vpn service. Note that the pw-id
leaf is a mandatory numeric input parameter.

Step 2 Flag the leaf pw-id as read-only using the config statement.

Step 3 Mark this leaf to be stored in the CDB. Make sure that the data stored
in CDB will be persistent. Use the tailf:cdb-oper and
tailf:persistent YANG extension statements.
leaf pw-id {
tailf:info "Pseudowire ID";
type uint32 {
range "1..4294967295";
}
config false;
tailf:cdb-oper {
tailf:persistent true;
}
}

Activity Verification
You have completed this task when you attain these results:
 You have successfully updated the pw-id leaf using the config statement.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–20


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Task 5: Implement Pseudowire ID Provisioning with Reactive


FASTMAP
The purpose of this task is to automate the provisioning of pseudowire ID for the point-
to-point L2VPN links. The IDs will be allocated and deallocated sequentially by an
external application.
First, you will change the service mapping code to request PW ID allocation, rather than
read it from the service model. The service mapping code will then exit.
Second, you will develop an application component that will subscribe to the changes in
the CDB affecting the l2vpn service, allocate a PW ID, and request a service redeploy
with the new PW ID parameter.

Activity Procedure
Complete these steps:
__________________________________ Note ________________________________
Refer to the snippets in the /opt/resources/lab2/lab1-task5-snippets-
python.txt file.
______________________________________________________________________________
Step 1 Change the service mapping code in l2vpn.py to request PW ID
allocation, and read the response. The response is stored in an
operational leaf pw-id, residing in the service model. In general, this
data would be stored outside the service model. In that scenario, the
data would be affected by FASTMAP (removed before the mapping logic
runs). Therefore, it is necessary to open a separate transaction toward
the operational data store to read the data unaffected by FASTMAP.
Use the high-level MAAPI API in Python to accomplish this. If the pw-
id is not available, your code must exit (snippet READ-PWID).

vpn_name = service.name
customer = service.customer

pw_id = None
with ncs.maapi.single_read_trans(tctx.username,
tctx.context, db=ncs.OPERATIONAL) as t:
try:
oper_service = ncs.maagic.get_node(t,
service._path)
pw_id = oper_service.pw_id
except KeyError:
# service instance does not yet exist
pass

if pw_id is None:
self.log.info('pw-id does not exit, waiting for
redeploy')

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–21


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

return proplist

Step 2 In the /opt/resources/lab2/lab2-task5-start-python folder,


you will find a file called l2vpn_subscriber.py. This is the skeleton
source code for your CDB Subscriber application. Copy this file to the
Python source folder for your l2vpn package.

Step 3 In the /opt/resources/lab2/lab2-task5-end-python folder, you


will find a file called fake_external_allocator.py. This is the fake
source code for the fake external allocator. Copy this file to the Python
source folder for your l2vpn package.

Step 4 Open the subscriber application Python module in your favorite text
editor, and first, take a few moments to go through the existing code.
Alternatively, you can also edit the file, using the PyCharm editor. The
skeleton subscriber does not directly use the CDB Subscription API
(which is very low-level), but instead uses a high-level Python wrapper,
located in the ncs.experimental.Subscriber class. You will extend this
class, and provide implementations for the following methods:
 init() –Initializer for the subscriber.

 pre_iterate() –Initializer for any state objects used during


iteration through changes. Return a new clean state object here.
 iterate(keypath, operation, oldval, newval, state) –
Iterate through all changes and evaluate keypath and node
operation. Pass state through the state object. A return flag controls
the iteration progress.
 should_post_iterate(state) –Executed by the wrapper
immediately after iterate to determine if there are any tasks that
require processing in post_iterate.
 post_iterate(state) –Executed by the wrapper asynchronously
(in s background worker thread) after iteration and subscription
sync. Perform your work here.
 cleanup() – Clean up any allocated resources here.

# -*- mode: python; python-indent: 4 -*-

import ncs
import ncs.maapi
import ncs.experimental

import _ncs
import fake_external_allocator

# ------------------------------------------------
# SUBSCRIBER ITERATOR OBJECT
# ------------------------------------------------

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–22


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

class AllocatorSubscriber(ncs.experimental.Subscriber):
"""This subscriber subscribes to changes in the..."""

# custom initializer which gets called from the


# constructor (__init__)
def init(self):
pass

# Initate your local state


def pre_iterate(self):
self.log.info('AllocatorSubscriber: pre_iterate')
return []

# Iterate over the change set


def iterate(self, keypath, operation, oldval, newval,
state):
self.log.debug('iterate: {} {} old:{}
new:{}'.format(operation, keypath, oldval, newval))

return ncs.ITER_RECURSE

# This will run in a separate thread to avoid a


transaction deadlock
def post_iterate(self, state):
self.log.info('AllocatorSubscriber: post_iterate,
state=', state)

# determine if post_iterate() should run


def should_post_iterate(self, state):
return state != []

def cleanup(self):
pass

Step 5 Implement the init() method. This method is called by the super
class (ncs.experimental.Subscriber) constructor and is
responsible for setting up the subscription. Use the register()
method defined in the Subscriber wrapper to subscribe to the list of
service instances for the l2vpn service (snippet CDB-SUBSCRIBE).
Replace the pass statement.

# ------------------------------------------------
# SUBSCRIBER ITERATOR OBJECT
# ------------------------------------------------
class AllocatorSubscriber(ncs.experimental.Subscriber):
"""This subscriber subscribes to changes in the..."""

# custom initializer which gets called from the


# constructor (__int__)
def init(self):
self.service_path = '/ncs:services/l2vpn:l2vpn'
self.register(self.service_path, priority=100)
Step 6 Now we need to filter out the event that we are interested in. We need
to iterate over all CDB requests and filter out CREATE and DELETE
© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–23
This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

operations, because we are interested only in service instance creation


and deletion.
The Subscriber wrapper requires you to implement a method –
iterate(), which will get called once for each node, based on the
DiffIterateFlags set.
In the iterate() method itself, you should not be doing any time-
intensive work. Instead, prepare a state object containing all necessary
information for background processing (snippet ITER-MAKE-
REQUESTS).
def iterate(self, keypath, operation, oldval, newval,
state):
self.log.debug('iterate: {} {} old:{}
new:{}'.format(operation, keypath, oldval, newval))

if operation == ncs.MOP_CREATED and str(keypath[1:]) ==


self.service_path:
state.append({'operation': 'create', 'path':
str(keypath)})
return ncs.ITER_STOP
elif operation == ncs.MOP_DELETED and str(keypath[1:])
== self.service_path:
path = str(keypath) + '/l2vpn:pw-id'
try:
with ncs.maapi.single_read_trans('admin',
'system', db=ncs.OPERATIONAL) as t:
val = t.get_elem(path)
state.append({'operation': 'delete', 'path':
str(keypath), 'value': val})
except Exception as e:
self.log.error('Error in iterate: ', e)
return ncs.ITER_STOP

return ncs.ITER_RECURSE

____________________________ Note ________________________________


Study the structure of the iterate() method. It is responsible for evaluating
the subscription notification – examining the node keypath and operation, and
storing the requested operations in the state object. If a new list entry in the
l2vpn list is created, the state object will contain a create operation with no
value. However, if an entry is removed (removing the service instance), the
state object will contain a delete operation with the allocated value.
________________________________________________________________________

Step 7 After iterating through the changes, the Subscriber wrapper will
execute the post_iterate() method in a background worker thread.
The method has access to the same state object populated by the

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–24


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

iterate() method. In the case of a create request, the method must


retrieve a new ID from the external allocator, write the results back to
the CDB as operational data, and redeploy the service instance. In the
case of a delete request, the method must free the allocated ID. We use
the MAAPI high-level Python API to interface with the CDB (snippet
RUN-REQUESTS).
# This will run in a separate thread to avoid a transaction
deadlock
def post_iterate(self, state):
self.log.info('AllocatorSubscriber: post_iterate,
state=', state)

for request in state:


if request['operation'] == 'create':
allocated_id =
fake_external_allocator.allocate_id()
self.log.info('Allocated pwid ', allocated_id)
path = request['path'] + '/pw-id'

with ncs.maapi.single_write_trans('admin',
'system', db=ncs.OPERATIONAL) as t:
t.set_elem(_ncs.Value(allocated_id,
_ncs.C_UINT32), path)
t.apply()

path = request['path'] + '/reactive-re-


deploy'
self.log.info('Redeploying ', path)
redeploy = ncs.maagic.get_node(t, path)
redeploy()
elif request['operation'] == 'delete':

fake_external_allocator.deallocate_id(request['value'])
self.log.info('Deallocated pwid ',
request['value'])

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–25


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Step 8 Import l2vpn_subscriber in l2vpn.py.

# -*- mode: python; python-indent: 4 -*-


import ncs
from ncs.application import Service
import ncs.template
import device_helper
import l2vpn_subscriber

Step 9 Register AllocatorSubscriber as change listener in l2vpn.py.


...
class L2vpn(ncs.application.Application):
def __init__(self, *args, **kwargs):
self.sub = None
super(L2vpn, self).__init__(*args, **kwargs)

def setup(self):
self.log.info('L2vpn RUNNING')
self.register_service('l2vpn-servicepoint',
ServiceCallbacks)
self.sub =
l2vpn_subscriber.AllocatorSubscriber(app=self)
self.sub.start()

def teardown(self):
...

Step 10 Now we are ready to compile our package. Navigate to the package
source folder (packages/l2vpn/src) and compile it by running the
make command.
root@ubuntu:/home/marko/ncs-rfs-run/packages/l2vpn/src# make
pylint --disable=R,C --reports=n
../python/fake_external_allocator.py || (test $? -ge 4)
No config file found, using default configuration
pylint --disable=R,C --reports=n ../python/l2vpn.py || (test
$? -ge 4)
No config file found, using default configuration
************* Module l2vpn
W: 18,49: Access to a protected member _path of a client
class (protected-access)
W: 25,54: Access to a protected member _path of a client
class (protected-access)
pylint --disable=R,C --reports=n
../python/l2vpn_subscriber.py || (test $? -ge 4)
No config file found, using default configuration
************* Module l2vpn_subscriber
W: 41,19: Catching too general exception Exception (broad-
except)
pylint --disable=R,C --reports=n ../python/device_helper.py
|| (test $? -ge 4)
No config file found, using default configuration

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–26


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Step 11 After the package is compiled successfully, reload the packages in NSO,
using the reload packages command.
admin@ncs# packages reload

>>> System upgrade is starting.


>>> Sessions in configure mode must exit to operational
mode.
>>> No configuration changes can be performed until upgrade
has finished.

Step 12 Repeat the verification procedure from the previous task. Notice how
you no longer need to provide the pw-id parameter, because it is
assigned automatically.

Activity Verification
You have completed this task when you attain these results:
 You have a directory structure and Java files for L2VPN service.
 You are able to successfully compile the L2VPN service package.
 You are able to successfully create and delete an L2VPN service instance
in your lab network.
 When you repeated the verification procedure, the pw-id parameter was
assigned automatically.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–27


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Task 6: Using the ID Allocator Package (Optional)


The purpose of this task is to change the mapping logic for the l2vpn service to reuse an
existing Resource Allocator package for ID allocation, named id-allocator. This action
will eliminate the need for a service-specific ID allocator and subscriber implementation.

Activity Procedure
Complete these steps:
Step 1 Copy the packages id-allocator and resource-manager from the
next lab solution folder (located in /home/cisco/advanced-lab3)
into your lab project folder. The packages are located in the
/opt/resources/lab3/packages/ folder.
cisco@nso:~/ncs-run$ cp -pr ~/advanced-
lab3/packages/resource-manager packages/
cisco@nso:~/ncs-run$ cp -pr ~/advanced-lab3/packages/id-
allocator packages/

Step 2 In the /opt/resources/lab2/lab2-task6-end-python folder, you


will find a file called id_allocator.py. This is a helper Python
module for working with the ID allocator package. Copy this file to
your l2vpn package Python source folder.
___________________ Note ________________________________
If you are using the new version 1.3.1 of the Resource Allocator
packages, the Python API is now bundled with the package.
______________________________________________________________
Step 3 Edit the l2vpn.py file, and remove the code added in Task 5—creating
the request-pwid container and reading the results of the allocation.
Replace it with a code using ID allocator. The code will create an ID
request; check whether it is available, and proceed. If the resource is
not yet available, the cb_create() method must return, and wait for
a redeploy (snippet PWID-RESOURCE-ALLOCATOR).
vpn_name = service.name
customer = service.customer

pw_id = None
service_path =
"/services/l2vpn[name='{}']".format(service.name)
self.log.info('Path: ', service_path)
id_allocator.id_request(service, service_path, 'pw-
id', tctx.username, vpn_name)
try:
pw_id = id_allocator.id_read(tctx, root, 'pw-
id', vpn_name)
except id_allocator.ResourceWait:

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–28


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

pass

if pw_id is None:
self.log.info('pw-id does not exit, waiting for
redeploy')
return proplist

Step 4 Import the id_allocator statement at the top of the


ServiceCallbacks class (replace l2vpn_subscriber).
import ncs.template
import device_helper
import id_allocator

Step 5 Remove the pw-id leaf and the unique pw-id statement from the
l2vpn.yang service model.

Step 6 Delete l2vpn_subscriber.py and fake_allocator.py from your


l2vpn package Python source folder.
Step 7 Unregister AllocatorSubscriber in l2vpn.py (remove
unnecessary lines).
...
class L2vpn(ncs.application.Application):
def __init__(self, *args, **kwargs):
self.sub = None
super(L2vpn, self).__init__(*args, **kwargs)

def setup(self):
self.log.info('L2vpn RUNNING')
self.register_service('l2vpn-servicepoint',
ServiceCallbacks)
self.sub =
l2vpn_subscriber.AllocatorSubscriber(app=self)
self.sub.start()

def teardown(self):
...

Step 8 Delete any existing test l2vpn services that you have created. Compile
the service, and reload the packages in Cisco NSO.
______________________ Note ________________________________
The change that we just made—migration to Resource Allocator—is a
significant upgrade of the service model and the mapping logic. In a
production environment, you would want to preserve existing service
instances during the upgrade. This action would require writing a
migration program that would populate the Resource Allocator
database with the already allocated PW IDs, and associate them with
the services.
_________________________________________________________________

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–29


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Step 9 Before the Resource Allocator can be used, the ID pool must be
configured in the CDB. Use Cisco NSO CLI to create an ID pool named
pw-id, and assign it the range 100 to 200.
admin@ncs(config)# resource-pools id-pool pw-id range start
100 end 200
admin@ncs(config-id-pool-pw-id)# commit
Commit complete.

Step 10 Create a test l2vpn service instance, as in previous steps. Note that
the pw-id leaf is no longer available as a service input parameter.

Step 11 Verify the service configuration, using the show services l2vpn
<instance> command. Note that the allocation request appears as
configuration data (device modification). You can examine the current
allocations in the pool with the show resource-pools id-pool pw-
id command from the operational mode.
admin@ncs(config)# show configuration
services l2vpn PE11-PE21
customer ACME
link PE11
ios intf-number 0/6
!
link PE21
iosxr intf-number 0/0/0/3
!
!
admin@ncs(config)# commit
admin@ncs(config)# exit
admin@ncs# show services l2vpn PE11-PE21
services l2vpn PE11-PE21
device-modifications devices {
device PE11 {
config {
ios:interface {
GigabitEthernet 0/6 {
xconnect {
+ address
10.1.1.3;
+ vcid 100;
+ encapsulation
mpls;
}
}
}
}
}
device PE21 {
config {
cisco-ios-xr:interface {
GigabitEthernet
0/0/0/3 {
+ l2transport {

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–30


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

+ }
}
}
cisco-ios-xr:l2vpn {
xconnect {
+ group ACME {
+ p2p PE11-PE21
{
+ interface
GigabitEthernet0/0/0/3;
+ neighbor
10.1.1.1 100;
+ }
+ }
}
}
}
}
}
resource-pools {
id-pool pw-id {
+ allocation PE11-PE21 {
+ allocating-service
/services/l2vpn:l2vpn[name='PE11-PE21'];
+ }
}
}

modified devices [ PE11 PE21 ]


directly-modified devices [ PE11 PE21 ]
device-list [ PE11 PE21 ]
link PE11
ios loopback-address 10.1.1.1
link PE21
iosxr loopback-address 10.1.1.3

Activity Verification
You have completed this task when you attain these results:
 You have successfully loaded the new packages.
 You have successfully created a new test l2vpn service instance.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–31


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Task 7: Add Support for Juniper Devices (Optional)


The purpose of this task is to extend your point-to-point L2VPN service with Juniper
router support.

Activity Procedure
Complete these steps:
Step 1 Copy the juniper-junos NED to your packages directory in
$HOME/ncs-run/packages from
$NCS_DIR/packages/neds/juniper-junos.
cisco@nso-stack:~/ncs-run/packages$ cp -pr ~/nso-
4.2/packages/neds/juniper-junos .

Step 2 Add a new Juniper device to Cisco NSO.


devices device PE41
address 127.0.0.1
port 12205
authgroup default
device-type netconf
state admin-state unlocked

Step 3 Perform a sync-from on the new PE41 device.

Step 4 Use the simulated device PE41 to prepare the XML template from the
Cisco NSO CLI. The device configuration for L2VPN on Junos devices
is as follows:
admin@ncs(config)# show configuration
devices device PE41
config
junos:configuration interfaces interface ge-0/1/1
encapsulation ethernet-ccc
!
! first
junos:configuration protocols l2circuit neighbor 10.0.0.1
! first
interface ge-0/1/1
virtual-circuit-id 1234
!
!
!
!

Step 5 Add the XML configuration to the existing l2vpn-template.xml


service configuration template (snippet CONFIG-JUNOS).
<configuration xmlns="http://xml.juniper.net/xnm/1.1/xnm">
<interfaces>
<interface tags="merge">
<name>{$INTERFACE-ID}</name>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–32


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

<encapsulation>ethernet-ccc</encapsulation>
</interface>
</interfaces>
<protocols tags="merge">
<l2circuit>
<neighbor>
<name>{$REMOTE-IP}</name>
<interface>
<name>{$INTERFACE-ID}</name>
<virtual-circuit-id>{$PW-ID}</virtual-circuit-id>
</interface>
</neighbor>
</l2circuit>
</protocols>
</configuration>

______________________ Note ________________________________


You could store device configurations for specific devices in separate
templates, but this approach simplifies applying the template in code.
_________________________________________________________________
Step 6 Add another container in your YANG model, which will hold the
JUNOS Gigabit Ethernet Interface (snippet CONTAINER-JUNOS).
container junos {
when
"deref(../device)/../ncs:module[1]/ncs:name='junos'" {
tailf:dependency "../device";
}

tailf:cli-drop-node-name;
leaf intf-number {
tailf:info "GigabitEthernet Interface ID";
mandatory true;
type leafref {
path
"deref(../../device)/../ncs:config/junos:configuration/junos
:interfaces/junos:interface/junos:name";
}
}

leaf loopback-interface {
tailf:info "Loopback Interface ID";
type string;
default "0";
}
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–33


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

Step 7 Add an import statement to the l2vpn service model at the top,
because it now references the junos NED.
module l2vpn {
...
import tailf-ned-cisco-ios-xr { prefix cisco-ios-xr; }
import junos { prefix junos; }

Step 8 Add the junos NED to the yangpath in the l2vpn service package
Makefile.
YANGPATH += ../../juniper-junos/src/ncsc-out/modules/yang

Step 9 In the device_helper class, modify the DEVICE_LOOKUP table to


support the new Juniper Junos device type (snippet
DEVICEHELPER-DEVICE-TYPE-JUNOS).
TYPE_CISCO_IOS = '{tailf-ned-cisco-ios}'
TYPE_CISCO_IOSXR = '{tailf-ned-cisco-ios-xr}'
TYPE_JUNIPER_JUNOS = '{junos}'

DEVICE_LOOKUP = {
TYPE_CISCO_IOS: 'ios',
TYPE_CISCO_IOSXR: 'iosxr'
TYPE_JUNIPER_JUNOS: 'junos'

Step 10 In the device_helper class, modify the get_loopback_address


method to return the loopback address on Junos devices (snippet
DEVICEHELPER-LOOPBACK-JUNOS).
if device_type == TYPE_CISCO_IOS:
loopback =
device_config.ios__interface.ios__Loopback[loopback_interfac
e]
address = loopback.ip.address.primary.address
elif device_type == TYPE_CISCO_IOSXR:
loopback =
device_config.cisco_ios_xr__interface.Loopback[loopback_inte
rface]
address = loopback.ipv4.address.ip
elif device_type == TYPE_JUNIPER_JUNOS:
loopback =
device_config.junos__configuration.interfaces.interface['lo'
+loopback_interface]
fullAddress =
loopback.unit['0'].family.inet.address.keys()[0]
address = str(fullAddress).strip('{}').split('/')[0]
else:
raise Exception('Unknown device type ' +
device_type)

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–34


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Layer 2 VPN Service Enhancements

___________________ Note ________________________________


Instead of using Maagic properties to navigate the config tree, you
can try writing an XPath query.
______________________________________________________________
Step 11 Compile and reload the package.
Step 12 Test the service by configuring an L2VPN between PE11 and the
JUNOS device.
admin@ncs# show running-config services l2vpn test-junos
services l2vpn test-junos
customer ACME
link PE11
intf-number 0/14
!
link PE41
intf-number xe-0/0/14
!
!

_____________________________ Note _______________________________


After completing this exercise, it is recommended that you remove the
juniper-junos NED for performance reasons (the package reload will take
longer).
________________________________________________________________________

Activity Verification
You have completed this task when you attain these results:
 You have successfully added a new simulated device, PE41.
 You have successfully enhanced your Python mapping code to support
Juniper devices.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 2–35


This document is for training purposes only. All content is subject to change without notice.
Lab 3: Creating a Simple Cloud Service
Bundle

Description
Complete this lab exercise to practice what you learned in the “Cloud VPN Service
Design” module of this course.

Activity Objective
In this activity, you will learn how to create a cloud bundle by implementing service
stacking. After completing this activity, you will be able to meet these objectives:
 Use service stacking to instantiate services
 Use Cisco Elastic Services Controller (Cisco ESC) to provision a virtual
network function (VNF) on OpenStack

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–1


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Visual Objective
The graphic below illustrates the network topology used in the activity:

customer-server

Lab Network
198.18.134.4/26 198.18.134.12/26 198.18.134.11/26
Neutron 20.0.0.20/24
customer-network (Neutron)
Cisco mgmt-router
NSO
10.1.0.1/24

mgmt-network (Neutron)
10.1.0.10/24

internet-network (Neutron)
30.0.0.30/24

ESC

internet-server
1 / HTDDEV100_2-1 © 2017 Cisco and/or its affiliates. All rights reserved.

The graphic below illustrates the objective of the activity.

customer-server

Lab Network
198.18.134.4/26 198.18.134.12/26 198.18.134.11/26
Neutron 20.0.0.20/24
customer-network (Neutron)
Cisco mgmt-router
NSO 20.0.0.25/24
IOS
10.1.0.1/24
10.1.0.16/24
mgmt-network (Neutron)
Activate
Cloud 10.1.0.10/24 CRS VNF
30.0.0.35/24
internet-network (Neutron)
30.0.0.30/24

ESC Activate VNF,


vRouter, vFirewall
internet-server
2 / HTDDEV100_2-1 © 2017 Cisco and/or its affiliates. All rights reserved.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–2


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Task Data
The following data will be required for this lab.
MGMT IP
Device Type Addresses SSH Port

CLOUD-TEST Cisco IOS XE 127.0.0.1 12052


esc0 Cisco ESC 198.18.134.12 830

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–3


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Task 1: Create a vRouter Service


The purpose of this task is to implement the virtual router service.
A basic cloud bundle consists of a virtual router and virtual firewall service instance. A
virtual router is used to provide client connectivity between the customer and Internet
networks. A virtual firewall is used to block or allow certain types of traffic between the
two networks.
Before we can create a cloud service, we still must implement the virtual router service.
After it is created and tested, we can create a high-level service called cloud, which will
instantiate both the vFirewall and vRouter services.

The preceding shows the graphical representation of the model used for the vRouter
service.

Activity Procedure
Complete these steps:
Step 1 Use the ncs-make-package tool to create a new service skeleton
called vrouter. Use the template-based service skeleton to create both
an XML template for the device configuration and an empty service
model.
cisco@nso-stack:~/ncs-run/packages$ ncs-make-package --
service-skeleton template-based vrouter

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–4


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Step 2 Edit the vrouter.yang file, and create the service model. Create a
grouping vrouter, containing a list of routes. Each route will use the
leafs network, mask, and gateway for storing the route information.
module vrouter {
namespace "http://com/example/vrouter";
prefix vrouter;

import ietf-inet-types { prefix inet; }


import tailf-common { prefix tailf; }
import tailf-ncs { prefix ncs; }

grouping vrouter {
list routes {
key "network mask";
min-elements 1;

leaf network {
type inet:ipv4-address;
}

leaf mask {
type inet:ipv4-address;
}

leaf gateway {
mandatory true;
type inet:ipv4-address;
}
}
}

augment /ncs:services {

list vrouter {
description "This is a vRouter service";

key name;
leaf name {
type string;
}

uses ncs:service-data;
ncs:servicepoint vrouter-servicepoint;

leaf device {
mandatory true;
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}

uses vrouter;
}
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–5


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Step 3 Create the vrouter-template.xml XML template for the static route
configuration. Use the Cisco NSO CLI and the test device CLOUD-TEST
to obtain the configuration in XML format.
admin@ncs# config
Entering configuration mode terminal
admin@ncs(config)# devices device CLOUD-TEST config
admin@ncs(config-config)# ios:ip route 192.168.1.0
255.255.255.0 10.0.0.1
admin@ncs(config-config)# commit dry-run outformat xml
device CLOUD-TEST
<ip xmlns="urn:ios">
<route>
<ip-route-forwarding-list>
<prefix>192.168.1.0</prefix>
<mask>255.255.255.0</mask>
<forwarding-address>10.0.0.1</forwarding-address>
</ip-route-forwarding-list>
</route>
</ip>

Step 4 Use the XML configuration to build the template file, and parameterize
it. Replace the placeholder values with XPath queries that will use the
service instance input data:
 192.168.1.0: {network}
 255.255.255.0: {mask}
 10.0.0.1: {gateway}
In addition, add a foreach tag to the ip-route-forwarding-list
element to repeat the configuration for every entry in the routes list.
<config-template xmlns="http://tail-f.com/ns/config/1.0"
servicepoint="vrouter-servicepoint">
<devices xmlns="http://tail-f.com/ns/ncs">
<device tags="nocreate">
<name>{/device}</name>
<config>
<ip xmlns="urn:ios">
<route tags="merge">
<ip-route-forwarding-list foreach="{routes}">
<prefix>{network}</prefix>
<mask>{mask}</mask>
<forwarding-address>{gateway}</forwarding-
address>
</ip-route-forwarding-list>
</route>
</ip>
</config>
</device>
</devices>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–6


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

</config-template>

Step 5 Compile the package and reload packages in Cisco NSO.


___________________ Note ________________________________
Package reload can take a long time. Consider removing unused
packages (from previous labs) in the ~/ncs-run/packages
directory (ex. juniper-junos).
______________________________________________________________
Step 6 Create a test instance of the vrouter service.
admin@ncs(config)# services vrouter test
Value for 'device' []: CLOUD-TEST
admin@ncs(config-vrouter-test)# routes 1.2.3.0 255.255.255.0
gateway 10.0.0.1
admin@ncs(config)# commit dry-run outformat native
device CLOUD-TEST
ip route 1.2.3.0 255.255.255.0 10.0.0.1

Activity Verification
You have completed this task when you attain these results:
 You have successfully created the vrouter service for Cisco NSO.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–7


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Task 2: Create a vFirewall Service


Another second-level service that we will need is a virtual firewall service. The purpose of
this task is to implement a vFirewall service. This service package will include some
Java code, because the mapping logic requires a transformation of the input parameters
before they can be used in the device configuration.
In our example, we will work with Cisco IOS, which has a specific way of configuring an
ACL entry. The network masks are bitwise inverted – wildcard masks. Specifying ports
is valid only for a TCP or UDP protocol filter. Refer to the graphic below for a brief
explanation of the rules.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–8


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

The graphic below illustrates the model used for the vFirewall service.

Activity Procedure
Complete these steps:
Step 1 Use the ncs-make-package tool to create a new service skeleton
called vfirewall. Use the Python service-example service skeleton
to create an XML template for the device configuration, an empty
service model, and some skeleton Python code.
cisco@nso-stack:~/ncs-run/packages$ ncs-make-package --
python-skeleton --service-example --component-name Vfirewall
vfirewall

Step 2 Edit the vfirewall.yang file, and create the service model. Create a
grouping vfirewall, containing a list of access-list-rules. Each
access list rule will use leafs listed in the following table for storing the
rule information.

Name Type Description

name string Name of the ACL rule

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–9


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

action enum: permit, deny Action for the ACL rule

protocol enum: ip, icmp, udp, Layer 3 protocol for the ACL rule
tcp

src-ip inet:ipv4-address Source IP address

src-mask inet:ipv4-address Source IP address mask

src-port union: int16 or any Source port (if protocol is UDP or


TCP)

dest-ip inet:ipv4-address Destination IP address

dest-mask inet:ipv4-address Destination IP address mask

dest-port union: int16 or any Destination port (if protocol is


UDP or TCP)

Step 3 After making the changes to the skeleton model, your


vfirewall.yang service model should look similar to the following
listing.
module vfirewall {
namespace "http://com/example/vfirewall";
prefix vfirewall;

import ietf-inet-types { prefix inet; }


import tailf-common { prefix tailf; }
import tailf-ncs { prefix ncs; }

grouping vfirewall {
list access-list-rules {
ordered-by user;
key name;

leaf name {
type string;
}

leaf action {
mandatory true;
type enumeration {
enum permit;
enum deny;
}
}

leaf protocol {
default ip;
type enumeration {
enum ip;

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–10


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

enum icmp;
enum tcp;
enum udp;
}
}
leaf src-ip {
mandatory true;
type inet:ipv4-address;
}
leaf src-mask {
mandatory true;
type inet:ipv4-address;
}
leaf src-port {
when "../protocol = 'tcp' or ../protocol = 'udp'";
default any;
type union {
type uint16;
type enumeration {
enum any;
}
}
}
leaf dest-ip {
mandatory true;
type inet:ipv4-address;
}
leaf dest-mask {
mandatory true;
type inet:ipv4-address;
}
leaf dest-port {
when "../protocol = 'tcp' or ../protocol = 'udp'";
default any;
type union {
type uint16;
type enumeration {
enum any;
}
}
}
}
}

augment /ncs:services {

list vfirewall {

uses ncs:service-data;
ncs:servicepoint vfirewall-servicepoint;

description "vFirewall service";

key name;
leaf name {

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–11


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

type string;
}

leaf device {
mandatory true;
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}

uses vfirewall;
}
}
}

Step 4 Create the vfirewall-template.xml XML template for a dummy


ACL entry in a templates directory (create it manually). Use the Cisco
NSO CLI and the test device CLOUD-TEST to obtain the configuration
in XML format. Assign the ACL on the Internet-facing interface
(GigabitEthernet 3), direction in.
___________________ Note ________________________________
The Cisco IOS NED used in the lab models ACL rules (list entries)
as strings. It is possible to construct a rule that is accepted by Cisco
NSO but is later rejected by the device, making the service instance
configuration fail.
______________________________________________________________
admin@ncs# config
Entering configuration mode terminal
admin@ncs(config)# devices device CLOUD-TEST config
admin@ncs(config-config)# ios:ip access-list extended
FIREWALL
admin@ncs(config-std-nacl)# permit tcp 1.2.3.0 0.0.0.255 eq
12445 5.6.7.0 0.0.0.255 eq 80
admin@ncs(config-config)# ios:interface GigabitEthernet 3
admin@ncs(config-if)# ip access-group FIREWALL in
admin@ncs(config-std-nacl)# commit dry-run outformat xml
device CLOUD-TEST
<interface xmlns="urn:ios">
<GigabitEthernet>
<name>3</name>
<ip>
<access-group>
<direction>in</direction>
<access-list>FIREWALL</access-list>
</access-group>
</ip>
</GigabitEthernet>
</interface>
<ip xmlns="urn:ios">
<access-list>
<extended>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–12


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

<ext-named-acl>
<name>FIREWALL</name>
<ext-access-list-rule>
<rule>permit tcp 1.2.3.0 0.0.0.255 eq 12445
5.6.7.0 0.0.0.255 eq 80</rule>
</ext-access-list-rule>
</ext-named-acl>
</extended>
</access-list>
</ip>
admin@ncs(config-std-nacl)# commit dry-run outformat native
device CLOUD-TEST
ip access-list extended FIREWALL
permit tcp 1.2.3.0 0.0.0.255 eq 12445 5.6.7.0 0.0.0.255
eq 80
!
interface GigabitEthernet3
ip access-group FIREWALL in
exit

Step 5 Parameterize the static XML template with XPath variables. You will
need the following variables in place of the static values.

Name Description

$DEVICE Device Name


$INTERFACE-ID Access-group Interface ID
$ACCESS-LIST-NAME Access List Name
$ACCESS-LIST-DIRECTION Access List Direction on Interface
$ACCESS-LIST-RULE Access List Rule (as a string)

Step 6 The final parameterized template should look like the following listing.
<config xmlns="http://tail-f.com/ns/config/1.0">
<devices xmlns="http://tail-f.com/ns/ncs">
<device tags="nocreate">
<name>{$DEVICE}</name>
<config>
<interface xmlns="urn:ios">
<GigabitEthernet>
<name>{$INTERFACE-ID}</name>
<ip tags="merge">
<access-group>
<direction>{$ACCESS-LIST-
DIRECTION}</direction>
<access-list>{$ACCESS-LIST-NAME}</access-
list>
</access-group>
</ip>
</GigabitEthernet>
</interface>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–13


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

<ip xmlns="urn:ios">
<access-list tags="merge">
<extended>
<ext-named-acl>
<name>{$ACCESS-LIST-NAME}</name>
<ext-access-list-rule>
<rule>{$ACCESS-LIST-RULE}</rule>
</ext-access-list-rule>
</ext-named-acl>
</extended>
</access-list>
</ip>
</config>
</device>
</devices>
</config>

Step 7 Open the vfirewall.py template and implement the mapping logic
that will build the correct ACL rule from the input parameters. Then
apply the template. Recall the configuration command that you used to
create the static XML template. The first helper method that you will
need will be used to invert the subnet mask to create a wildcard
network. Create the helper method convert_to_wildcard in the
ServiceCallbacks class (snippet CONVERT-TO-WILDCARD).

class ServiceCallbacks(Service):
...
def _convert_to_wildcard(self, mask):
# Could use python3 ipaddress module in future
mask_bytes = struct.unpack('BBBB',
socket.inet_aton(mask))
inverted_bytes = struct.pack('BBBB', *[~x & 0xFF for
x in mask_bytes])
return socket.inet_ntoa(inverted_bytes)

Step 8 The helper method uses two standard Python modules: socket and
struct. Add import statements at the top of your vfirewall.py
module (snippet IMPORT-BATTERIES).
import socket
import struct

Step 9 The rules for building an ACL rule state that the TCP or UDP port
number must be prepended with the ‘eq ‘ string. Create another helper
method, ¬_stringify_port, in the SeviceCallbacks class (snippet
STRINGIFY-PORT).
def _stringify_port(self, port):
if isinstance(port, int):
return 'eq ' + str(port)
else:
return ''

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–14


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Step 10 The third helper method, _build_acl_rule, will be used to create the
ACL rule string from the input parameters (snippet BUILD-ACL-
RULE).
def _build_acl_rule(self, rule):
src_port = self._stringify_port(rule.src_port)
dest_port = self._stringify_port(rule.dest_port)

acl_entry = '{action} {protocol} {src_ip} {src_mask}


{src_port} ' \
'{dest_ip} {dest_mask} {dest_port}' \
.format(action=rule.action.string,
protocol=rule.protocol,
src_ip=rule.src_ip,

src_mask=self._convert_to_wildcard(rule.src_mask),
src_port=src_port,
dest_ip=rule.dest_ip,

dest_mask=self._convert_to_wildcard(rule.dest_mask),
dest_port=dest_port)

self.log.info('Generated ACL entry:


{}'.format(acl_entry))
return acl_entry

____________________ Note _______________________________


In this implementation example, all helper methods are part of the
ServiceCallbacks class. Be sure to use the correct indendation
level. You could also implement these methods as functions in the
vfirewall module or in a separate supporting module.
______________________________________________________________
Step 11 You can implement the cb_create method to provide device
configuration. In the beginning of the method, set up some global
service variables. For this example, we hardcode the interface and ACL
direction, but these could also be service input parameters (snippet
SERVICE-GLOBAL-PARAMETERS).
@Service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=',
service._path, ')')

device = service.device

# Some hardcoded parameters


acl_name = 'FIREWALL'
acl_interface = '3'
acl_direction = 'in'

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–15


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Step 12 Apply the previously prepared vfirewall-template.xml template


with the appropriate variable values. For each entry in the access-
list-rules list, prepare the variables and apply the template
(snippet APPLY-TEMPLATE).
for rule in service.access_list_rules:
template = ncs.template.Template(service)
tvars = ncs.template.Variables()

tvars.add('DEVICE', device)
tvars.add('ACCESS-LIST-NAME', acl_name)
tvars.add('INTERFACE-ID', acl_interface)
tvars.add('ACCESS-LIST-DIRECTION',
acl_direction)

tvars.add('ACCESS-LIST-RULE',
self._build_acl_rule(rule))
template.apply('vfirewall-template', tvars)

Step 13 Optionally, add some instruction to the Makefile that will allow you to
check the syntax and style of your Python code. Do this step by running
the pylint tool on all Python source files. The tool has already been
installed in the lab environment but is not bundled by default with
Cisco NSO installation.
all: fxs pylint

SRC = $(wildcard yang/*.yang)


FXS = $(SRC:yang/%.yang=../load-dir/%.fxs)

PYLINT = pylint
PYLINTFLAGS = --disable=R,C --reports=n
PYDIR = ../python
PYTHONFILES = $(wildcard $(PYDIR)/*.py)

pylint: $(patsubst %.py,%.pylint,$(PYTHONFILES))

%.pylint:
$(PYLINT) $(PYLINTFLAGS) $*.py || (test $$? -ge 4)

fxs: $(FXS)

Step 14 Compile and reload packages.


Step 15 Create a test instance of the vfirewall service with the parameters
that follow. You do not necessarily have to commit the configuration at
the end.
admin@ncs(config)# show configuration
services vfirewall vfirewall-first-test
! first
vfirewall access-list-rules test
action permit
protocol tcp

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–16


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

src-ip 0.0.0.0
src-mask 0.0.0.0
dest-ip 1.2.3.4
dest-mask 255.255.255.255
dest-port 80
!
!
admin@ncs(config)# commit dry-run outformat native
device CLOUD-TEST
ip access-list extended FIREWALL
permit tcp 0.0.0.0 255.255.255.255 1.2.3.4 0.0.0.0 eq 80
!
interface GigabitEthernet3
ip access-group FIREWALL in
exit

Activity Verification
You have completed this task when you attain these results:
 You have successfully implemented the vfirewall service.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–17


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Task 3: Create a Cloud Service


The purpose of this task is to implement a cloud service. The top-level service cloud will
create instances of the vfirewall and vrouter services. The service model will contain
all necessary parameters for creating a router and applying the firewall rules. In this
first task, the cloud service will use an existing device, but you will later modify it to
automatically create a new virtual device.
The cloud service will depend on several different packages:

 vfirewall: the vFirewall service, implementing the virtual firewall


functionality
 vrouter: the vRouter service, implementing the virtual router
functionality

Visual Objective
The graphic below shows the graphical representation of the cloud service model.

Activity Procedure
Subtask 1: Create the Cloud Service YANG Model
Complete these steps:
Step 1 Use the ncs-make-package tool to create a new service skeleton
called “vcloud.” Use the Python service-example service skeleton to
create an XML template for the device configuration, an empty service
model and some skeleton Python code.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–18


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

cisco@nso-stack:~/ncs-run/packages$ ncs-make-package --
python-skeleton --service-example --component-name Cloud
cloud

Step 2 Edit the cloud.yang file, containing the service model. Add a leaf,
device, for specifying an existing device. Add two containers for the
vrouter and vfirewall configuration. To avoid repetition when
modeling the vRouter and vFirewall parameters, use a uses
statement, for referencing the vrouter and vfirewall service model
(snippets CLOUD-MODEL-IMPORT and CLOUD-MODEL-SERVICE).
module cloud {
namespace "http://com/example/cloud";
prefix cloud;

import ietf-inet-types { prefix inet; }


import tailf-common { prefix tailf; }
import tailf-ncs { prefix ncs; }
import vrouter { prefix vrouter; }
import vfirewall { prefix vfirewall; }

augment /ncs:services {

list cloud {
description "This is the Cloud service";

key name;
leaf name {
type string;
}

uses ncs:service-data;
ncs:servicepoint cloud-servicepoint;

leaf device {
mandatory true;
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}

container vrouter {
presence "vrouter";

uses vrouter:vrouter;
}

container vfirewall {
presence "vfirewall";

uses vfirewall:vfirewall;
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–19


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

}
}

___________________ Note ________________________________


The use of the presence statements in the containers is important,
because you are going to check for the existence of the container in
the mapping logic to determine if the vRouter or vFirewall
functionality is required in the cloud service. The parameter for
the presence statement is a string describing its purpose.
______________________________________________________________
Step 3 Because you referenced statements defined in another module (the
import vrouter and vfirewall statements), you also need to inform
the compiler about where to find the vrouter and vfirewall module.
Add the YANGPATH to the service Makefile.
...
SRC = $(wildcard yang/*.yang)
FXS = $(SRC:yang/%.yang=../load-dir/%.fxs)

YANGPATH ?= --yangpath yang


YANGPATH += --yangpath ../../vrouter/src/yang
YANGPATH += --yangpath ../../vfirewall/src/yang
...

Step 4 Optionally, add some instruction to the Makefile that will allow you to
check the syntax and style of your Python code. This is accomplished by
running the pylint tool on all Python source files. The tool has already
been installed in the lab environment, but is not bundled by default
with Cisco NSO installation.
all: fxs pylint

SRC = $(wildcard yang/*.yang)


FXS = $(SRC:yang/%.yang=../load-dir/%.fxs)

...

PYLINT = pylint
PYLINTFLAGS = --disable=R,C --reports=n
PYDIR = ../python
PYTHONFILES = $(wildcard $(PYDIR)/*.py)

pylint: $(patsubst %.py,%.pylint,$(PYTHONFILES))

%.pylint:
$(PYLINT) $(PYLINTFLAGS) $*.py || (test $$? -ge 4)

fxs: $(FXS)

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–20


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Subtask 2: Implement the create() Method


Step 1 The skeleton cloud.py class already contains the create() method
with some sample code. Remove the commented-out code, and keep
only the method declaration with the try/catch block.
class ServiceCallbacks(Service):

# The create() callback is invoked inside NCS FASTMAP


and
# must always exist.
@Service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=',
service._path, ')')
# Remove rest of method

Step 2 Prepare the variables for storing the “global service input parameters.”
Store the value of the device leaf in a device variable (snippet
DEVICE-NAME).
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=',
service._path, ')')

device = service.device

Step 3 Recall the input parameters for the vrouter service. You will need to
construct an XML template in order to create a service instance. Use
the Cisco NSO CLI to create an instance (or simply use an existing
configured instance from the previous task) and obtain the
configuration in XML.
___________________ Note ________________________________
Use the show running-configuration services vrouter
<instance> | display xml command to get the service instance
configuration in XML.
______________________________________________________________

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–21


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Step 4 Parameterize the template. Use $NAME and $DEVICE variables for the
name and device input parameters for the vrouter service. Use the
foreach tag to copy the input parameters containing the list of static
routes directly from the cloud service instance data. Save the XML
template in the vrouter-service-template.xml template in the
cloud service package (under the templates directory, create it
manually). The final solution is as follows (snippet VROUTER-
SERVICE-TEMPLATE).
<config xmlns="http://tail-f.com/ns/config/1.0">
<services xmlns="http://tail-f.com/ns/ncs">
<vrouter xmlns="http://com/example/vrouter">
<name>{$NAME}</name>
<device>{$DEVICE}</device>
<routes foreach="{/routes}">
<network>{network}</network>
<mask>{mask}</mask>
<gateway>{gateway}</gateway>
</routes>
</vrouter>
</services>
</config>

Step 5 Apply the vrouter-service-template.xml service template in the


cloud service, in the cb_create() method. In the beginning, check
for the existence of the vrouter container in the cloud service input
parameters with the Maagic exists() method. If the container exists,
you need to apply the template; otherwise, ignore it (snippet CREATE-
VROUTER-SERVICE).).
if service.vrouter.exists():
self.log.info('vRouter config exists, will
create vRouter instance')
template =
ncs.template.Template(service.vrouter)
tvars = ncs.template.Variables()
tvars.add('NAME', service.name)
tvars.add('DEVICE', device)
template.apply('vrouter-service-template',
tvars)

Step 6 Perform Steps 2 through 4 for the vfirewall service. Create an XML
template for the service input parameters, and conditionally apply the
template from the cloud service based on the existence of the
vfirewall container. The final template and code are as follows
(snippets VFIREWALL-SERVICE-TEMPLATE and CREATE-
VFIREWALL-SERVICE).
<config xmlns="http://tail-f.com/ns/config/1.0">
<services xmlns="http://tail-f.com/ns/ncs">
<vfirewall xmlns="http://com/example/vfirewall">
<name>{$NAME}</name>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–22


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

<device>{$DEVICE}</device>
<access-list-rules foreach="{/access-list-rules}">
<name>{name}</name>
<action>{action}</action>
<protocol>{protocol}</protocol>
<src-ip>{src-ip}</src-ip>
<src-mask>{src-mask}</src-mask>
<src-port>{src-port}</src-port>
<dest-ip>{dest-ip}</dest-ip>
<dest-mask>{dest-mask}</dest-mask>
<dest-port>{dest-port}</dest-port>
</access-list-rules>
</vfirewall>
</services>
</config>

if service.vfirewall.exists():
self.log.info('vFirewall config exists, will
create vFirewall instance')
template =
ncs.template.Template(service.vfirewall)
tvars = ncs.template.Variables()
tvars.add('NAME', service.name)
tvars.add('DEVICE', device)
template.apply('vfirewall-service-template',
tvars)

Step 7 Create a test instance of the cloud service.


admin@ncs(config)# services cloud first-test
Value for 'device' (<string>): CLOUD-TEST
admin@ncs(config-cloud-first-test)# commit
Commit complete.

Step 8 Configure a static route on the first-test cloud service instance, to


test the vRouter functionality.
admin@ncs# config
Entering configuration mode terminal
admin@ncs(config)# services cloud first-test
admin@ncs(config-cloud-first-test)# vrouter routes 1.2.3.0
255.255.255.0 gateway 5.6.7.8
admin@ncs(config-routes-1.2.3.0/255.255.255.0)# commit dry-
run outformat native
device CLOUD-TEST
ip route 1.2.3.0 255.255.255.0 5.6.7.8
admin@ncs(config-routes-1.2.3.0/255.255.255.0)# commit
Commit complete.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–23


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

admin@ncs# config
Entering configuration mode terminal
admin@ncs(config)# services cloud first-test
admin@ncs(config-cloud-first-test)# vfirewall access-list-
rules test-rule
Value for 'action' [deny,permit]: permit
Value for 'src-ip' (<IPv4 address>): 0.0.0.0
Value for 'src-mask' (<IPv4 address>): 0.0.0.0
Value for 'dest-ip' (<IPv4 address>): 1.2.3.4
Value for 'dest-mask' (<IPv4 address>): 255.255.255.255
admin@ncs(config-access-list-rules-test-rule)# protocol tcp
admin@ncs(config-access-list-rules-test-rule)# commit dry-
run outformat native
native {
device {
name CLOUD-TEST
data ip access-list extended FIREWALL
permit tcp 0.0.0.0 255.255.255.255 1.2.3.4
0.0.0.0
exit
}
}
admin@ncs(config-access-list-rules-test-rule)# commit
Commit complete.

Step 9 The commit operation must be completed. Examine the output of the
show services cloud first-test again, and notice the changed
device-modifications, containing the static route and a firewall rule.
admin@ncs# show services cloud first-test
services cloud first-test
device-modifications devices {
device CLOUD-TEST {
config {
ios:ip {
route {
+ ip-route-
forwarding-list 1.2.3.0 255.255.255.0 5.34.23.4 {
+ }
}
access-list {
extended {
+ ext-named-acl
FIREWALL {
+ ext-
access-list-rule "permit tcp 0.0.0.0 255.255.255.255
1.2.3.4 0.0.0.0 ";
+ }
}
}
}
}
}
}
services {

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–24


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

+ vfirewall first-test {
+ device CLOUD-TEST;
+ access-list-rules test-rule {
+ action permit;
+ protocol tcp;
+ src-ip 0.0.0.0;
+ src-mask 0.0.0.0;
+ dest-ip 1.2.3.4;
+ dest-mask
255.255.255.255;
+ dest-port any;
+ }
+ }
+ vrouter first-test {
+ device CLOUD-TEST;
+ routes 1.2.3.0 255.255.255.0
{
+ gateway 5.34.23.4;
+ }
+ }
}

modified devices [ CLOUD-TEST ]


modified services [
/ncs:services/vrouter:vrouter[vrouter:name='first-test']
/ncs:services/vfirewall:vfirewall[vfirewall:name='first-
test'] ]
directly-modified services [
/ncs:services/vfirewall:vfirewall[vfirewall:name='first-
test'] /ncs:services/vrouter:vrouter[vrouter:name='first-
test'] ]

____________________________ Note ________________________________


In Cisco NSO version 4.2, the operational data device-modifications also
display any directly modified services. Notice that the cloud service instance
also contains a configuration for the vRouter and vFirewall service instances.
________________________________________________________________________

Activity Verification
You have completed this task when you attain these results:
 You have successfully implemented the cloud service.
 You have successfully created a test instance of the cloud service, and
configured the vRouter and vFirewall functionality on the test CLOUD-
TEST device.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–25


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Task 4: Implement NFV for the Cloud Service


The purpose of this task is to implement a cloud service. The top-level service Cloud
already creates instances of the vfirewall and vrouter services. The service model
contains all necessary parameters for creating a router and applying the firewall rules.
In this task, the service package will also be responsible for virtual network function
(VNF) creation.
The cloud service will depend on several different packages:

 vfirewall: the vFirewall service, implementing the virtual firewall


functionality
 vrouter: the vRouter service, implementing the virtual router
functionality
 Resource Management packages that you will reuse:
 vm-manager, vm-manager-esc, esc: Service packages and NEDs
used to integrate Cisco NSO with Cisco Elastic Services Controller
(Cisco ESC)
 resource-manager, ip-address-allocator: Auxiliary packages
used for resource management (IP address pools, numeric IDs)

Activity Procedure
Subtask 1: Copy the Required Packages
Complete these steps:
Step 1 The Resource Management packages required by the cloud service are
located on the NSO server, in the /home/cisco/advanced-
lab3/packages/ folder. Copy all packages to your packages folder in
$HOME/ncs-run/packages.
cisco@ncs:~/ncs-run/packages$ cp -pr ~/advanced-
lab3/packages/vm-manager .
cisco@ncs:~/ncs-run/packages$ cp -pr ~/advanced-
lab3/packages/vm-manager-esc .
cisco@ncs:~/ncs-run/packages$ cp -pr ~/advanced-
lab3/packages/esc .
cisco@ncs:~/ncs-run/packages$ cp -pr ~/advanced-
lab3/packages/resource-manager .
cisco@ncs:~/ncs-run/packages$ cp -pr ~/advanced-
lab3/packages/ipaddress-allocator .

Step 2 Copy the updated Cisco IOS NED from the Lab3 solution folder. In
Task 5, you will use the new functionality of the NED.
cisco@ncs:~/ncs-run/packages$ cp -pr ~/advanced-
lab3/packages/cisco-ios .

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–26


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Step 3 Reload packages and make sure that all packages are loaded correctly
before proceeding.
___________________________ WARNING ____________________________
After upgrading the Cisco IOS NED, you will receive an error message during
the package reload, notifying you that the l3mplsvpn-iosxr-template.xml
is invalid. The template that is part of the l3mplsvpn package still refers to
the old device model. If you do not plan to use the l3mplsvpn package from
Lab 1 any longer, it is safe to ignore the error. Otherwise, you must update the
template to use the upgraded Cisco IOS device model.
________________________________________________________________________

Subtask 2: Modify the cloud Service Model


In this subtask, you will modify the cloud service model to accommodate VNF
management on OpenStack. You will add leafs for specifying the OpenStack tenant and
networks. Additionally, the device leaf will no longer be configurable.

Step 1 Add customer-network, internet-network, and tenant leafs to


the cloud.yang service model (snippet CLOUD-NFV-MODEL).
module cloud {
...
augment /ncs:services {

list cloud {
...
uses ncs:service-data;
ncs:servicepoint cloud-servicepoint;

leaf device {
mandatory true;
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}

leaf tenant {
mandatory true;
type string;
}

leaf customer-network {
mandatory true;
type string;
}

leaf internet-network {
mandatory true;
type string;
}

container vrouter {

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–27


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

presence "vrouter";

uses vrouter:vrouter;
}
...

Step 2 Modify the device leaf to be nonconfigurable (operational data)


(snippet CLOUD-NVF-MODEL-DEVICE).
leaf device {
config false;
tailf:cdb-oper {
tailf:persistent true;
}
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}

Subtask 3: Modify the cloud Service Mapping Logic


Step 1 Copy a helper Python module resource_management to your cloud
package that will help you to work with the resource-manager and
vm-manager packages. The module is located in the folder
/opt/resources/lab3/lab3-task4-start-
python/resource_management. You need to copy the whole directory
structure to the python folder of the cloud service package.
cisco@nso-stack:~/ncs-run/packages/$ cp –pr
/opt/resources/lab3/lab3-task4-start-
python/resource_management cloud/python

Step 2 Start by importing the newly copied resource_management module


to the cloud.py file. Additionally, import the re - Python built-in
regular expression module. At the beginning of the file, add two import
statements (snippet IMPORT-RESOURCE-MANAGER).
import ncs.template
import re
from resource_management import ipaddress_allocator,
vm_manager

Step 3 Add a helper method for allocating the management IP address to the
ServiceCallbacks class. The method will use the
resource_manager Python module to interface with the resource-
manager packages to request a new IP address from the IP address
pool named mgmt. When the request is processed, the method will
return the allocated IP address (snippet ALLOCATE-MGMT-
ADDRESS).
ServiceCallbacks(Service):
...

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–28


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

def _allocate_mgmt_address(self, tctx, service,


service_path, root, allocation_id):
try:
ipaddress_allocator.subnet_request(service,
service_path, 'mgmt', tctx.username, 32, allocation_id)
result = ipaddress_allocator.subnet_read(tctx,
root, 'mgmt', allocation_id)
self.log.info('Got allocated ID:
{}'.format(result))
return re.sub('/32$', '', result)
except ipaddress_allocator.ResourceWait:
pass

Step 4 Execute the new helper method from the main cb_create() method,
and check the returned result. If the IP address is not returned, it
means that the service mapping logic must wait for a redeploy from the
external subscriber. Exit from the main method at this point (snippet
EXECUTE-ALLOCATE-MGMT-ADDRESS).
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=',
service._path, ')')
service_path =
"/services/cloud[name='{}']".format(service.name)

mgmt_ip = self._allocate_mgmt_address(tctx,
service,
service_path,
root,
service.name)
if not mgmt_ip:
self.log.info('Waiting for redeploy')
return proplist

Step 5 Copy a vm-manager-template.xml from


/opt/resources/lab3/lab3-task4-end-python to your cloud
package templates directory.
cisco@nso-stack:~/ncs-run/packages/$ cp
/opt/resources/lab3/lab3-task4-end-python/vm-manager-
template.xml cloud/templates/

Step 6 Add a new helper method for creating a new VNF request to the
ServiceCallbacks class. The method will set the
resource_manager Python module to interface with the vm-manager
packages to request a new VNF. In the first part, apply the prepared
template vm-manager-template to create the start request (snippet
CREATE-VNF).
def _create_vnf(self, tctx, service, service_path,
tenant, deployment_name, mgmt_ip):
tvars = ncs.template.Variables()

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–29


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

vm_name = tenant + "_" + deployment_name + "_" +


"CSR"
tvars.add('NAME', vm_name)
tvars.add('ESC', 'esc0')
tvars.add('TENANT', tenant)
tvars.add('DEPNAME', deployment_name)
tvars.add('VM_GROUP', 'CSR')
tvars.add('VM_TYPE', 'csr')
tvars.add('IMAGE_ID', 'csr')
tvars.add('FLAVOR_ID', 'csr')
tvars.add('CUSTOMER-NETWORK',
service.customer_network)
tvars.add('INTERNET-NETWORK',
service.internet_network)
tvars.add('MGMT-IP', mgmt_ip)
template = ncs.template.Template(service)
template.apply('vm-manager-template', tvars)

Step 7 In the second part of create_vnf function, register the service


instance with this start request. When the request is processed (the
VNF is running and was automatically added to Cisco NSO Device
Manager), the method will return the generated device name (snippet
CREATE-VNF-RETURN).
vm_manager.register_start_request(service, vm_name,
service_path)
device_name =
'{tenant}_{deployment_name}_{vm_group}_{esc}'\
.format(tenant=tenant,

deployment_name=deployment_name,
vm_group='CSR',
esc='esc0')

if vm_manager.device_ready(tctx, device_name):
return device_name

Step 8 Execute the new helper method from the main cb_create() method
(overwrite device = service.device line), and check the returned
result. If the device name is not returned, it means that the service
mapping logic must wait for a redeploy from the external subscriber.
Exit from the main method at this point (snippet EXECUTE-CREATE-
VNF).
deployment_name = 'cloud-' + service.name VNF).
device = self._create_vnf(tctx,
service,
service_path,
service.tenant,
deployment_name,
mgmt_ip)
if not device:
self.log.info('Waiting for CSR')
return proplist

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–30


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Step 9 After the device is automatically added into NSO Device Manager by
the vm-manager-esc package, you can store the device name in the
operational device leaf that is part of the service model. Create
another helper method, _set_operational_device_leaf, in the
ServiceCallbacks class to write the operational data (snippet SET-
OPERATIONAL-DEVICE-LEAF).
def _set_operational_device_leaf(self, tctx, service,
device_name):
with ncs.maapi.single_write_trans(tctx.username,
tctx.context, db=ncs.OPERATIONAL) as oper_th:
oper_service = ncs.maagic.get_node(oper_th,
service._path)
oper_service.device = device_name
oper_th.apply()

Step 10 Execute the helper method from the main cb_create() method after
the device is available for configuration (snippet EXECUTE-SET-
OPERATIONAL-DEVICE-LEAF).
if not device:
self.log.info('Waiting for CSR')
return proplist

self._set_operational_device_leaf(tctx, service,
device)

Step 11 Use the Maagic API to set the hostname on the Cisco IOS device. You
can put this code into another helper method, and execute it from the
main cb_create() method (snippet SET-HOSTNAME).

class ServiceCallbacks(Service):
def cb_create(self, tctx, root, service, proplist):
...
self._set_operational_device_leaf(tctx, service,
device)
self._set_hostname(root, device)
...

def _set_hostname(self, root, device_name):


# IOS XE does not like hostname longer that 16 chars

root.devices.device[device_name].config.ios__hostname =
device_name[:16]

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–31


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Subtask 4: Add a Reactive FASTMAP Service Plan


At this point, the mapping logic for the cloud service should be completely functional; it
should run without errors. Before you test it, you will also define and provide a Reactive
FASTMAP service plan. By defining two plan components (one for the service instance as
a whole, called self, and one for each of the VNFs involved), you or another operator will
be able to use the operational data to determine the current stage of the service instance
provisioning process. The following table contains two examples of plan components and
states.

Plan Plan
Component Component
Name Type Plan Component States Description
ncs:init Represents the complete service
self ncs:self instance configuration
ncs:ready
ncs:init Represents the provisioning and
configuration process of the VNF
cloud:mgmt-address-
CSR cloud:vnf allocated
cloud:vnf-created
ncs:ready

Step 1 Add the new components and states to the cloud service model. Use
the preceding table as a reference for the plan component types and
states (snippet SERVICE-PLAN-COMPONENTS).
module cloud {
namespace "http://com/example/cloud";
prefix cloud;

import ietf-inet-types { prefix inet; }


import tailf-common { prefix tailf; }
import tailf-ncs { prefix ncs; }
import vrouter { prefix vrouter; }
import vfirewall { prefix vfirewall; }

identity vnf {
base ncs:plan-component-type;
}

identity mgmt-address-allocated {
base ncs:plan-state;
}

identity vnf-created {
base ncs:plan-state;
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–32


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Step 2 the additional data structures. Add a uses ncs:plan-data statement


to the service model (cloud list).
augment /ncs:services {

list cloud {
description "This is the Cloud service";

key name;
leaf name {
type string;
}

uses ncs:service-data;
uses ncs:plan-data;
ncs:servicepoint cloud-servicepoint;`

Step 3 In the Python code, you will now define the plan components and states
and set the status as part of the mapping logic. At the beginning of the
cb_create() method, define a plan_data dictionary that will store
all possible and reached states for the additional VNF component. In
the initialization, the reached_states list will be empty, but you will
add new entries for each of the Reactive FASTMAP stages (snippet
PLAN-DATA).
class ServiceCallbacks(Service):
@Service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=',
service._path, ')')
service_path =
"/services/cloud[name='{}']".format(service.name)

plan_data = {'CSR':{'states':['mgmt-address-
allocated', 'vnf-created'],
'reached_states': []}}

Step 4 Import the PlanComponent class from the ncs.application package


at the beginning of the cloud.py file.
import ncs.template
import ncs
from ncs.application import Service, PlanComponent
import ncs.template
import re
from resource_management import ipaddress_allocator,
vm_manager

Step 5 Create a helper method, _write_plan_data, in the


ServiceCallbacks class. The method will be used to write the
operational plan data, using the PlanComponent Python API (snippet
WRITE-PLAN-DATA).

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–33


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

def _write_plan_data(self, service, plan_data):


self_plan = PlanComponent(service, 'self',
'ncs:self')
self_plan.append_state('ncs:init')
self_plan.append_state('ncs:ready')
self_plan.set_reached('ncs:init')

finished = True
for component, states in plan_data.iteritems():
vnf_plan = PlanComponent(service, component,
'cloud:vnf')
vnf_plan.append_state('ncs:init')
vnf_plan.set_reached('ncs:init')
[vnf_plan.append_state(x) for x in
states['states']]
[vnf_plan.set_reached(x) for x in
states['reached_states']]
vnf_plan.append_state('ncs:ready')
if len(states['states']) ==
len(states['reached_states']):
vnf_plan.set_reached('ncs:ready')
else:
finished = False

if finished:
self_plan.set_reached('ncs:ready')

____________________________ Note ________________________________


The method works with the plan_data dictionary that contains various
components. Each component is another Python dictionary, containing a list of
states and reached_states. The states list is used to populate the
operational data. The reached_states list is used to set the status of each
state.
________________________________________________________________________
Step 6 Find the section of the code that executes the
_allocate_mgmt_address method. If the method returns a valid IP
address, it means that we are now in the second stage of the
provisioning process and can set the mgmt-address-allocated state
to the reached status. Add a new entry to the reached_states list of
the CSR component. If the IP address is not available yet, we must still
write the plan data before exiting from the mapping logic. Add a new
method call to the _write_plan_data method in the conditional
statement checking for IP address (snippet ADD-MGMT-ADDRESS-
ALLOCATED).
...
if not mgmt_ip:
self.log.info('Waiting for redeploy')
self._write_plan_data(service, plan_data)
return proplist

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–34


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

plan_data['CSR']['reached_states'].append('mgmt-
address- allocated')

____________________ Note _______________________________


Add the method call to _write_plan_data inside the if-block, but
the plan_data modification must be outside.
______________________________________________________________
Step 7 Find the section of the code that executes the _create_vnf method. If
the method returns a valid device name, it means that we are now in
the third stage of the provisioning process and can set the vnf-
created state to the reached status. Add a new entry to the
reached_states list of the CSR component. If the VNF is not yet
available, again write the current service plan before exiting from the
mapping logic (snippet ADD-VNF-CREATED).
if not device:
self.log.info('Waiting for CSR')
self._write_plan_data(service, plan_data)
return proplist

self._set_operational_device_leaf(tctx, service,
device)
plan_data['CSR']['reached_states'].append('vnf-
created')

Step 8 At the end of the mapping logic, just before the end of the
cb_create() method, add the final call to the _write_plan_data
method to ensure that plan components are created in the final stage of
the service provisioning process as well (snippet FINAL-WRITE-PLAN-
DATA).
if service.vrouter.exists():
...

self._write_plan_data(service, plan_data)

Subtask 5: Configure the Management IP Address Pool and Add Cisco


ESC
Recall that the cloud service uses the Resource Allocator to request a new management
IP address for the new virtual device. Before testing the service, you need to configure
the pool of addresses. You also need to add the Cisco Elastic Services Controller (Cisco
ESC) device into Cisco NSO, and subscribe to NETCONF notifications.
Step 1 Create a new ip-address-pool with the following parameters:

 name: mgmt
 subnet: 10.1.0.0/24

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–35


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

 exclude: 10.1.0.0/28
admin@ncs(config)# resource-pools ip-address-pool mgmt
admin@ncs(config-ip-address-pool-mgmt)# subnet 10.1.0.0 24
admin@ncs(config-ip-address-pool-mgmt)# exclude 10.1.0.0 28
admin@ncs(config-ip-address-pool-mgmt)# commit

Step 2 Add Cisco ESC into Cisco NSO. The NED is already loaded, and Cisco
ESC is running. Use the following parameters for the new device:
 name: esc0
 address: 198.18.134.12
 port 830
 authgroup: esc
 device-type: netconf
admin@ncs(config)# devices device esc0
admin@ncs(config-device-esc0)# address 198.18.134.12
admin@ncs(config-device-esc0)# port 830
admin@ncs(config-device-esc0)# device-type netconf
admin@ncs(config-device-esc0)# authgroup esc
admin@ncs(config-device-esc0)# state admin-state unlocked
admin@ncs(config-device-esc0)# commit
admin@ncs# devices device esc0 ssh fetch-host-keys
result updated
fingerprint {
algorithm ssh-dss
value 71:66:f6:a2:af:a8:1f:73:11:00:82:33:d0:c5:3d:3f
}

Step 3 Subscribe to ESC NETCONF notifications, the escEvent stream.


admin@ncs(config)# devices device esc0
admin@ncs(config-device-esc0)# netconf-notifications
subscription vm-status
Value for 'stream' (<string>): escEvent
Value for 'local-user' (<string>): admin

Step 4 Perform a sync-from on the esc0 device.


____________________ Note _______________________________
It is important to do a sync-from at this point. Otherwise, testing
the cloud service will fail, because the Cisco ESC device will be out
of sync.
______________________________________________________________

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–36


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Step 5 Create a test instance of the cloud service.


admin@ncs(config)# services cloud second-test
Value for 'tenant' (<string>): admin
Value for 'customer-network' (<string>): customer
Value for 'internet-network' (<string>): internet
admin@ncs(config-cloud-first-test)# commit
Commit complete.

Step 6 View the progress of the request through RFM Service Plan:
admin@ncs# show services cloud second-test plan
NAME TYPE STATE STATUS WHEN
------------------------------------------------------------
----------
self self init reached 2016-08-
23T15:07:11
ready not-reached -
CSR vnf init reached 2016-08-
23T15:07:11
mgmt-address-allocated reached 2016-08-
23T15:07:11
vnf-created not-reached -
ready not-reached -

Step 7 View the progress of the request in various logs:


 ncs-python-vm-cloud.log on Cisco NSO

 escmanager.log on ESC
(10.1.0.10:/var/log/esc/escmanager.log)

Step 8 View the status of the VM instantiation process on the OpenStack


controller with the nova list command.
cisco@nso:~/$ nova list
+--------------------------------------+--------------------
----------------------------------------+--------+----------
--+-------------+-------------------------------------------
---------------------------+
| ID | Name
| Status | Task State | Power State | Networks
|
+--------------------------------------+--------------------
----------------------------------------+--------+----------
--+-------------+-------------------------------------------
---------------------------+
| a5c0a579-e471-4244-819a-f4897ba43fb9 |
SystemAdminTena_CSR_0_773127ab-71b6-4c36-a4f9-0253998dfc9b |
ACTIVE | - | Running | customer=20.0.0.7;
mgmt=10.1.0.16, 172.16.122.206; internet=30.0.0.7 |
| 8e33a05b-6785-423d-b8af-1e3613c80243 | esc2
| ACTIVE | - | Running | mgmt=10.1.0.10
|

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–37


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

| 657016fa-c22e-465a-94b2-a17213f8ca54 | moo
| ACTIVE | - | Running | public=172.16.122.208
|
+--------------------------------------+--------------------
----------------------------------------+--------+----------
--+-------------+-------------------------------------------
---------------------------+

Step 9 Check the service status in Cisco NSO with the show services
cloud first-test command.
admin@ncs# show services cloud second-test
services cloud first-test
device-modifications devices {
device admin_cloud-second-
test_CSR_esc0 {
config {
- ios:hostname csr;
+ ios:hostname admin_cloud-
second-test_CSR_esc0;
}
}
}
vm-manager {
+ start admin_cloud-second-test_CSR
{
+ deployment-name cloud-second-
test;
+ vm-device esc0;
+ tenant admin;
+ vm-type csr;
+ vm-group CSR;
+ day0-url
http://controller:8080/csr_config.txt;
+ image-id csr;
+ flavor-id csr;
+ interface 0 {
+ name mgmt;
+ ip 10.1.0.16;
+ }
+ interface 1 {
+ name customer;
+ }
+ interface 2 {
+ name internet;
+ }
+ scaling-min 1;
+ scaling-max 1;
+ allocators
/services/cloud:cloud[name='second-test'];
+ }
}
resource-pools {
ip-address-pool mgmt {

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–38


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

+ allocation admin_cloud-
second-test_CSR_esc0 {
+ allocating-service
/services/cloud:cloud[name='second-test'];
+ request {
+ subnet-size 32;
+ }
+ }
}
}

modified devices [ admin_cloud-second-test_CSR_esc0 ]


directly-modified devices [ admin_cloud-second-
test_CSR_esc0 ]
device-list [ admin_cloud-second-test_CSR_esc0 ]

Step 10 Configure a static route on the second-test cloud service instance


to test the vRouter functionality.
admin@ncs# config
Entering configuration mode terminal
admin@ncs(config)# services cloud second-test
admin@ncs(config-cloud-first-test)# vrouter routes 1.2.3.0
255.255.255.0 gateway 5.6.7.8
admin@ncs(config-routes-1.2.3.0/255.255.255.0)# commit dry-
run outformat native
device admin_cloud-second-test_CSR_esc0
ip route 1.2.3.0 255.255.255.0 5.6.7.8
admin@ncs(config-routes-1.2.3.0/255.255.255.0)# commit
Commit complete.

Step 11 The commit operation must be completed. Because the VNF for the
cloud service already exists, this change will only reconfigure the
existing virtual device. Examine the output of show services cloud
second-test again, and notice the changed device modifications
containing the static route.
admin@ncs# show services cloud second-test
services cloud first-test
device-modifications devices {
device admin_cloud-second-
test_CSR_esc0 {
config {
- ios:hostname csr;
+ ios:hostname
admin_second-first-test_CSR_esc0;
ios:ip {
route {
+ ip-route-
forwarding-list 1.2.3.0 255.255.255.0 5.6.7.8 {
+ }
}
}
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–39


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

}
}

Activity Verification
You have completed this task when you attain these results:
 You have successfully implemented the cloud service.

 You have successfully created a test instance of the cloud service, and
configured the vRouter and vFirewall functionality on a virtual device.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–40


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Task 5: Implement a ping Action


The purpose of this task is to implement a ping action that is available on the cloud
service. The action can then be used by operators to ping any IP address from the virtual
device.
You will add the appropriate changes to the service model, and implement the action in
Python. The action will use another action defined in the Cisco IOS NED that allows
executing a ping command directly on the device.

Although this new action will only return the string result of the ping command from
the device, it shows how to use Cisco NSO features to provide some additional
operational data that can be used for service assurance.

Activity Procedure
Complete these steps:
Step 1 Examine the ping action definition in the Cisco IOS NED. The file
tailf-ned-cisco-ios-stats.yang is located in the
packages/cisco-ios/src/yang folder. Use the model to determine
the input and output parameters for the ping action and the path to
execute the action.
Step 2 Verify that the ping action works on the virtual device when invoked
through the Cisco NSO CLI, by pinging one of the virtual servers in the
customer or Internet networks (either 20.0.0.20 or 30.0.0.30).
admin@ncs# devices device admin_cloud-second-test_CSR_esc0
live-status exec ping 20.0.0.20
result
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 20.0.0.20, timeout is 2
seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max =
4/12/30 ms
admin_cloud-second-test_CSR_esc0#
admin@ncs#

Step 3 Add your ping action to the cloud.yang service model. Use the
tailf:action statement. The action must have one mandatory input
parameter of the type ipv4-address and one output parameter of the
type string (snippet PING-ACTION-MODEL).
tailf:action ping {
tailf:actionpoint cloud-ping;
input {
leaf ip {
mandatory true;
type inet:ipv4-address;
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–41


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

}
output {
leaf result {
type string;
}
}
}

Step 4 Add a new Python file cloud_actions.py to your cloud service


package python folder. The folder already contains other Python source
files. In the file, import the necessary modules and create a
PingAction class, inheriting from Action (snippet PING-ACTION).

import ncs.maapi
import ncs.maagic
from ncs.dp import Action

class PingAction(Action):
@Action.action
def cb_action(self, uinfo, name, kp, action_input,
action_output):
self.log.info('action name: ', name)
self.log.info('action input.ip: ', action_input.ip)

Step 5 In the annotated action callback cb_action, you will start a new
Maapi session and attach to the current transaction of the user
executing the action. Use the Python high-level Maapi API to start a
new session (snippet ATTACH-MAAPI).
with ncs.maapi.Maapi() as m:
with ncs.maapi.Session(m, uinfo.username,
uinfo.context):
tid = uinfo.actx_thandle
self.log.info(
'Action {} attaching to user {} tid
{}'.format(name, uinfo.username, tid))
t = m.attach(tid, usid=uinfo.usid)

Step 6 After executing the attach method, you will have a new Transaction
object to use as a Maagic back end. Create two Maagic Nodes – one
pointing to the current service instance list entry (use the get_node
Maagic method and kp) and one pointing to the root of the CDB (use
the get_root Maagic method) (snippet MAAGIC-NODES).
service = ncs.maagic.get_node(t, kp)
root = ncs.maagic.get_root(t)

Step 7 Use the root Maagic Node to get a reference to the ping action on
the device that the current service instance is using (snippet MAAGIC-
PING-ACTION).
ping =

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–42


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

root.devices.device[service.device].live_status.ios_stats__e
xec.ping

Step 8 Execute the Maagic action, passing the input parameters from your
cb_action method (snippet EXECUTE-PING).
ping_input = ping.get_input()
ping_input.args = [action_input.ip]
ping_output = ping(ping_input)
action_output.result = ping_output.result

Step 9 Detach the current Maapi session from the ongoing user transaction
(snippet DETACH-MAAPI).
m.detach(tid)

Step 10 You must tell Cisco NSO about the new action callback. Open the
cloud.py file and add an import of the file that you just created at the
top (snippet IMPORT-CLOUD-ACTIONS).
from cloud_actions import PingAction

Step 11 Find the component thread code, located in the Cloud class at the
bottom of the file. Add a new action registration in the existing
setup() method (snippet REGISTER-ACTION).

class Cloud(ncs.application.Application):
def setup(self):
self.log.info('Cloud RUNNING')
self.register_service('cloud-servicepoint',
ServiceCallbacks)
self.register_action('cloud-ping', PingAction)

Step 12 Compile the cloud package with the make command and reload the
packages in Cisco NSO.
Step 13 Invoke the ping action through the Cisco NSO CLI on an existing
service instance. The output should be similar to the one at the
beginning of this task, when you were testing the ping command
directly on the virtual device.
admin@ncs# services cloud second-test ping ip 20.0.0.20
result
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 20.0.0.20, timeout is 2
seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max =
11/18/33 ms
admin_cloud-second-test_CSR_esc0#
admin@ncs#

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–43


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Creating a Simple Cloud Service Bundle

Activity Verification
You have completed this task when you attain these results:
 You have successfully added a new ping action to the existing cloud
service.
 You have successfully tested the new action by executing the action on an
existing instance of the cloud service.

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide 3–44


This document is for training purposes only. All content is subject to change without notice.
Answer Key
This answer key contains the final solutions for each of the labs.

Lab 1
l3mplsvpn.yang
module l3mplsvpn {
namespace "http://com/example/l3mplsvpn";
prefix l3mplsvpn;

import ietf-inet-types { prefix inet; }


import tailf-ncs { prefix ncs; }
import tailf-common { prefix tailf; }

augment /ncs:services {
leaf l3mplsvpn-id-cnt {
description "Provides a unique 32-bit number used as VPN
instance identifier";
tailf:hidden "Counter";
type uint32;
default 1;
}
}

augment /ncs:services {

list l3mplsvpn {
tailf:info "Layer-3 MPLS VPN Service";
key vpn-name;
unique vpn-id;

uses ncs:service-data;
ncs:servicepoint "l3mplsvpn-servicepoint";

leaf vpn-name {
type string;
tailf:info "Service Instance Name";
}

leaf vpn-id {
tailf:info "Layer-3 MPLS VPN Service Instance
identifier";
tailf:hidden "ID";
type uint32 {
range "1..65535" {
error-message "VPN ID is out of range. Should be
between 1 and 65535.";
}
}
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-1


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

leaf link-id-cnt {
description "Provides a unique 32-bit number used as site
identifier";
tailf:hidden "Counter";
default 1;
type uint64 {
range "1..65535";
}
}

leaf customer {
tailf:info "VPN Customer";
type leafref {
path "/ncs:customers/ncs:customer/ncs:id";
}
}

list link {
tailf:info "PE-CE Attachment Point";
key link-name;
unique "link-id";
unique "device interface";
min-elements 1;

leaf link-name {
type string;
tailf:info "Link Name";
}

leaf link-id {
tailf:hidden "ID";
type uint32 {
range "1..65535" {
error-message "Link ID is out of range. Should be
between 1 and 65535.";
}
}
}

leaf device {
tailf:info "PE Router";
mandatory true;
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
must "starts-with(current(),'PE')" {
error-message "Only PE devices can be selected.";
}
}

leaf interface {
tailf:info "Customer Facing Interface";
type string;
mandatory true;

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-2


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

must "count(../../../l3mplsvpn[vpn-name !=
current()/../../vpn-name]/link[device
= current()/../device][interface=current()])
= 0" {
error-message "Interface is already used for another
link.";
}
}

leaf pe-ip {
tailf:info "PE Interface IP Address";
mandatory false;
type inet:ipv4-address {
pattern "172\.([1][6-9]|[2][0-9]|3[0-1])\..*" {
error-message "Invalid IP address. IP address
should be in the 172.16.0.0/12
range.";
}
}
}

leaf ce-ip {
tailf:info "CE Interface IP Address";
when "../routing-protocol='bgp'";
mandatory false;
type inet:ipv4-address {
pattern "172\.([1][6-9]|[2][0-9]|3[0-1])\..*" {
error-message "Invalid IP address. IP address
should be in the 172.16.0.0/12
range.";
}
}
}

leaf rip-net {
tailf:info "IP network for RIP";
when "../routing-protocol='rip'";
mandatory false;
type inet:ipv4-address {
pattern "172\.([1][6-9]|[2][0-9]|3[0-1])\.[0-9]+\.0"
{
error-message "Invalid IP address. IP address
should be in the 172.16.0.0/12
range.";
}
}
}

leaf routing-protocol {
tailf:info "Routing option for the PE-CE link";
type enumeration {
enum bgp;
enum rip;
}
default bgp;

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-3


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

}
}
}
}
}

l3mplsvpn.py
# -*- mode: python; python-indent: 4 -*-
import ncs

import l3mplsvpn_callbacks

# ---------------------------------------------
# COMPONENT THREAD THAT WILL BE STARTED BY NCS.
# ---------------------------------------------
class L3MplsVpn(ncs.application.Application):
def setup(self):
# The application class sets up logging for us. Is is
accessible
# through 'self.log' and is a ncs.log.Log instance.
self.log.info('l3mplsvpn RUNNING')

# Service callbacks require a registration for a 'service


point',
# as specified in the corresponding data model.
#
self.register_service('l3mplsvpn-servicepoint',
l3mplsvpn_callbacks.ServiceCallbacks)

# If we registered any callback(s) above, the Application


class
# took care of creating a daemon (related to the
service/action point).

# When this setup method is finished, all registrations


are
# considered done and the application is 'started'.

def teardown(self):
# When the application is finished (which would happen if
NCS went
# down, packages were reloaded or some error occurred)
this teardown
# method will be called.

self.log.info('l3mplsvpn FINISHED')

def _get_device_type(root, device):


# Return module used by device, to determine device type
modules = root.devices.device[device].module.keys()
return str(modules[0])

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-4


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

13mplsvpn_callbacks.py
# -*- mode: python; python-indent: 4 -*-
import _ncs
from ncs.application import Service
import ncs.template

TYPE_CISCO_IOS = '{tailf-ned-cisco-ios}'
TYPE_CISCO_IOSXR = '{tailf-ned-cisco-ios-xr}'

# ------------------------
# SERVICE CALLBACK EXAMPLE
# ------------------------
class ServiceCallbacks(Service):

# The create() callback is invoked inside NCS FASTMAP and


# must always exist.
@Service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=', service._path,
')')

vpn_id = [x[1] for x in proplist if x[0] == 'vpn-id'][0]

tvars = ncs.template.Variables()
template = ncs.template.Template(service)
tvars.add('VPNID', vpn_id)

for link in service.link:


device_type = _get_device_type(root, link.device)

link_ip = link.pe_ip
peer_ip = link.ce_ip
rip_net = link.rip_net

link_id = int([x[1] for x in proplist if x[0] ==


'link-id-'+link.link_name][0])

# Calculate IP address from unique site ID: 172.x.y.z


pe_ip_o2 = 31 - (link_id * 4) % 4096 # Second
octet
pe_ip_o3 = ((link_id * 4) % 4096) / 64 # Third
octet
pe_ip_o4 = ((link_id * 4) % 4096) % 64 + 1 # Fourth
octet
ce_ip_o4 = pe_ip_o4 + 1 # Fourth
octet for CE side ( = PE + 1 )
if not link_ip:
link_ip = '172.{}.{}.{}'.format(pe_ip_o2,
pe_ip_o3, pe_ip_o4)
if not peer_ip:
peer_ip = '172.{}.{}.{}'.format(pe_ip_o2,
pe_ip_o3, ce_ip_o4)
if not rip_net:
rip_net = '172.{}.0.0'.format(pe_ip_o2)

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-5


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

tvars.add('DEVICE', link.device)
tvars.add('PEIP', link_ip)
tvars.add('CEIP', peer_ip)
tvars.add('INTERFACE', link.interface)
tvars.add('ROUTING-PROTOCOL', link.routing_protocol)
if link.routing_protocol == 'rip':
tvars.add('RIP-NET', rip_net)
else:
tvars.add('RIP-NET', '')

if device_type == TYPE_CISCO_IOS:
self.log.info('Applying IOS template for device
', link.device)
template.apply('l3mplsvpn-ios-template', tvars)
elif device_type == TYPE_CISCO_IOSXR:
self.log.info('Applying IOS-XR template for
device ', link.device)
template.apply('l3mplsvpn-iosxr-template', tvars)
else:
raise Exception('Unknown device type ' +
device_type)

return proplist

@Service.pre_modification
def cb_pre_modification(self, tctx, op, kp, root, proplist):
self.log.info('Service premod(service=', kp, ')')

if op == _ncs.dp.NCS_SERVICE_DELETE:
self.log.info('Delete, ignore')
return proplist

with ncs.maapi.Maapi(self.dd.ip(), self.dd.port(),


self.dd.path()) as m:
trans = m.attach(tctx)
froot = ncs.maagic.get_root(trans)
service = ncs.maagic.get_node(trans, kp)

if op == _ncs.dp.NCS_SERVICE_CREATE:
vpn_id =
froot.ncs__services.l3mplsvpn__l3mplsvpn_id_cnt
proplist.append(('vpn-id', str(vpn_id)))
froot.ncs__services.l3mplsvpn__l3mplsvpn_id_cnt =
vpn_id + 1
self.log.info('Setting vpn_id to ',
froot.ncs__services.l3mplsvpn__l3mplsvpn_id_cnt)

for link in service.link:


link_name = 'link-id-' + link.link_name
if not [x[1] for x in proplist if x[0] ==
link_name]:
proplist.append((link_name,
str(service.link_id_cnt)))

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-6


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

self.log.info('Setting link_id for {} to


{}'.format(link.link_name, service.link_id_cnt))
service.link_id_cnt = service.link_id_cnt + 1

m.detach(tctx)

return proplist

def _get_device_type(root, device):


# Return module used by device, to determine device type
modules = root.devices.device[device].module.keys()
return str(modules[0])

l3mplsvpn-ios-template.xml
<config-template xmlns="http://tail-f.com/ns/config/1.0">
<devices xmlns="http://tail-f.com/ns/ncs">
<device tags="nocreate">
<name>{$DEVICE}</name>
<config>
<vrf xmlns="urn:ios" tags="merge">
<definition>
<name>vpn{$VPNID}</name>
<address-family>
<ipv4 />
</address-family>
<route-target>
<import>
<asn-
ip>1:{$VPNID}</asn-ip>
</import>
<export>
<asn-
ip>1:{$VPNID}</asn-ip>
</export>
</route-target>
<rd>1:{$VPNID}</rd>
</definition>
</vrf>
<router xmlns="urn:ios" tags="merge">
<rip when="{$ROUTING-PROTOCOL='rip'}">
<address-family>
<ipv4>
<vrf>

<name>vpn{$VPNID}</name>
<default-
information>

<originate />
</default-
information>
<network>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-7


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

<ip>{$RIP-NET}</ip>
</network>
</vrf>
</ipv4>
</address-family>
</rip>
<bgp when="{$ROUTING-PROTOCOL='bgp'}">
<as-no>1</as-no>
<address-family>
<with-vrf>
<ipv4>
<unicast-
multicast>unicast</unicast-multicast>
<vrf>

<name>vpn{$VPNID}</name>

<neighbor>

<id>{$CEIP}</id>

<remote-as>65001</remote-as>

</neighbor>

<redistribute>

<connected />

<static />

</redistribute>
</vrf>
</ipv4>
</with-vrf>
</address-family>
</bgp>
</router>
<interface xmlns="urn:ios" tags="nocreate">
<GigabitEthernet>
<name>{$INTERFACE}</name>
<vrf tags="create">

<forwarding>vpn{$VPNID}</forwarding>
</vrf>
<ip tags="merge">
<address>
<primary>

<mask>255.255.255.252</mask>

<address>{$PEIP}</address>
</primary>
</address>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-8


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

</ip>
</GigabitEthernet>
</interface>
</config>
</device>
</devices>
</config-template>

l3mplsvpn-iosxr-template.xml
<config-template xmlns="http://tail-f.com/ns/config/1.0">
<devices xmlns="http://tail-f.com/ns/ncs">
<device tags="nocreate">
<name>{$DEVICE}</name>
<config>
<vrf xmlns="http://tail-f.com/ned/cisco-ios-xr"
tags="merge">
<vrf-list>
<name>vpn{$VPNID}</name>
<address-family>
<ipv4>
<unicast>
<import>
<route-target>
<address-list>
<name>1:{$VPNID}</name>
</address-list>
</route-target>
</import>
<export>
<route-target>
<address-list>
<name>1:{$VPNID}</name>
</address-list>
</route-target>
</export>
</unicast>
</ipv4>
</address-family>
</vrf-list>
</vrf>
<router xmlns="http://tail-f.com/ned/cisco-ios-xr"
tags="merge">
<bgp>
<bgp-no-instance>
<id>1</id>
<vrf>
<name>vpn{$VPNID}</name>
<neighbor>
<id>{$CEIP}</id>
<remote-as>65001</remote-as>
<address-family>
<ipv4>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-9


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

<unicast>
<route-policy>
<direction>in</direction>
<name>pass</name>
</route-policy>
<route-policy>
<direction>out</direction>
<name>pass</name>
</route-policy>
<as-override/>
<default-originate/>
</unicast>
</ipv4>
</address-family>
</neighbor>
<address-family>
<ipv4>
<unicast>
<redistribute>
<connected/>
<static/>
</redistribute>
</unicast>
</ipv4>
</address-family>
<rd>1:{$VPNID}</rd>
</vrf>
</bgp-no-instance>
</bgp>
</router>
<interface xmlns="http://tail-f.com/ned/cisco-ios-xr"
tags="merge">
<GigabitEthernet>
<id>{$INTERFACE}</id>
<ipv4>
<address>
<mask>255.255.255.252</mask>
<ip>{$PEIP}</ip>
</address>
</ipv4>
<vrf>vpn{$VPNID}</vrf>
</GigabitEthernet>
</interface>
<route-policy xmlns="http://tail-f.com/ned/cisco-ios-xr"
tags="merge">
<name>pass</name>
<cmd>
<value>pass</value>
</cmd>
</route-policy>
</config>
</device>
</devices>
</config-template>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-10


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

Lab 2
l2vpn.yang
module l2vpn {
namespace "http://com/example/l2vpn";
prefix l2vpn;

import ietf-inet-types { prefix inet; }


import tailf-ncs { prefix ncs; }
import tailf-common { prefix tailf; }
import tailf-ned-cisco-ios { prefix ios; }
import tailf-ned-cisco-ios-xr { prefix cisco-ios-xr; }
//import junos { prefix junos; }

container id-database {
leaf start {
type uint32;
default 100;
}

leaf stop {
must "current() > ../start";
type uint32;
default 200;
}

leaf-list used-ids {
type uint32;
config false;
tailf:cdb-oper {
tailf:persistent true;
}
}
}

augment /ncs:services {
list l2vpn {
key name;
unique pw-id;

uses ncs:service-data;
ncs:servicepoint l2vpn-servicepoint;

leaf name {
tailf:info "Service Instance Name";
mandatory true;
type string;
}

leaf customer {
tailf:info "Customer Name";
mandatory true;

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-11


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

type leafref {
path "/ncs:customers/ncs:customer/ncs:id";
}
}

leaf pw-id {
tailf:info "Unique Pseudowire ID";
type uint32 {
range "1..4294967295";
}

/* Uncomment for second part of the lab (PW ID allocation


with custom subscriber) */
config false;
tailf:cdb-oper {
tailf:persistent true;
}
}

list link {
tailf:info "Attachment Circuits";
min-elements 2;
max-elements 2;
key device;

leaf device {
tailf:info "PE Router";
mandatory true;
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}

container ios {
when
"deref(../device)/../ncs:module[1]/ncs:name='tailf-ned-cisco-
ios'" {
tailf:dependency "../device";
}
tailf:cli-drop-node-name;

leaf intf-number {
tailf:info "GigabitEthernet Interface ID";
mandatory true;
type leafref {
path
"deref(../../device)/../ncs:config/ios:interface/ios:GigabitEther
net/ios:name";
}
}

leaf loopback-interface {
tailf:info "Loopback Interface ID";
type string;
default "0";

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-12


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

}
}

container iosxr {
when
"deref(../device)/../ncs:module[1]/ncs:name='tailf-ned-cisco-ios-
xr'" {
tailf:dependency "../device";
}
tailf:cli-drop-node-name;

leaf intf-number {
tailf:info "GigabitEthernet Interface ID";
mandatory true;
type leafref {
path "deref(../../device)/../ncs:config/cisco-ios-
xr:interface/cisco-ios-xr:GigabitEthernet/cisco-ios-xr:id";
}
}

leaf loopback-interface {
tailf:info "Loopback Interface ID";
type string;
default "0";
}
}

/* Uncomment for the last (optional) task */


/*
container junos {
when
"deref(../device)/../ncs:module[1]/ncs:name='junos'" {
tailf:dependency "../device";
}
tailf:cli-drop-node-name;

leaf intf-number {
tailf:info "GigabitEthernet Interface ID";
mandatory true;
type leafref {
path
"deref(../../device)/../ncs:config/junos:configuration/junos:inte
rfaces/junos:interface/junos:name";
}
}

leaf loopback-interface {
tailf:info "Loopback Interface ID";
type string;
default "0";
}
}
*/
}
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-13


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

}
}

l2vpn.py
# -*- mode: python; python-indent: 4 -*-
import ncs
from ncs.application import Service
import ncs.template
import ncs.experimental
#import l2vpn_subscriber
import device_helper
import id_allocator

# ------------------------
# SERVICE CALLBACK EXAMPLE
# ------------------------
class ServiceCallbacks(Service):

# The create() callback is invoked inside NCS FASTMAP and


# must always exist.
@Service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=', service._path,
')')

vpn_name = service.name
customer = service.customer

""" Uncomment for task 5


pw_id = None
with ncs.maapi.single_read_trans(tctx.username,
tctx.context, db=ncs.OPERATIONAL) as t:
try:
oper_service = ncs.maagic.get_node(t,
service._path)
pw_id = oper_service.pw_id
except KeyError:
# service instance does not yet exist
pass

if pw_id is None:
self.log.info('pw-id does not exit, waiting for
redeploy')
return proplist
"""

pw_id = None
service_path =
"/services/l2vpn[name='{}']".format(service.name)
self.log.info('Path: ', service_path)
id_allocator.id_request(service, service_path, 'pw-id',
tctx.username, vpn_name)
try:

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-14


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

pw_id = id_allocator.id_read(tctx, root, 'pw-id',


vpn_name)
except id_allocator.ResourceWait:
pass

if pw_id is None:
self.log.info('pw-id does not exit, waiting for
redeploy')
return proplist

links_data = []
for link in service.link:
link_data = {'device': link.device}
device_type = device_helper.get_device_type(root,
link.device)
self.log.info('Normalizing data for device {} of type
{}'
.format(link.device, device_type))
device_type_container = getattr(link,
device_helper.DEVICE_LOOKUP[device_type])

link_data['intf-number'] =
device_type_container.intf_number
link_data['loopback-address'] = \
device_helper.get_loopback_address(root,
link.device,
device_type,

device_type_container.loopback_interface)

links_data.append(link_data)

for index, link in enumerate(links_data):


self.log.info('Configuring device
{}'.format(link['device']))
tvars = ncs.template.Variables()
tvars.add('SERVICE', vpn_name)
tvars.add('CUSTOMER', customer)
tvars.add('PW-ID', pw_id)
tvars.add('DEVICE', link['device'])
tvars.add('INTERFACE-ID', link['intf-number'])
tvars.add('REMOTE-IP', links_data[1-index]['loopback-
address'])

template = ncs.template.Template(service)
template.apply('l2vpn-template', tvars)

# ---------------------------------------------
# COMPONENT THREAD THAT WILL BE STARTED BY NCS.
# ---------------------------------------------
class L2vpn(ncs.application.Application):
def __init__(self, *args, **kwargs):
self.sub = None

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-15


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

super(L2vpn, self).__init__(*args, **kwargs)

def setup(self):
# The application class sets up logging for us. Is is
accessible
# through 'self.log' and is a ncs.log.Log instance.
self.log.info('L2vpn RUNNING')

# Service callbacks require a registration for a 'service


point',
# as specified in the corresponding data model.
#
self.register_service('l2vpn-servicepoint',
ServiceCallbacks)

# If we registered any callback(s) above, the Application


class
# took care of creating a daemon (related to the
service/action point).
# When this setup method is finished, all registrations
are
# considered done and the application is 'started'.

#self.sub =
l2vpn_subscriber.AllocatorSubscriber(app=self)
#self.sub.start()

def teardown(self):
# When the application is finished (which would happen if
NCS went
# down, packages were reloaded or some error occurred)
this teardown
# method will be called.

#self.sub.cleanup()
#self.sub.stop()

self.log.info('L2vpn FINISHED')

l2vpn-template.xml
<config-template xmlns="http://tail-f.com/ns/config/1.0">
<devices xmlns="http://tail-f.com/ns/ncs">
<device tags="nocreate">
<name>{$DEVICE}</name>
<config>
<interface xmlns="urn:ios">
<GigabitEthernet>
<name>{$INTERFACE-ID}</name>
<xconnect tags="merge">
<encapsulation>mpls</encapsulation>
<vcid>{$PW-ID}</vcid>
<address>{$REMOTE-IP}</address>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-16


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

</xconnect>
</GigabitEthernet>
</interface>
<l2vpn xmlns="http://tail-f.com/ned/cisco-ios-xr"
tags="merge">
<xconnect>
<group>
<name>{$CUSTOMER}</name>
<p2p>
<name>{$SERVICE}</name>
<neighbor>
<address>{$REMOTE-IP}</address>
<pw-id>{$PW-ID}</pw-id>
</neighbor>
<interface>
<name>GigabitEthernet{$INTERFACE-ID}</name>
</interface>
</p2p>
</group>
</xconnect>
</l2vpn>
<interface xmlns="http://tail-f.com/ned/cisco-ios-xr">
<GigabitEthernet>
<id>{$INTERFACE-ID}</id>
<l2transport tags="merge">
</l2transport>
</GigabitEthernet>
</interface>
</config>
</device>
</devices>
</config-template>

12vp_subscriber.py
# -*- mode: python; python-indent: 4 -*-

import ncs
import ncs.maapi
import ncs.experimental

import _ncs

import fake_external_allocator

# ------------------------------------------------
# SUBSCRIBER ITERATOR OBJECT
# ------------------------------------------------
class AllocatorSubscriber(ncs.experimental.Subscriber):
"""This subscriber subscribes to changes in the..."""

# custom initializer which gets called from the


# constructor (__int__)

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-17


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

def init(self):
self.service_path = '/ncs:services/l2vpn:l2vpn'
self.register(self.service_path, priority=100)

# Initate your local state


def pre_iterate(self):
self.log.info('AllocatorSubscriber: pre_iterate')
return []

# Iterate over the change set


def iterate(self, keypath, operation, oldval, newval, state):
self.log.debug('iterate: {} {} old:{}
new:{}'.format(operation, keypath, oldval, newval))

if operation == ncs.MOP_CREATED and str(keypath[1:]) ==


self.service_path:
state.append({'operation': 'create', 'path':
str(keypath)})
return ncs.ITER_STOP
elif operation == ncs.MOP_DELETED and str(keypath[1:]) ==
self.service_path:
path = str(keypath) + '/l2vpn:pw-id'
try:
with ncs.maapi.single_read_trans('admin',
'system', db=ncs.OPERATIONAL) as t:
val = t.get_elem(path)
state.append({'operation': 'delete', 'path':
str(keypath), 'value': val})
except Exception as e:
self.log.error('Error in iterate: ', e)
return ncs.ITER_STOP

return ncs.ITER_RECURSE

# This will run in a separate thread to avoid a transaction


deadlock
def post_iterate(self, state):
self.log.info('AllocatorSubscriber: post_iterate,
state=', state)

for request in state:


if request['operation'] == 'create':
allocated_id =
fake_external_allocator.allocate_id()
self.log.info('Allocated pwid ', allocated_id)
path = request['path'] + '/pw-id'

with ncs.maapi.single_write_trans('admin',
'system', db=ncs.OPERATIONAL) as t:
t.set_elem(_ncs.Value(allocated_id,
_ncs.C_UINT32), path)
t.apply()

path = request['path'] + '/reactive-re-


deploy'

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-18


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

self.log.info('Redeploying ', path)


redeploy = ncs.maagic.get_node(t, path)
redeploy()
elif request['operation'] == 'delete':

fake_external_allocator.deallocate_id(request['value'])
self.log.info('Deallocated pwid ',
request['value'])

# determine if post_iterate() should run


def should_post_iterate(self, state):
return state != []

def cleanup(self):
pass

device_helper.py
TYPE_CISCO_IOS = '{tailf-ned-cisco-ios}'
TYPE_CISCO_IOSXR = '{tailf-ned-cisco-ios-xr}'
TYPE_JUNIPER_JUNOS = '{juniper-junos}'

DEVICE_LOOKUP = {
TYPE_CISCO_IOS: 'ios',
TYPE_CISCO_IOSXR: 'iosxr',
TYPE_JUNIPER_JUNOS: 'junos'
}

def get_device_type(root, device):


"""Return the YANG module name used by the device

Arguments:
root -- Maagic CDB root
device -- name of the device
"""

modules = root.devices.device[device].module.keys()
return str(modules[0])

def get_loopback_address(root, device, device_type,


loopback_interface):
"""Return the loopback IP address for the given device and id

Arguments:
root -- Maagic CDB root
device -- name of the device
device_type -- device type (YANG module name)
loopback_interface -- Loopback interface ID
"""

device_config =
root.ncs__devices.ncs__device[device].ncs__config
address = None
if device_type == TYPE_CISCO_IOS:

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-19


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

loopback =
device_config.ios__interface.ios__Loopback[loopback_interface]
address = loopback.ip.address.primary.address
elif device_type == TYPE_CISCO_IOSXR:
loopback =
device_config.cisco_ios_xr__interface.Loopback[loopback_interface
]
address = loopback.ipv4.address.ip
elif device_type == TYPE_JUNIPER_JUNOS:
loopback =
device_config.junos__configuration.interfaces.interface[loopback_
interface]
address = loopback.unit['0'].family.inet.address[0].name
else:
raise Exception('Unknown device type ' + device_type)

return address

id_allocator.py
import ncs.template
import ncs.maagic

class ResourceException(Exception):
def __init__(self, value):
super(ResourceException, self).__init__()
self.value = value
def __str__(self):
return repr(self.value)

class ResourceError(ResourceException):
pass
class ResourceWait(ResourceException):
pass

def id_request(root, service_path, pool_name, username,


allocation_id):
"""Create an ID allocation request.

Arguments:
root -- maagic node referencing the CDB root
service_path -- XPath to service instance (not keypath!)
pool_name -- name of pool to request from
username -- username to use when redeploying the requesting
service
allocation_id -- unique allocation id
"""

template = ncs.template.Template(root)
tvars = ncs.template.Variables()
tvars.add('POOL', pool_name)
tvars.add('ALLOCATIONID', allocation_id)
tvars.add('USERNAME', username)

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-20


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

tvars.add('SERVICE', service_path)
template.apply('id-allocation', tvars)

def id_read(tctx, root, pool_name, allocation_id):


"""Read result of an ID allocation request.

Arguments:
tctx -- transaction context
root -- maagic root
pool_name -- name of pool the request was created in
id -- unique allocation id
"""

pool = _get_id_pool(root, pool_name)

if pool is None:
raise ResourceError('Pool {} does not
exist'.format(pool_name))

allocation = _get_id_allocation(pool, allocation_id)


if allocation is None:
raise ResourceError('Allocation {} does not
exist'.format(allocation_id))

with ncs.maapi.single_read_trans(tctx.username, tctx.context,


db=ncs.OPERATIONAL) as oper_th:
allocation =
_get_id_allocation(_get_id_pool(ncs.maagic.get_root(oper_th),
pool_name), allocation_id)

if allocation is None:
raise ResourceWait('Not ready')

if allocation.response.id:
return allocation.response.id
elif allocation.response.error:
raise ResourceError(allocation.response.error)

def _get_id_pool(root, pool_name):


try:
return root.ralloc__resource_pools.id_pool[pool_name]
except KeyError:
pass

def _get_id_allocation(pool, allocation_id):


try:
return pool.allocation[allocation_id]
except KeyError:
pass

fake_external_allocator.py
#!/usr/bin/env python

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-21


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

import ncs.maapi
import ncs.maagic

def allocate_id():
with ncs.maapi.single_write_trans('admin', 'system') as t:
root = ncs.maagic.get_root(t)
db = root.l2vpn__id_database
try:
l = db.used_ids
if l is None: l = list()
allocated_id = [n for n in range(db.start, db.stop)
if n not in l][0]
l.append(allocated_id)
db.used_ids = l
t.apply()
return allocated_id
except IndexError:
raise Exception('Exhausted all IDs!')

def deallocate_id(i):
with ncs.maapi.single_write_trans('admin', 'system') as t:
root = ncs.maagic.get_root(t)
db = root.l2vpn__id_database
l = db.used_ids
if l is None: return
try:
l.remove(i)
db.used_ids = l
t.apply()
except ValueError:
pass

def main():
print 'Testing Fake External Allocator'
allocated_id = allocate_id()
print 'Allocated ID:', allocated_id

deallocate_id(allocated_id)
print 'Successfully deallocated ID!'

if __name__ == '__main__':
main()

Lab 3
cloud.yang
module cloud {
namespace "http://com/example/cloud";
prefix cloud;

import ietf-inet-types { prefix inet; }

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-22


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

import tailf-common { prefix tailf; }


import tailf-ncs { prefix ncs; }
import vrouter { prefix vrouter; }
import vfirewall { prefix vfirewall; }

augment /ncs:services {

list cloud {
description "This is the Cloud service";

key name;
leaf name {
type string;
}

uses ncs:service-data;
ncs:servicepoint cloud-servicepoint;

leaf device {
config false;
tailf:cdb-oper {
tailf:persistent true;
}
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}

/* Uncomment for first part of the lab


leaf device {
mandatory true;
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}
*/

leaf tenant {
mandatory true;
type string;
}

leaf customer-network {
mandatory true;
type string;
}

leaf internet-network {
mandatory true;
type string;
}

container vrouter {
presence "vrouter";

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-23


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

uses vrouter:vrouter;
}

container vfirewall {
presence "vfirewall";

uses vfirewall:vfirewall;
}

tailf:action ping {
tailf:actionpoint cloud-ping;
input {
leaf ip {
mandatory true;
type inet:ipv4-address;
}
}
output {
leaf result {
type string;
}
}
}
}
}
}

vrouter.yang
module vrouter {
namespace "http://com/example/vrouter";
prefix vrouter;

import ietf-inet-types { prefix inet; }


import tailf-common { prefix tailf; }
import tailf-ncs { prefix ncs; }

grouping vrouter {
list routes {
key "network mask";
min-elements 1;

leaf network {
type inet:ipv4-address;
}

leaf mask {
type inet:ipv4-address;
}

leaf gateway {
mandatory true;
type inet:ipv4-address;

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-24


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

}
}
}

augment /ncs:services {

list vrouter {
description "This is a vRouter service";

key name;
leaf name {
type string;
}

uses ncs:service-data;
ncs:servicepoint vrouter-servicepoint;

leaf device {
mandatory true;
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}

uses vrouter;
}
}
}

vfirewall.yang
module vfirewall {
namespace "http://com/example/vfirewall";
prefix vfirewall;

import ietf-inet-types { prefix inet; }


import tailf-common { prefix tailf; }
import tailf-ncs { prefix ncs; }

grouping vfirewall {
list access-list-rules {
ordered-by user;
key name;

leaf name {
type string;
}

leaf action {
mandatory true;
type enumeration {
enum permit;
enum deny;
}

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-25


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

leaf protocol {
default ip;
type enumeration {
enum ip;
enum icmp;
enum tcp;
enum udp;
}
}
leaf src-ip {
mandatory true;
type inet:ipv4-address;
}
leaf src-mask {
mandatory true;
type inet:ipv4-address;
}
leaf src-port {
when "../protocol = 'tcp' or ../protocol = 'udp'";
default any;
type union {
type uint16;
type enumeration {
enum any;
}
}
}
leaf dest-ip {
mandatory true;
type inet:ipv4-address;
}
leaf dest-mask {
mandatory true;
type inet:ipv4-address;
}
leaf dest-port {
when "../protocol = 'tcp' or ../protocol = 'udp'";
default any;
type union {
type uint16;
type enumeration {
enum any;
}
}
}
}
}

augment /ncs:services {

list vfirewall {

uses ncs:service-data;

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-26


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

ncs:servicepoint vfirewall-servicepoint;

description "vFirewall service";

key name;
leaf name {
type string;
}

leaf device {
mandatory true;
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}

uses vfirewall;
}
}
}

cloud.py
# -*- mode: python; python-indent: 4 -*-
import re
import ncs
from ncs.application import Service, PlanComponent
import ncs.template
from resource_management import ipaddress_allocator, vm_manager
from cloud_actions import PingAction

# ------------------------
# SERVICE CALLBACK EXAMPLE
# ------------------------
class ServiceCallbacks(Service):

# The create() callback is invoked inside NCS FASTMAP and


# must always exist.
@Service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=', service._path,
')')
service_path =
"/services/cloud[name='{}']".format(service.name)

plan_data = {'CSR':{'states':['mgmt-address-allocated',
'vnf-created'],
'reached_states': []}}

mgmt_ip = self._allocate_mgmt_address(tctx,
service,
service_path,
root,

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-27


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

service.name)
if not mgmt_ip:
self.log.info('Waiting for redeploy')
self._write_plan_data(service, plan_data)
return proplist

plan_data['CSR']['reached_states'].append('mgmt-address-
allocated')

deployment_name = 'cloud-' + service.name


device = self._create_vnf(tctx,
service,
service_path,
service.tenant,
deployment_name,
mgmt_ip)
if not device:
self.log.info('Waiting for CSR')
self._write_plan_data(service, plan_data)
return proplist

self._set_operational_device_leaf(tctx, service, device)


plan_data['CSR']['reached_states'].append('vnf-created')

self._set_hostname(root, device)

if service.vfirewall.exists():
self.log.info('vFirewall config exists, will create
vFirewall instance')
template = ncs.template.Template(service.vfirewall)
tvars = ncs.template.Variables()
tvars.add('NAME', service.name)
tvars.add('DEVICE', device)
template.apply('vfirewall-service-template', tvars)

if service.vrouter.exists():
self.log.info('vRouter config exists, will create
vRouter instance')
template = ncs.template.Template(service.vrouter)
tvars = ncs.template.Variables()
tvars.add('NAME', service.name)
tvars.add('DEVICE', device)
template.apply('vrouter-service-template', tvars)

self._write_plan_data(service, plan_data)

def _write_plan_data(self, service, plan_data):


self_plan = PlanComponent(service, 'self', 'ncs:self')
self_plan.append_state('ncs:init')
self_plan.append_state('ncs:ready')
self_plan.set_reached('ncs:init')

finished = True
for component, states in plan_data.iteritems():

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-28


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

vnf_plan = PlanComponent(service, component,


'cloud:vnf')
vnf_plan.append_state('ncs:init')
vnf_plan.set_reached('ncs:init')
[vnf_plan.append_state(x) for x in states['states']]
[vnf_plan.set_reached(x) for x in
states['reached_states']]
vnf_plan.append_state('ncs:ready')
if len(states['states']) ==
len(states['reached_states']):
vnf_plan.set_reached('ncs:ready')
else:
finished = False

if finished:
self_plan.set_reached('ncs:ready')

def _allocate_mgmt_address(self, tctx, service, service_path,


root, allocation_id):
try:
ipaddress_allocator.subnet_request(service,
service_path, 'mgmt', tctx.username, 32, allocation_id)
result = ipaddress_allocator.subnet_read(tctx, root,
'mgmt', allocation_id)
self.log.info('Got allocated ID: {}'.format(result))
return re.sub('/32$', '', result)
except ipaddress_allocator.ResourceWait:
pass

def _create_vnf(self, tctx, service, service_path, tenant,


deployment_name, mgmt_ip):
tvars = ncs.template.Variables()

vm_name = tenant + "_" + deployment_name + "_" + "CSR"


tvars.add('NAME', vm_name)
tvars.add('ESC', 'esc0')
tvars.add('TENANT', tenant)
tvars.add('DEPNAME', deployment_name)
tvars.add('VM_GROUP', 'CSR')
tvars.add('VM_TYPE', 'csr')
tvars.add('IMAGE_ID', 'csr1000v-
universalk9.03.16.01a.S.155-3.S1a-ext.qcow2')
tvars.add('FLAVOR_ID', 'cisco-csr')
tvars.add('CUSTOMER-NETWORK', service.customer_network)
tvars.add('INTERNET-NETWORK', service.internet_network)
tvars.add('MGMT-IP', mgmt_ip)
template = ncs.template.Template(service)
template.apply('vm-manager-template', tvars)

vm_manager.register_start_request(service, vm_name,
service_path)
device_name =
'{tenant}_{deployment_name}_{vm_group}_{esc}'\
.format(tenant=tenant,
deployment_name=deployment_name,

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-29


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

vm_group='CSR',
esc='esc0')

if vm_manager.device_ready(tctx, device_name):
return device_name

def _set_operational_device_leaf(self, tctx, service,


device_name):
with ncs.maapi.single_write_trans(tctx.username,
tctx.context, db=ncs.OPERATIONAL) as oper_th:
oper_service = ncs.maagic.get_node(oper_th,
service._path)
oper_service.device = device_name
oper_th.apply()

def _set_hostname(self, root, device_name):


# IOS XE does not like hostname longer that 16 chars
root.devices.device[device_name].config.ios__hostname =
device_name[:16]

# ---------------------------------------------
# COMPONENT THREAD THAT WILL BE STARTED BY NCS.
# ---------------------------------------------
class Cloud(ncs.application.Application):
def setup(self):
self.log.info('Cloud RUNNING')
self.register_service('cloud-servicepoint',
ServiceCallbacks)
self.register_action('cloud-ping', PingAction)

def teardown(self):
self.log.info('Cloud FINISHED')

cloud_actions.py
import ncs.maapi
import ncs.maagic
from ncs.dp import Action

class PingAction(Action):
@Action.action
def cb_action(self, uinfo, name, kp, action_input,
action_output):
self.log.info('action name: ', name)
self.log.info('action input.ip: ', action_input.ip)

with ncs.maapi.Maapi() as m:
with ncs.maapi.Session(m, uinfo.username,
uinfo.context):
tid = uinfo.actx_thandle
self.log.info(
'Action {} attaching to user {} tid
{}'.format(name,

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-30


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

uinfo.username,

tid))
t = m.attach(tid, usid=uinfo.usid)

service = ncs.maagic.get_node(t, kp)


root = ncs.maagic.get_root(t)
ping =
root.devices.device[service.device].live_status.ios_stats__exec.p
ing

ping_input = ping.get_input()
ping_input.args = [action_input.ip]
ping_output = ping(ping_input)
action_output.result = ping_output.result

m.detach(tid)

vm-manager-template.xml
<config xmlns="http://tail-f.com/ns/config/1.0">
<vm-manager xmlns="http://cisco.com/yang/nso/vm-manager"
tags="merge">
<start>
<name>{$NAME}</name>
<deployment-name>{$DEPNAME}</deployment-name>
<vm-device>{$ESC}</vm-device>
<tenant>{$TENANT}</tenant>
<vm-group>{$VM_GROUP}</vm-group>
<vm-type>{$VM_TYPE}</vm-type>
<flavor-id>{$FLAVOR_ID}</flavor-id>
<image-id>{$IMAGE_ID}</image-id>
<day0-url>http://198.18.134.4:8081/csr_config.txt</day0-
url>
<interface>
<id>0</id>
<name>mgmt</name>
<ip>{$MGMT-IP}</ip>
</interface>
<interface>
<id>1</id>
<name>{$CUSTOMER-NETWORK}</name>
</interface>
<interface>
<id>2</id>
<name>{$INTERNET-NETWORK}</name>
</interface>
<scaling-min>1</scaling-min>
<scaling-max>1</scaling-max>
</start>
</vm-manager>
</config>

vrouter-service-template.xml

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-31


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

<config xmlns="http://tail-f.com/ns/config/1.0">
<services xmlns="http://tail-f.com/ns/ncs">
<vrouter xmlns="http://com/example/vrouter">
<name>{$NAME}</name>
<device>{$DEVICE}</device>
<routes foreach="{/routes}">
<network>{network}</network>
<mask>{mask}</mask>
<gateway>{gateway}</gateway>
</routes>
</vrouter>
</services>
</config>

vfirewall-service-template.xml
<config xmlns="http://tail-f.com/ns/config/1.0">
<services xmlns="http://tail-f.com/ns/ncs">
<vfirewall xmlns="http://com/example/vfirewall">
<name>{$NAME}</name>
<device>{$DEVICE}</device>
<access-list-rules foreach="{/access-list-rules}">
<name>{name}</name>
<action>{action}</action>
<protocol>{protocol}</protocol>
<src-ip>{src-ip}</src-ip>
<src-mask>{src-mask}</src-mask>
<src-port>{src-port}</src-port>
<dest-ip>{dest-ip}</dest-ip>
<dest-mask>{dest-mask}</dest-mask>
<dest-port>{dest-port}</dest-port>
</access-list-rules>
</vfirewall>
</services>
</config>

vrouter-template.xml
<config-template xmlns="http://tail-f.com/ns/config/1.0"
servicepoint="vrouter-servicepoint">
<devices xmlns="http://tail-f.com/ns/ncs">
<device tags="nocreate">
<name>{/device}</name>
<config>
<ip xmlns="urn:ios">
<route tags="merge">
<ip-route-forwarding-list
foreach="{routes}">
<prefix>{network}</prefix>
<mask>{mask}</mask>
<forwarding-
address>{gateway}</forwarding-address>
</ip-route-forwarding-list>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-32


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

</route>
</ip>
</config>
</device>
</devices>
</config-template>

vfirewall.py
# -*- mode: python; python-indent: 4 -*-
import socket
import struct

import ncs
from ncs.application import Service
import ncs.template

class ServiceCallbacks(Service):

# The create() callback is invoked inside NCS FASTMAP and


# must always exist.
@Service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=', service._path,
')')

device = service.device

# Some hardcoded parameters


acl_name = 'FIREWALL'
acl_interface = '3'
acl_direction = 'in'

for rule in service.access_list_rules:


template = ncs.template.Template(service)
tvars = ncs.template.Variables()

tvars.add('DEVICE', device)
tvars.add('ACCESS-LIST-NAME', acl_name)
tvars.add('INTERFACE-ID', acl_interface)
tvars.add('ACCESS-LIST-DIRECTION', acl_direction)

tvars.add('ACCESS-LIST-RULE',
self._build_acl_rule(rule))
template.apply('vfirewall-template', tvars)

def _build_acl_rule(self, rule):


src_port = self._stringify_port(rule.src_port)
dest_port = self._stringify_port(rule.dest_port)

acl_entry = '{action} {protocol} {src_ip} {src_mask}


{src_port} ' \
'{dest_ip} {dest_mask} {dest_port}' \
.format(action=rule.action.string,

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-33


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

protocol=rule.protocol,
src_ip=rule.src_ip,

src_mask=self._convert_to_wildcard(rule.src_mask),
src_port=src_port,
dest_ip=rule.dest_ip,

dest_mask=self._convert_to_wildcard(rule.dest_mask),
dest_port=dest_port)

self.log.info('Generated ACL entry:


{}'.format(acl_entry))
return acl_entry

def _stringify_port(self, port):


if isinstance(port, int):
return 'eq ' + str(port)
else:
return ''

def _convert_to_wildcard(self, mask):


# Could use python3 ipaddress module in future
mask_bytes = struct.unpack('BBBB',
socket.inet_aton(mask))
inverted_bytes = struct.pack('BBBB', *[~x & 0xFF for x in
mask_bytes])
return socket.inet_ntoa(inverted_bytes)

# ---------------------------------------------
# COMPONENT THREAD THAT WILL BE STARTED BY NCS.
# ---------------------------------------------
class Vfirewall(ncs.application.Application):
def setup(self):
# The application class sets up logging for us. Is is
accessible
# through 'self.log' and is a ncs.log.Log instance.
self.log.info('Vfirewall RUNNING')

# Service callbacks require a registration for a 'service


point',
# as specified in the corresponding data model.
#
self.register_service('vfirewall-servicepoint',
ServiceCallbacks)

# If we registered any callback(s) above, the Application


class
# took care of creating a daemon (related to the
service/action point).

# When this setup method is finished, all registrations


are
# considered done and the application is 'started'.

def teardown(self):

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-34


This document is for training purposes only. All content is subject to change without notice.
Cisco Learning Services (www.cisco.com/go/cls) Answer Key

# When the application is finished (which would happen if


NCS went
# down, packages were reloaded or some error occurred)
this teardown
# method will be called.

self.log.info('Vfirewall FINISHED')

vfirewall-template.xml
<config xmlns="http://tail-f.com/ns/config/1.0">
<devices xmlns="http://tail-f.com/ns/ncs">
<device tags="nocreate">
<name>{$DEVICE}</name>
<config>
<interface xmlns="urn:ios">
<GigabitEthernet>
<name>{$INTERFACE-ID}</name>
<ip tags="merge">
<access-group>
<direction>{$ACCESS-
LIST-DIRECTION}</direction>
<access-
list>{$ACCESS-LIST-NAME}</access-list>
</access-group>
</ip>
</GigabitEthernet>
</interface>
<ip xmlns="urn:ios">
<access-list tags="merge">
<extended>
<ext-named-acl>
<name>{$ACCESS-LIST-
NAME}</name>
<ext-access-list-
rule>
<rule>{$ACCESS-
LIST-RULE}</rule>
</ext-access-list-
rule>
</ext-named-acl>
</extended>
</access-list>
</ip>
</config>
</device>
</devices>
</config>

© 2017 Cisco Systems, Inc. NSO30020 Lab Guide A-35


This document is for training purposes only. All content is subject to change without notice.

Potrebbero piacerti anche