PANTHEON.tech Solutions: ONAP Integration

[What Is] ONAP | Open Network Automation Platform

ONAP (Open Network Automation Platform) is quite a trend in the contemporary SDN world. It is a broad project, consisting of a variety of sub-projects (or components),  which together form a network function orchestration and automation platform. Several enterprises are active in ONAP and its growth is accelerating rapidly. PANTHEON.tech is a proud contributor as well.

What is ONAP?

The platform itself emerged from the AT&T ECOMP (Enhanced Control, Orchestration, Management & Policy) and Open-O (Open Orchestrator) initiatives. ONAP is an open-source software platform, that offers a robust, real-time, policy-driven orchestration and automation framework, for physical and virtual network functions. It exists above the infrastructure layer, which automates the network.

ONAP enables end-users to connect services through the infrastructure. It allows network scaling and VNF/CNF implementations in a fully automated manner. Among other benefits, like:

  • Bring agile deployment & best practices to the telecom world
  • Add & deploy new features on a whim
  • Improve network efficiency & sink costs

Its goal is to enable operators and developers, networks, IT, and the cloud to quickly automate new technologies and support full lifecycle management. It is capable of managing (build, plan, orchestrate) Virtual Network Functions (VNF), as well as Software-Defined Networks (SDN).

ONAP’s high-level architecture involves numerous software subsystems (components). PANTHEON.tech is involved in multiple ONAP projects, but mostly around controllers (like SDN-C). For a detailed view, visit the official wiki page for the architecture of ONAP.

SDN-C

SDN-C is one of the components of ONAP – the SDN controller. It is basically OpenDaylight, with additional Directed Graph Execution capabilities. In terms of architecture, ONAP SDN-C is composed of multiple Docker containers.

Directed Graph Creator runs one of these containers. It’s a user-friendly web UI, that can be used to create directed graphs. Another container runs the Admin Portal. The next one runs the relational database, which is the focal point of the implementation of SDN-C and used for each container. Lastly, the SDN-C container, that runs the controller itself.

This component is of particular interest to us because it has all the rationale behind the execution of graphs that are directed. We have previously shown, how lighty.io can integrate well with SDN-C and drastically improve performance.

According to the latest 5G use-case paper for ONAP, SDN-C has managed to implement “radio-related optimizations through the SDN-R sub-project and support for the A1 interface”.

CDS: Controller Design Studio

As the official documentation puts it:

CDS Designer UI is a framework to automate the resolution of resources for instantiation and any config provisioning operation, such as day0, day1, or day2 configuration.

CDS has both design-time & run-time activities. During design time, the designer can define what actions are required for a given service, along with anything comprising the action. The design produces a CBA Package. Its content is driven by a catalog of reusable data dictionaries and components, delivering a reusable and simplified self-service experience.

CDS enables users to adapt resources in a way, where no direct code-changes are needed. The Design Studio gives users, not only developers, the option to customize the system, to meet the customer’s demands. The two main components of CDS are the frontend (GUI) and backend (run-time). It is possible to run CDS in Kubernetes or an IDE of your choice.

One interesting use-case shows the creation of a WordPress CNF via CDS.

SO: Service Orchestration

The primary role of SO is the automation of the provisioning operations of end-to-end service instances. In favor of overall end-to-end service instantiation, processes, and maintenance, SO is accountable for the instantiation and setup of VNFs.

To accomplish its purpose, Service Orchestration performs well-defined processes – usually triggered by receiving service requests, created by other ONAP components, or by Order Lifecycle Management in the BSS layer.

The orchestration procedure is either manually developed or received from ONAP’s Service Design and Development (SDC) portion, where all service designs are created for consumption and exposed/distributed.

The latest achievement of the Service Orchestrator is the implementation of new workflows such as:

  • CSMF – Communication Service Management Function
  • NSMF – Network Slice Management Function
  • NSSMF – Network Slice Sub-Net Management Function

DMaaP: Data Movement as a Platform

The DMaaP component is a data movement service, which transports and processes data from a selected source to the desired target. It is capable of transferring data and messages between ONAP components, data filtering/compression/routing, as well as message routing and batch/event-based processing.

DCAE: Data Collection Analytics & Events

The Data Collection Analytics & Events component does exactly what’s in its name – gather performance, usage & configuration data from the managed environment. The component guards events in a sense – if something significant occurs or an anomaly is detected, DCAE takes appropriate actions.

The component collects and stores data that is necessary for analysis while providing a framework for the development of needed analytics.

DCAE: Collectors and other microservices required to support the telemetry collection for 5G network optimization; this includes the O1 interface from O-RAN.

A&AI: Active & Available Inventory

The Active & Available Inventory functionality offers real-time views of relationships with the products and services operated by them. It gives real-time insights into the managed products and services, as well as their connections.

A&AI is a list of properties that are active, available, and allocated. It establishes a multi-dimensional relationship between the programs and infrastructure under administration. It provides interfaces for dynamic network topology requests, both canned and ad-hoc network topology queries.

Recently AAI gained schema support for 5G service design and slicing models.

Is ONAP worth it?

Yes, it is. Since you have come up to this conclusion, then you might feel that ONAP is the right fit for your needs. It is an enormous project with around 20 components.

If you feel overwhelmed, don’t worry and leave it to the experts – contact PANTHEON.tech today for your ONAP integration needs!

[What Is] O-RAN | Open Radio Access Network

It is a long-term goal of several enterprises, including PANTHEON.tech, to embrace an open(-source) ecosystem for network development and connectivity.

An open approach to software development opens doors to all the talents around the globe, to contribute to projects that will shape the future of networking. One such project is the Open Radio Access Network or O-RAN for short.

Next In Line: O-RAN

Originally launched as OpenRAN, the project was started in 2017 by the Telecom Infra Project. The goal was to build a vendor-neutral, hardware & software-defined technology for 2-3-4G RAN solutions.

Then, the O-RAN Alliance was founded to increase community engagement, as well as to motivate operators to be included in this development. The alliance has made it a point, to create a standardization – meaning a description, of how this concept should function in reality.

O-RAN Architecture

O-RAN is part of the massive evolution from 4G networks, into the 5G generation. In 5G, due to higher bandwidths, more antenna and the use of multiple-input multiple-output (MIMO) technology, even more data needs to go back and forth.

O-RAN Architecture Explained

We can observe the formation of two solutions: the high-level split (HLS) and the low-level split (LLS). With so much of the processing shifting to the edge, the high-level split is a two-box solution. The F1 interface lies between the DU+RU and links to the centralized device. Alternatively, further processing is shifted to the middle by LLS and the antenna is held at the edge.

Three separate units are deployed with O-RAN:

  • O-RU: Radio Unit
  • O-DU: Distributed Unit
  • O-CU: Centralized Unit

At the edge sits the O-RU. In the center, the O-DU sits and performs some of the processing. Both HLS and LLS are included in O-RAN. They standardize the interfaces. For CUs, DUs, or RUs, operators may use different vendors. With one working group concentrating on the F1 interface and another on the front-haul, the components are much more interoperable and the protocols more clearly defined.

O-RAN: Service Management and Orchestration Framework

What’s more, O-RAN selected SDN-R as the project’s SDN controller. PANTHEON.tech is part of the SDN-R community.

What is a RAN?

A radio access network implements radio access technology, which makes it able for user devices (anything able to receive this signal) to receive a connection to the core network, above the specific RAN.

RAN Diagram

A visual representation of core networks, radio access networks, and user devices.

The types of radio access networks include GSM, EDGE, and LTE standards, named GRAN, GERAN, E-UTRAN in that order.

The core network provides a path for information exchanging between subnetworks or different LANs. Imagine the core network as the backbone of an enterprise’s entire network.

The technology behind RANs is called RAT (radio access technology) and represents the principal technology behind radio-based communication. RATs include known network standards like GSM or LTE, or Bluetooth and WiFi.

Linux Foundation Networking Presents: O-RAN Software Community

In the first half of 2019, The Linux Foundation, in collaboration with the O-RAN Alliance, created the O-RAN Software Community, where members can contribute their knowledge & know-how to the O-RAN project.

Currently, the goal is to create a common O-RAN specification, that all RAN vendors would potentially adopt. This would mean a common interface, independent of the radio unit type.

This move certainly makes sense, since, at its core, O-RAN stands for openness – open-source, nonproprietary radio access networks. As the technical charter of the project puts it:

The mission of the Project is to develop open-source software enabling modular open, intelligent, efficient, and agile radio access networks, aligned with the architecture specified by O-RAN Alliance.

The further goal of creating a software community centered around this project is to include projects such as OPNFV, ONAP, and others, to create a complete package for future, open networking.

PANTHEON.tech in 2020

PANTHEON.tech 2020: A Look Back

Join us in reminiscing and reminding you, what PANTHEON.tech has managed to create, participate in, or inform about in 2020.

Project: CDNF.io

In the first quarter of the year, we have made our latest project, CDNF.io, accessible to the public. Cloud-native functions were long overdue in our portfolio and let me tell you – there are lots of them, ready to be deployed anytime. Check out the list of available CNFs or ask us about them.

We have prepared a series of videos, centered around our CNFs, which you can conveniently view here:

Perhaps you like to read more than hear someone explain things to you? We wrote a few posts on:

Integration Scenarios

Apart from our in-house solutions, we have worked on demonstrating several scenarios with common technologies behind them: ServiceNow® & Cisco’s Network Services Orchestrator.

In terms of ServiceNow®, our posts centered around:

Cisco’s NSO got a nearly all-inclusive treatment, thanks to Samuel Kontriš, with a defacto NSO Guide on:

This includes two videos about the Network Service Orchestrator:

Open-Source Software Releases

We have made several projects available on our GitHub, which we regularly maintain and update. What stole the spotlight was the lighty.io NETCONF Device Simulator & Monitoring Tool, which you can download here.

PANTHEON.tech has also been active in adding new features to existing open-source projects, such as:

lighty.io, our open-source passion project, celebrated its 13th release, which also included a separate post highlighting improvements and changes. 

Thoughts, Opinions & Information

Since we did not want to exclude people who might not be that knowledgable about what we do, we have created a few series on technologies and concepts PANTHEON.tech is engaged in, such as:

We try to listen closely to what Robert Varga, the top-single contributor to the OpenDaylight source-code, has to say about OpenDaylight. That allowed us to publish opinion/informative pieces like:

Step into a new decade

We would like to thank everybody who does their part in working and contributing to projects in PANTHEON.tech, but open-source projects as well. 2020 was challenging, to say the least, but pulling together, makes us stronger – together.

Happy holidays and new years to our colleagues, partners, and readers – from PANTHEON.tech.

Karaf in OpenDaylight

[Thoughts] On Karaf & Its Future

These thoughts were originally sent on the public karaf-dev mailing list, where Robert Varga wrote a compelling opinion on what the future holds for Karaf and where its currently is headed. The text below was slightly edited from the original.


With my various OpenDaylight hats on, let me summarize our project-wide view, with a history going back to the project that was officially announced (early 2013).

From the get-go, our architectural requirement for OpenDaylight was OSGi compatibility. This means every single production (not maven-plugin obviously) artifact has to be a proper bundle.

This highly-technical and implementation-specific requirement was set down because of two things:

  1. What OSGi brings to MANIFEST.MF in terms of headers and intended wiring, incl. Private-Package
  2. Typical OSGi implementation (we inherited Equinox and are still using it) uses multiple class loaders and utterly breaks on split packages

This serves as an architectural requirement that translates to an unbreakable design requirement of how the code must be structured.

We started up with a home-brew OSGi container. We quickly replaced it for Karaf 3.0.x (6?), massively enjoying it being properly integrated, with shell, management, and all that. Also, feature:install.

At the end of the day, though, OpenDaylight is a toolkit of a bunch of components that you throw together and they work.

Our initial thinking was far removed from the current world of containers when operations go. The deployment was envisioned more like an NMS with a dedicated admin team (to paint a picture), providing a flexible platform.

The world has changed a lot, and the focus nowadays is on containers providing a single, hard-wired use-case.

We now provide out-of-the-box use-case wiring. using both dynamic Karaf and Guice (at least for one use case). We have an external project which shows the same can be done with pure Java, Spring Boot, and Quarkus.

We now also require Java 11, hence we have JPMS – and it can fulfill our architectural requirement just as well as OSGi. Thanks to OSGi, we have zero split packages.

We do not expect to ditch Karaf anytime soon, but rather leverage static-framework for a light-weight OSGi environment, as that is clearly the best option for us short-to-medium term, and definitely something we will continue supporting for the foreseeable future.

The shift to nimble single-purpose wirings is not going away and hence we will be expanding there anyway.

To achieve that, we will not be looking for a framework-of-frameworks, we will do that through native integration ourselves.

If Karaf can do the same, i.e. have its general-purpose pieces available as components, easily thrown together with @Singletons or @Components, with multiple frameworks, as well as nicely jlinkable – now that would be something. 

[OpenDaylight] Binding-Independent & Binding-Aware

From the get-go, the MD-SAL architecture was split into two distinct worlds: Binding-Independent (BI, DOM) and Binding-Aware (BA, Binding).

This split comes from two competing requirements:

  • Type-safety provided by Java, for application developers who interact with specific data models
  • Infrastructure services that are independent of data models.

Type-safety is supported by interfaces and classes generated from YANG models. It generally feels like any code, where you deal with DTOs.

Infrastructure services are supported by an object, model similar to XML DOM, where you deal with hierarchical “document” trees. All you have to go by, are QNames.

For obvious reasons, most developers interacting with OpenDaylight have never touched the Binding Independent world, even though it underpins pretty much every single feature available on the platform.

The old OpenDaylight SAL architecture looked like this:

MD-SAL BA/BI

A very dated picture of how the system is organized.

It is obvious that the two worlds need to seamlessly interoperate.

For example, RPCs invoked by one world, must be able to be serviced by the other. Since RPCs are the equivalent of a method call, this process needs to be as fast as possible, too.

That leads to a design, where each world has its own broker and the two brokers are connected. Invocations within the world would be handled by that world’s broker, foregoing any translation.

The Binding-Aware layer sits on top of the Binding Independent one. But it is not a one-to-one mapping.

This comes from the fact, that the Binding-Independent layer is centered around what makes sense in YANG, whereas the Binding-Aware layer is centered around what makes sense in Java, including various trade-offs and restrictions coming from them.

Binding-Aware: what makes sense in Java.

Binding-Independent: what makes sense in YANG.

Remote Procedure Calls

For RPCs, this meant that there were two independent routing tables, with repeated exports being done from each of them.

The idea of an RPC router was generalized in the (now long-forgotten) RpcRouter interface. Within a single node, the Binding & DOM routers would be interconnected.

For clustered scenarios, a connector would be used to connect the DOM routers across all nodes. So an inter-node Binding-Aware RPC request from node A to node B would go through:

BA-ABI-AConnector-AConnector-BBI-B → BA-B (and back again)

Both the BI and connector speak the same language – hence they can communicate without data translation.

The design was simple and effective but has not survived the test of time. Most notably, the transition to dynamic loading of models in the Karaf container.

BA/BI Debacle: Solution

Model loading impacts data translation services needed to cross the BA/BI barrier, leading to situations where an RPC implementation was available in the BA world, but could not yet be exported to the BI world. This, in turn, leads to RPC routing loops, and in the case of data-store services – missing data & deadlocks.

To solve these issues, we have decided to remove the BA/BI split from the implementation and turn the Binding-Aware world into an overlay on top of the Binding-Independent world.

This means, that all infrastructure services always go through BI, and the Binding RPC Broker was gradually taken behind the barn, there was a muffled sound in 2015.

Ultimate OpenDaylight Guide Part 1: Documentation & Testing

Ultimate OpenDaylight Guide | Part 1: Documentation & Testing

by Samuel Kontriš, Robert Varga, Filip Čúzy | Leave us your feedback on this post!


Welcome to Part 1 of the PANTHEON.tech Ultimate Guide to OpenDaylight! We will start off lightly with some tips & tricks regarding the tricky documentation, as well as some testing & building tips to speed up development!


Documentation

1. Website, Docs & Wiki

The differences between these three sources can be staggering. But no worries, we have got you covered!

2. Dependencies between projects & distributions

3. Contributing to OpenDaylight

4. Useful Mailing Lists

There are tens (up to hundreds) of mailing lists you can join, so you are up-to-date with all the important information – even dev talks, thoughts, and discussions!

Testing & Building

1. Maven “Quick” Profile

There’s a “Quick” maven profile in most OpenDaylight projects. This profile skips a lot of tests and checks, which are unnecessary to run with each build.

This way, the build is much faster:

mvn clean install -Pq

2. GitHub x OpenDaylight

The OpenDaylight code is mirrored on GitHub! Since more people are familiar with the GitHub environment, rather than Gerrit, make sure to check out the official GitHub repo of ODL!

3. Gerrit

Working with Gerrit can be challenging and new for newcomers. Here is a great guide on the differences between the two.


You can contact us at https://pantheon.tech/

Explore our Pantheon GitHub.

Watch our YouTube Channel.

Road to Cloud-Native Network Functions

We have come a long way to enjoy all the benefits that cloud-native network functions bring us – lowered costs, agility, scalability & resilience. This post will break down the road to CNFs – from PNF to VNF, to CNF.

What are PNFs (physical network functions)?

Back in the ’00s, network functions were utilized in the form of physical, hardware boxes, where each box served the purpose of a specific network function. Imagine routers, firewalls, load balancers, or switches as PNFs, utilized in data centers for decades before another technology replaced them. PNF boxes were difficult to operate, install, and manage.

Just as it was unimaginable to have a personal computer 20 years ago, we were unable to imagine virtualized network functions. Thanks to cheaper, off-the-shelf hardware and expansion of cloud services, enterprises were able to afford to move some network parts from PNFs to generic, commodity hardware.

What are VNFs (virtual network functions)?

The approach of virtualization enabled us to share hardware resources between multiple tenants while keeping the isolation of environments in place. The next logical step was the move from the physical, to the virtual world.

A VNF is a virtualized network function, that runs on top of a hardware networking infrastructure. Individual functions of a network may be implemented or combined together, in order to create a complete package of a networking-communication service. A virtual network function can be part of an SDN architecture or used as a singular entity within a network.

Today’s standardization of VNFs would not be possible without ETSIs Open-Source Mano architecture, or the TOSCA standard, which can serve as lifecycle management. These are, for example, used in the open-source platform ONAP (Open Network Automation Platform).

What are CNFs (cloud-native network functions)?

Cloud-native network functions are software implementations of functions, which are traditionally performed by PNFs – and they need to conform to cloud-native principles. They can be packaged within a container image, are always ready to be deployed & orchestrated, chained together to perform a series of complex network functions.

Why should I use CNFs?

Microservices and the overall benefits of adapting cloud-native principles, come with several benefits, which show a natural evolution of network functions in the 2020s. Imagine the benefits of:

  • Reduced Costs
  • Immediate Deployment
  • Easy Control
  • Agility, Scalability & Resilience

Our CDNF.io project delivers on all of these promises. Get up-to-date with your network functions and contact us today, to get a quote.

[NSO Guide] Cisco NSO® with lighty.io

by Samuel Kontriš | Leave us your feedback on this post!

This is a continuation of our guide on the Cisco Network Service Orchestrator. In our previous article, we have shown you how to install and run Cisco NSO with three virtual devices. We believe you had time to test it out and get to know this great tool.

Now, we will show you how to use the Cisco NSO with our SDN Framework – lighty.io. You can read more about lighty.io here, and even download lighty-core from our GitHub here.

Prerequisites

This tutorial was tested on Ubuntu 18.04 LTS. In this tutorial we are going to use:

Get and start the lighty.io application

To get the lighty.io 11.2.0 release, clone its GitHub repository and build it with Maven.

git clone https://github.com/PANTHEONtech/lighty-core.git
cd lighty-core
git checkout 11.2.0
mvn clean install

After the build, locate the lighty-community-restconf-netconf-app artifact and unzip its distribution from the target directory:

cd lighty-examples/lighty-community-restconf-netconf-app/target
unzip lighty-community-restconf-netconf-app-11.2.0-bin.zip
cd lighty-community-restconf-netconf-app-11.2.0

Now we can start lighty.io application by running its .jar file:

java -jar lighty-community-restconf-netconf-app-11.2.0.jar

After a few seconds we should see in the logs message that everything was started successfully:

INFO [main] (Main.java:97) - lighty.io and RESTCONF-NETCONF started in 7326.731ms

The lighty.io application should now be up and running. The default RESTCONF port is 8888.

Connect Cisco NSO to the lighty.io application

To connect Cisco NSO to the lighty.io application via NETCONF protocol we must add it as a node to the configuration datastore using RESTCONF. To do this, call a PUT request on the URI:

http://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=nso

with the payload:

{
    "netconf-topology:node":[ { 
        "node-id":"nso",
        "host":"127.0.0.1",
        "port":2022,
        "username":"admin",
        "password":"admin",
        "tcp-only":false,
        "keepalive-delay":0,
        "netconf-node-configuration:schemaless":false
    } ]
}

The parameter nodeId specifies the name, under which we will address Cisco NSO in the lighty.io application. Parameters host and port specify, where the Cisco NSO instance is running. The default username and password for Cisco NSO is admin/admin. In case you would like to change node-id be sure to change it in the URI too.

To check if Cisco NSO was connected successfully, call a GET request on the URI:

http://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=nso

The output should look similar to this:

{
    "network-topology:node": [
        {
            "node-id": "nso",
            "netconf-node-topology:unavailable-capabilities": {...},
            "netconf-node-topology:schemaless": false,
            "netconf-node-topology:available-capabilities": {...},
            "netconf-node-topology:password": "admin",
            "netconf-node-topology:username": "admin",
            "netconf-node-topology:tcp-only": false,
            "netconf-node-topology:port": 2022,
            "netconf-node-topology:host": "127.0.0.1",
            "netconf-node-topology:keepalive-delay": 0,
            "netconf-node-topology:connection-status": "connected"
        }
    ]
}

If Cisco NSO was connected successfully, the value of the connection-status should be connected.

Activate Cisco NSO service using lighty.io

Activation of the Cisco NSO service is similar to connecting Cisco NSO to lighty.io. We are going to activate the ACL service we created in the previous tutorial, by calling PUT REST request on URI:

http://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=nso/yang-ext:mount/services/acl-service:acl-service=myAcl

with payload:

{
    "acl-service:acl-service": [
        {
            "ACL_Name": "myAcl",
            "ACL_Direction": "in",
            "devices": [
                {
                    "device_name": "c0",
                    "interfaces": [
                        {
                            "interface_type": "GigabitEthernet",
                            "interface_number": "1/1"
                        }
                    ]
                }
            ]
        }
    ]
}

This payload is modeled in a YANG model we created together with the ACL service in our previous tutorial. Feel free to change the values of the ACL parameters (first, check what types they are in the ACL service YANG model) and if you are changing ACL_Name, don’t forget to change it in the URI too.

Unfortunately, in the time of writing this tutorial, there is a bug in the OpenDaylight NETCONF (NETCONF-568) with parsing the output from this call. It prevents lighty.io from sending a response to the RESTCONF request we sent and we need to manually stop waiting for this response in Postman (or another REST client you are using).

Now, our service should be activated! To check activated services in Cisco NSO, call a GET request on the URI:

http://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=nso/yang-ext:mount/services/acl-service:acl-service=myAcl

In response, you should see the service we just activated. It should look similar to this:

"acl-service:acl-service": [
    {
        "ACL_Name": "myAcl",
        "ACL_Direction": "in",
        "devices": [
            {
                "device_name": "c0",
                "interfaces": [
                    {
                        "interface_type": "GigabitEthernet",
                        "interface_number": "1/1"
                    }
                ]
            }
        ],
        "directly-modified": {
            "devices": [
                "c0"
            ]
        },
        "device-list": [
            "c0"
        ],
        "modified": {
            "devices": [
                "c0"
            ]
        }
    }
]

To check if the device was configured, log into Cisco NSO CLI and execute a show command:

ncs_cli -u admin
show configuration devices device c0 config ios:interface

You should see an output, similar to this:

admin@ncs> show configuration devices device c0 config ios:interface
FastEthernet 1/0;
GigabitEthernet 1/1 {
    ip {
        access-group {
            access-list myAcl;
            direction   in;
        }
    }
}

A Postman collection containing all REST requests we executed in this tutorial can be found here or downloaded directly from here.

Today we showed you how to connect Cisco NSO with lighty.io. Up next, our tutorial will depict how to connect ONAP SDN-C with Cisco NSO.

Leave us your feedback on this post!

10/03/2020 Update: Added the video demonstration, enjoy!


You can contact us at https://pantheon.tech/

Explore our Pantheon GitHub.

Watch our YouTube Channel.

[Free Tool] NETCONF Device Simulator & Monitoring

by Martin Bugáň Leave us your feedback on this post!

You can simulate hundreds or thousands of NETCONF devices within your development or CI/CD. We are of course talking about our lighty NETCONF Simulator, which is now available on GitHub! This tool is free & open-source, while based on OpenDaylight’s state-of-art NETCONF implementation.

We have recently finished the implementation of get-schema RPC from NETCONF Monitoring, which is based on the RFC 6022 by the IETF and brings users a missing monitoring possibility for NETCONF devices.

Download NETCONF Device Simulator (from GitHub)

 

Let us know, what NETCONF device you would like to simulate!

What is a get-schema

Part of NETCONF Monitoring features is get-schema RPC, which allows the controller to download schemas from the NETCONF device to the controller, so they don’t have to be added manually.

In the points, one after another, the process of device connection looks like this (when controller and device are started):

1. Connection between NETCONF device and controller is established
2. When established and hello message capabilities exchanged, the controller requests a list of available models from the NETCONF device
3. When NETCONF device supports this feature, it sends its models to the controller
4. Controller then processes those models and builts schema context

In a more technical perspective, here is the process of connecting devices:

1. SSH connection from the controller to the NETCONF device is established
2. NETCONF device sends a hello message with its capabilities
3. Controller sends hello message with its capabilities
4. Controller requests (gets) a list of available schemas (models) from the NETCONF device datastore (ietf-netconf-monitoring:netconf-state/schemas)
5. NETCONF device sends a list of available schemas to the controller
6. controller goes through this list, download each model via get-schema RPC, and stores them in the cache/schema directory
7. Schema context is built in the controller from models in the cache/schema directory

How does the feature work in an enabled device?

In the device, there is a monitoring flag that can be set up with EnabledNetconfMonitoring(boolean) method. The feature is enabled by default. If the flag is enabled, when the device is built and then started, the device’s operational datastore is populated with schemas from the device’s schemaContext.

In our device, we use NetconfDevice implementation which is built with NetconfDeviceBuilder pattern. This feature is by default enabled and can be disabled by calling with NetconfMonitoringEnabled(false) on the NetconfDeviceBuilder, which sets a flag that netconf-monitoring will be enabled.

When the build() command is called on device builder, if that flag is set, the netconf-monitoring model is added to the device and is created NetconfDeviceImpl instance with a monitoring flag from the builder. Then, when the device is started, prepareSchemasForNetconfMonitoring is called if monitoring is enabled and the datastore is populated with schemas, which are then stored in the netconf-state/schemas path.

It is done via write transaction, where each module and submodule in the device’s schema context is converted to a schema and written into a map with schema key (if the map doesn’t already contain a schema with a given key) When the device is then connected to the controller, get-schema RPC will ask for each of these schemas in netconf-state/schemas path and download them to the cache/schema directory.

What is the purpose of the get-schema?

It helps to automate the device connection process. When a new device is connected, there is no need to manually find and add all models that the device supports in its capabilities, to the controller, but those are downloaded from the device by the controller.

[Example 1] NETCONF Monitoring schemas on our Toaster simulator device

To get a list of all schemas, it is needed to send a get request with a specified netconf-state/schemas path.

Get request for netconf-state/schemas:

<rpc message-id="nss1" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
            <get>
                <filter type="subtree">
                    <netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
                        <schemas/>
                    </netconf-state>
                </filter>
            </get>
        </rpc>
        ]]>]]>

[Example 2] netconf-state/schemas path in datastore, after get request:

This is an example of a reply with schemas stored in the data store (albeit a little shortened). Reply for a get netconf-state/schemas request:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
      <rpc-reply message-id="nss1" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
          <data>
              <netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
                  <schemas>
                      <schema>
                          <identifier>toaster</identifier>
                          <version>2009-11-20</version>
                          <format>yang</format>
                          <namespace>http://netconfcentral.org/ns/toaster</namespace>
                          <location>NETCONF</location>
                      </schema>
                      ... all schemas here
                  </schemas>
              </netconf-state>
          </data>
      </rpc-reply>

[Example 3] get-schema RPC

To get a particular schema with its content in YANG format, the following RPC is sent – an example of getting toaster schema, with revision version 2009-11-20. XML RPC request:

<rpc message-id="gs1" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
    <get-schema xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
        <identifier>toaster</identifier>
        <version>2009-11-20</version>
        <format>YANG</format>
    </get-schema>
</rpc>
]]>]]>

In reply, there is a YANG module schema of the requested toaster schema (again, shortened). XML get-schema RPC reply:

 

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="gs1">
     <data xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
         module toaster {

             yang-version 1;

             namespace
             "http://netconfcentral.org/ns/toaster";

             prefix toast;

             organization "Netconf Central";

             contact
             "Andy Bierman <andy@netconfcentral.org>;";

             description
             "YANG version of the TOASTER-MIB.";

             revision "2009-11-20" {
             description
                 "Toaster module in progress.";
             }

             ... contents of Toaster YANG model
             
         }  // module toaster
     </data>
 </rpc-reply>
PANTHEON.tech Guide for Cisco NSO

[NSO Guide] Cisco Network Services Orchestrator

by Samuel Kontriš | Leave us your feedback on this post!

A network can get messy. That is why many service providers require a Network Orchestrator, to fill the gap between managing hundreds of devices & corresponding services like SNMP, NETCONF, REST and others. This is where Cisco’s Network Services Orchestrator comes into play and translates service orders to various network devices in your network.

The second part of our NSO Guide focuses on connecting the NSO with our SDN framework, lighty.io!

What is Cisco NSO?

An NSO serves as a translator. It breaks up high-level service layers, from management & resource layers – connecting various network functions, which may run in a virtualized or hardware environment. It defines how these network functions interact with other infrastructures and technologies within the network.

The third part of our NSO Guide focuses on Cisco NSO x ONAP SDN-C!

We have introduced Ansible & AWX for automation in the past. Since we also enjoy innovation, we decided to create this guide on installing Cisco NSO, and it’s usage with lighty.io & ONAP (SDN-C).

Contact us for a custom solution!

What an NSO connects

NSO Datasheet by Cisco

Installing the Network Service Orchestrator

Get & install the Cisco NSO

The installation package can be downloaded from the official Cisco developer website. This guide contains steps on how to install the Cisco NSO. We will use the NSO 5.1.0.1 version in this tutorial. This tutorial was tested on Ubuntu 18.04 LTS.

Don’t forget to set NCS_DIR variable and source ncsrc file!

export NCS_DIR=<path_to_NSO_directory>
source $NCS_DIR/ncsrc
Create a Cisco NSO project & run simulated devices

At first, create a directory where the Cisco NSO instance will be started. We will use a nso-run folder in our home directory.

mkdir ~/nso-run
cd ~/nso-run

We will create and start a network with three simulated cisco-ios-cli-3 devices with IDs c0, c1, and c2.

ncs-netsim create-network $NCS_DIR/packages/neds/cisco-ios-cli-3.0 3 c
ncs-netsim start
ncs-setup --netsim-dir ./netsim --dest .
ncs
Connect to the CLI with the command:
ncs_cli -u admin

Connect and sync-from simulated devices in CLI:

request devices connect
request devices sync-from

In the output, you should see connect-result and sync-result from all three devices.

To leave CLI, press CTRL+D.

Create Cisco NSO Service

Go to the packages directory and use ncs-make-package command:

cd packages
ncs-make-package --service-skeleton template acl-service --augment /ncs:services

This will create the directory acl-service with a structure containing templates and default YANG models. Templates are used for applying configurations to devices. With the YANG file, we can model how our service can be activated and what parameters it uses.

Now, open the template XML file acl-service/templates/acl-service-template.xml and replace its content with:

<config-template xmlns="http://tail-f.com/ns/config/1.0" servicepoint="acl-service"> 
   <devices xmlns="http://tail-f.com/ns/ncs">
     <device foreach="{/devices}">
            <name>{device_name}</name>
            <config>
               <interface xmlns="urn:ios" foreach="{interfaces}" >
                  <FastEthernet when="{interface_type='FastEthernet'}">
                     <name>{interface_number}</name>
                     <ip>
                        <access-group tags="merge">
                           <direction>{/ACL_Direction}</direction>
                           <access-list>{/ACL_Name}</access-list>
                        </access-group>
                     </ip>
                  </FastEthernet>
                  <GigabitEthernet when="{interface_type='GigabitEthernet'}">
                     <name>{interface_number}</name>
                     <ip>
                        <access-group tags="merge">
                           <direction>{/ACL_Direction}</direction>
                           <access-list>{/ACL_Name}</access-list>
                        </access-group>
                     </ip>
                  </GigabitEthernet>
 
                  <TenGigabitEthernet when="{interface_type='TenGigabitEthernet'}">
                     <name>{interface_number}</name>
                     <ip>
                        <access-group tags="merge">
                           <direction>{/ACL_Direction}</direction>
                           <access-list>{/ACL_Name}</access-list>
                        </access-group>
                    </ip>
                  </TenGigabitEthernet>
 
              </interface>
            </config>
        </device>
    </devices>
</config-template>

This template will be used for configuring selected devices. It will add access-group with specified interface_type, interface_number, ACL_Name and ACL_Direction variables to their configuration.

The values of the mentioned variables will be set when we will activate this service. These variables are modeled in the YANG file, which we are going to update now.

Replace the content of the acl-service/src/yang/acl-service.yang file with:

module acl-service {
  namespace "http://com/example/aclservice";
  prefix acl-service;
 
  import ietf-inet-types {
    prefix inet;
  }
  import tailf-ncs {
    prefix ncs;
  }
 
  augment /ncs:services {
  list acl-service {
    key ACL_Name;
  
      uses ncs:service-data;
      ncs:servicepoint "acl-service";
 
    leaf ACL_Name {
      type string;
    }
  
    leaf ACL_Direction {
      type enumeration{
        enum "in";
        enum "out";
      }
    }
  
    list devices {
      key device_name;
  
      leaf device_name {
        type leafref {
          path "/ncs:devices/ncs:device/ncs:name";
        }
      }
      list interfaces {
        key "interface_type interface_number";
  
        leaf interface_type {
          type enumeration{
            enum "FastEthernet";
            enum "GigabitEthernet";
            enum "TenGigEthernet";
          }
        }
  
        leaf interface_number {
          type string;
        }
      }
    }
   }
  }
}

This YANG file model defines, what input/output parameters for the service (and devices) should be configured.

After changing the YANG file, call the make command in the src folder of your package:

cd ~/nso-run/packages/acl-service/src
make

You should see an output similar to this:

samuel@samuel-VirtualBox:~/nso-run/packages/acl-service/src$ make
mkdir -p ../load-dir
/home/samuel/nso-5.1/bin/ncsc `ls acl-service-ann.yang > /dev/null 2>&1 && echo "-a acl-service-ann.yang"` \
-c -o ../load-dir/acl-service.fxs yang/acl-service.yang

And now log into the Cisco NSO CLI and reload the packages:

ncs_cli -C -u admin
packages reload

The output should look similar to this:

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.
>>> System upgrade has completed successfully.
reload-result {
    package acl-service
    result true
}
reload-result {
    package cisco-ios-cli-3.0
    result true
}

Now a Cisco NSO instance with three simulated devices should be up and running!

Turn off and clean Cisco NSO

Later when you will want to stop and clean what you started, call these commands in your project directory:

cd ~/nso-run
ncs-netsim stop
ncs --stop
ncs-netsim reset
ncs-setup --reset
ncs-netsim delete-network

Now you can continue to our next tutorial about using the Cisco NSO with lighty.io or with the ONAP (SDNC).

Leave us your feedback on this post!

9/22/2020 Update: We added our video-guide to this article, enjoy!


You can contact us at https://pantheon.tech/

Explore our Pantheon GitHub.

Watch our YouTube Channel.

Imperative & Declarative Programming

[What Is] Declarative vs. Imperative Approach

A DevOps paradigm, programmatic approach, or Kubernetes management. The decision between a declarative or imperative approach is not really a choice – which we will explain in this post.
The main difference between the declarative and imperative approach is:
  • Declarative: You will say what you want, but not how
  • Imperative: You describe how to do something

Declarative Approach

Users will mainly use the declarative approach when describing how services should start, for example: “I want 3 instances of this service to run simultaneously”.

In the declarative approach, a YAML file containing the wished configuration will be read and applied towards the declarative statement. A controller will then know about the YAML file and apply it where needed. Afterwards, the K8s scheduler will start the services, where it has the capacity to do so.

Kubernetes, or K8s for short, lets you decide between what approach you choose. When using the imperative approach, you will explain to Kubernetes in detail, how to deploy something. An imperative way includes the commands create, run, get & delete – basically any verb-based command.

Will I ever manage imperatively?

Yes, you will. Even when using declarative management, there is always an operator, which translates the intent to a sequence of orders and operations which he will do. Or there might be several operators who cooperate or split the responsibility for parts of the system.

Although declarative management is recommended in production environments, imperative management can serve as a faster introduction to managing your deployments, with more control over each step you would like to introduce.

Each approach has its pro’s and con’s, where the choice ultimately depends on your deployment and how you want to manage it.

While software-defined networking aims for automation, once your network is fully automated, enterprises should consider IBN (Intent-Based Networking) the next big step.

Intent-Based Networking (IBN)

Intent-Based Networking is an idea introduced by Cisco, which makes use of artificial intelligence, as well as machine learning to automate various administrative tasks in a network. This would be telling the network, in a declarative way, what you want to achieve, relieving you of the burden of exactly describing what a network should do.

For example, we can configure our CNFs in a declarative way, where we state the intent – how we want the CNF to function, but we do not care how the configuration of the CNF will be applied to, for example, VPP.

For this purpose, VPP-Agent will send the commands in the correct sequence (with additional help from KVscheduler), so that the configuration will come as close as possible to the initial intent.

SDN vs. NFV

[What Is] SDN & NFV

by Filip Čúzy | Leave us your feedback on this post!

For newcomers to our blog – welcome to a series on explanations from the world of PANTHEON.tech software development. Today, we will be looking at what software-defined networking is – what it stands for, it’s past, present, future – and more.

What is SDN – Software Defined Networking?

Networks can exponentially scale and require around the clock troubleshooting, in case something goes wrong – which always can. Software-Defined Networking is a concept of decluttering enterprises of physical network devices and replacing them with software. The goal is to improve the traditional network management and ease the entire process by removing pricey, easily obsolete hardware and replace it with their virtualized counterparts.

The core component is the control plane, which encompasses one (or several) controllers, like OpenDaylight. This makes centralization of the network a breeze and provides an overview of its entirety. The main benefits of utilizing SDN are:

  • Centralization
  • Open Standards
  • Scheduling

Most network admins can relate to the feeling when you have to manage multiple network devices separately, with different ones requiring proprietary software and making your network a decentralized mess. Utilizing SDN enables you to make use of a network controller and centralize the management, security, and other aspects of your network in one place.

Network topologies enable full control of the network flow. Bandwidth can be managed to go where it needs, but it does not end there – network resources, in general, can be secured, managed, and optimized, in order to accommodate current needs. Scheduling or programmability is what differs software-defined networking from a traditional network approach.

Open standards let you know, that you do not have to rely on one hardware provider, with vendor-specific protocols and devices. Projects, such as OpenDaylight, which has been around since 2013, with contributions from major companies like Orange, RedHat, but with leading contributions from PANTHEON.tech. Being an open-source project, you can rely on the community of expert technicians on perfecting the solution with each commit or pull request.

You are also free to modify OpenDaylight yourself, but it gets easier with features from lighty.io, commercial support, or training.

The idea of a software-defined network supposedly started at Stanford University, where researchers played with the idea of virtualizing the network. The idea was to virtualize the network by making the control plane and data plane two separate entities, independent of each other.

What is NFV – Network Function Virtualization?

On the other hand, NFV or Network Function Virtualization aims to replace hardware, which serves a specific purpose, with virtual network functions (Virtual Customer Premise Equipment – vCPE). Imagine getting rid of most proprietary hardware, the difficulty of upgrading each part, and making them more accessible, scalable, and centralized.

SDN & NFV go therefore hand-in-hand in most of the aspects covered, but mainly in the goal of virtualizing most parts of the network equipment or functions.

As for the future, PANTHEON.tech’s mission is to bring enterprises closer to a complete SDN & NFV coverage, with training, support, and custom network software that will make the transition easier. Contact us today – the future of networking awaits.


You can contact us here.

Explore our PANTHEON.tech GitHub.

Watch our YouTube Channel.

Firewall Orchestration by PANTHEON.tech

Cloud-Native Firewall Orchestration w/ ServiceNow®

by Slavomír Mazúr | Leave us your feedback on this post!

PANTHEON.tech s.r.o., its products or services, are not affiliated with ServiceNow®, neither is this post an advertisement of ServiceNow® or its products.

ServiceNow® is a cloud-based platform, that enables enterprise organizations to automate business processes across the enterprise. We have previously shown, how to use ServiceNow® & OpenDaylight to automate your network.

We will demonstrate the possibility of using ServiceNow®, to interact with a firewall device. More precisely, we will manage Access Controls Lists (ACLs), which work on a set of rules that define how to forward or block packets in network traffic.

User Administration

The Now® platform offers, among other things, user administration, which allows us to work with users, assign them to groups, as well as assigning both to roles, based on their privileges. In this solution/demonstration, two different groups of users, with corresponding roles are used.

The first group of users are requestors, which may represent a basic end-user, employees, or customers of an enterprise organization. This user can create new rule requests by submitting a simple form. Without any knowledge of networking, the user can briefly describe his request in the description field.

This request will then be handled by the network admin. At the same time, users can monitor their requests and their status:

The custom table used in the request process is inherited from the Task table, which is one of the core tables provided with the base system. It provides a series of fields, which can be used in the process of request-items management and provide us access to approval logic.

Approval Strategy

Network admins form the second group of users. They receive requests from end-user and decide, if they will fulfill a request, or reject it.

If they decide to fulfill a request, they have an available, extended view of the previous form, which offers more specific fields and simply fills the necessary data. This data represents the ACL rule information, that will be later applied. There are several types of rules (IP, TCP, UDP, ICMP, MAC), and different properties (form fields) must be filled for each of these types.

NOTE: It is possible to add another group of users, which can for example fill details of the rule. This group will create another layer in the entire process, network admin then may focus only on requests approval or rejection.

Network admin has an existing set of rules available, which are stored in tables, according to their type. Existing rules can be accessed from the Application navigator and viewed inside of the created rule request, which the admin is currently reviewing. Data in tables are updated on regular intervals, as well as after a new rule is added.

Workflow Overview

The network admin can decide to approve or reject the request. Once the request is approved, a flow of actions will be triggered. Everything after approval will be done automatically. A list of existing rules is GET from VPP-Agent, using the REST API call. Based on the type of ACL rule, the corresponding action is performed.

Each action consists of two steps. First, the payload is created by inserting new rules into a list of existing rules (if ACL already exists) or creating a new Access Control List (ACL). In the second step, a payload from the previous step is sent back to VPP-agent, using the REST API. At the end of this action flow, tables that contain data describing existing rules are updated.

Managing existing rules

In addition to the approval process, the network admin can also update existing rules, or create new rules. The network admin fills the data into a simple form. After submitting the form, a request is sent directly to the device, without the need of the approval process. Meanwhile, the rule is applied.

MID server

ServiceNow® applications need to communicate with external systems due to data transfer. For this purpose, the MID server is used, which runs as a Windows service or UNIX daemon. In our case, we need to get a list of existing rules from VPP-Agent or send a request to VPP-Agent, when we want to create or update rule. The advantage of a MID server is, that communications are initiated inside the enterprise’s firewall and therefore do not require any special firewall rules or VPNs.


You can contact us at https://pantheon.tech/

Explore our PANTHEON.tech GitHub.

Watch our YouTube Channel.

A PANTHEON.tech Guide on ONAP SDN-C & Cisco NSO

[NSO Guide] Cisco NSO with SDN-C (ONAP)

by Samuel Kontriš | Leave us your feedback on this post!

Welcome to the third and final part of our guide on Cisco’s Network Service Orchestrator. In previous parts, we managed to install and run the NSO on Ubuntu & connected it with lighty.io

Prerequisites

This tutorial was tested on Ubuntu 18.04 LTS. In this tutorial, we are going to use:

Get and start SDN-C

We will download and start SDN-C with only necessary components using Docker. All ONAP Docker images will be downloaded directly from docker-hub.

Create a file called docker-compose.yml with the following content:

version: '2.1'
 
networks:
  default:
    driver: bridge
    driver_opts:
      com.docker.network.driver.mtu: 1500
 
 
services:
  db:
    image: mysql/mysql-server:5.6
    container_name: sdnc_db_container
    ports:
      - "3306"
    environment:
      - MYSQL_ROOT_PASSWORD=openECOMP1.0
      - MYSQL_ROOT_HOST=%
    logging:
      driver:   "json-file"
      options:
        max-size: "30m"
        max-file: "5"
 
  ansible:
    image: onap/sdnc-ansible-server-image:1.7.7
    depends_on :
      - db
    container_name: sdnc_ansible_container
    entrypoint: ["/opt/onap/ccsdk/startAnsibleServer.sh"]
    ports:
      - "8000"
    links:
      - db:dbhost
      - db:sdnctldb01
      - db:sdnctldb02
    environment:
      - MYSQL_ROOT_PASSWORD=openECOMP1.0
    logging:
      driver:   "json-file"
      options:
        max-size: "30m"
        max-file: "5"
 
  sdnc:
    image: onap/sdnc-image:1.7.7
    depends_on :
      - db
    container_name: sdnc_controller_container
    entrypoint: ["/opt/onap/sdnc/bin/startODL.sh"]
    ports:
      - "8282:8181"
    links:
      - db:dbhost
      - db:sdnctldb01
      - db:sdnctldb02
      - ansible:ansiblehost
    environment:
      - MYSQL_ROOT_PASSWORD=openECOMP1.0
      - SDNC_CONFIG_DIR=/opt/onap/sdnc/data/properties
    dns:
      - ${DNS_IP_ADDR-10.0.100.1}
    logging:
      driver:   "json-file"
      options:
        max-size: "30m"
        max-file: "5"
    extra_hosts:
        aaf.osaaf.org: 10.12.6.214
 
  dgbuilder:
    image: onap/ccsdk-dgbuilder-image:0.7.0
    depends_on:
      - db
      - sdnc
    container_name:  sdnc_dgbuilder_container
    entrypoint:
       - "/bin/bash"
       - "-c"
       - "cd /opt/onap/ccsdk/dgbuilder/ && ./start.sh sdnc1.0 && wait"
    ports:
      - "3000:3100"
    links:
      - db:dbhost
      - db:sdnctldb01
      - db:sdnctldb02
      - sdnc:sdnhost
    environment:
      - MYSQL_ROOT_PASSWORD=openECOMP1.0
      - SDNC_CONFIG_DIR=/opt/onap/ccsdk/data/properties
    logging:
      driver:   "json-file"
      options:
        max-size: "30m"
        max-file: "5"

 

This docker-compose file is based on this one from the official sdnc/oam Gerrit repository. The most important images are dgbuilder (which will start a webserver, where directed graphs can be created) and sdnc (the SDN-Controller itself).

To download and start images specified in the docker-compose file call this command:

docker-compose up

Be patient, it may take a while.

In the end, when everything is up & running, we should see a log stating that Karaf was started successfully. It should look similar to this:

sdnc_controller_container | Karaf started in 0s. Bundle stats: 12 active, 12 total

Directed Graph builder should be accessible through this address (port is specified in the docker-compose file):

https://localhost:3000

Default login for dgbuilder is:

username: dguser
password: test123

Upload and activate Directed Graphs

Steps how to upload DG from clipboard:

  1. On the upper right side of the webpage click on the menu button
  2. In the menu click on the “Import…” button
  3. Select “Clipboard…” option
  4. Paste json representation of the graph to the text field
  5. Click “Ok”
  6. Place graph on the sheet

Uploading a Directed Graph

Steps to activate DG:

  1. Click on the small square at the left side of the beginning of the graph (DGSTART node)
  2. Click on the “Upload XML” button
  3. Click on the “ViewDGList” button
  4. Click on the “Activate” button in the “Activate/Deactivate” column of the table
  5. Click on the “Activate” button

In these files are exported, parametrized Directed Graphs to connect your Cisco NSO instance via NETCONF protocol. You can get information about connected the Cisco NSO instance from the operational datastore. To activate ACL service (that we created in this tutorial). We will use these in later steps, so you can upload and activate them in your SDN-C instance.

You can download the corresponding JSON files here:

Connect Cisco NSO to SDN-C using DG

In the previous tutorial, we started Cisco NSO with three simulated devices. Now, we are going to connect a running Cisco NSO instance to SDN-C, using the directed graphs we just imported and activated.

But first, we need to obtain the address of Cisco NSO which we will use in the connect request. Run docker inspect command from the terminal like this:

docker inspect sdnc_controller_container

Search for “NetworkSettings” – “Networks” – “yaml_default” – “Gateway”. The field “Gateway” contains an IP address that we will use, so save it for later. In my case it looks like this:

...
"Gateway": "172.18.0.1",
...

Now, we are going to connect to the SDN-C Karaf so we can see the log because some of the DGs write information in there. Execute these commands:

docker exec -it sdnc_controller_container /bin/bash
cd /opt/opendaylight/bin/
./client
log:tail

To execute the Directed Graph, call RESTCONF RPC SLI-API: execute-graph. To do this, call a POST request on URI:

http://localhost:8282/restconf/operations/SLI-API:execute-graph

With payload:

{
  "input": {
    "module-name": "<module-name>",
    "rpc-name": "<rpc-name>",
    "mode": "sync",
    "sli-parameter": [
        {
            "parameter-name": "param1",
            "string-value": "val1"
        }
    ]
  }
}

Where <module-name> is the name of the module, where the RPC you want to call is located. <rpc-name> is the name of the RPC. Additionally, you can specify parameters if they are required. We are using port 8282, which we specified in the docker-compose file.

This Postman collection contains all the requests we are going to use now. Feel free to change any attributes, according to your needs.

To connect the Cisco NSO instance, we are going to execute the connectNSO directed graph. Execute SLI-API:execute-graph RPC with this payload:

{
  "input": {
    "module-name": "NSO-operations",
    "rpc-name": "connectNSO",
    "mode": "sync",
    "sli-parameter": [
        {
            "parameter-name": "nodeId",
            "string-value": "nso"
        },
        {
            "parameter-name": "nodeAddress",
            "string-value": "172.18.0.1"
        },
        {
            "parameter-name": "nodePort",
            "string-value": "2022"
        },
        {
            "parameter-name": "nodeUser",
            "string-value": "admin"
        },
        {
            "parameter-name": "nodePassword",
            "string-value": "admin"
        }
    ]
  }
}

Don’t forget to set the correct nodeAddress to this request – we got this value before by executing the docker inspect command.

The parameter nodeId specifies the name, under which we will address Cisco NSO in SDN-C. Other parameters are default for the Cisco NSO.

After executing this RPC, we should see our DG – ID of the Cisco NSO node and its connection status (which will be most probably “connecting”), in the SDN-C logs output.

...
12:57:14.654 INFO [qtp1682691455-1614] About to execute node #2 block node in graph SvcLogicGraph [module=NSO-operations, rpc=getNSO, mode=sync, version=1.0, md5sum=f7ed8e2805f0b823ab05ca9e7bb1b997]
12:57:14.656 INFO [qtp1682691455-1614] About to execute node #3 record node in graph SvcLogicGraph [module=NSO-operations, rpc=getNSO, mode=sync, version=1.0, md5sum=f7ed8e2805f0b823ab05ca9e7bb1b997]
12:57:14.671 INFO [qtp1682691455-1614] |Node ID is: nso|
12:57:14.672 INFO [qtp1682691455-1614] About to execute node #4 record node in graph SvcLogicGraph [module=NSO-operations, rpc=getNSO, mode=sync, version=1.0, md5sum=f7ed8e2805f0b823ab05ca9e7bb1b997]
12:57:14.674 INFO [qtp1682691455-1614] |Connection status is: connecting|
...

To check if Cisco NSO node was connected successfully, call getNSO DG. Execute SLI-API:execute-graph RPC with payload:

{
  "input": {
    "module-name": "NSO-operations",
    "rpc-name": "getNSO",
    "mode": "sync",
    "sli-parameter": [
        {
            "parameter-name": "nodeId",
            "string-value": "nso"
        }
    ]
  }
}

In the SDN-C logs, we should now see the “connected” status:

...
13:02:15.888 INFO [qtp1682691455-188] About to execute node #2 block node in graph SvcLogicGraph [module=NSO-operations, rpc=getNSO, mode=sync, version=1.0, md5sum=f7ed8e2805f0b823ab05ca9e7bb1b997]
13:02:15.889 INFO [qtp1682691455-188] About to execute node #3 record node in graph SvcLogicGraph [module=NSO-operations, rpc=getNSO, mode=sync, version=1.0, md5sum=f7ed8e2805f0b823ab05ca9e7bb1b997]
13:02:15.892 INFO [qtp1682691455-188] |Node ID is: nso|
13:02:15.893 INFO [qtp1682691455-188] About to execute node #4 record node in graph SvcLogicGraph [module=NSO-operations, rpc=getNSO, mode=sync, version=1.0, md5sum=f7ed8e2805f0b823ab05ca9e7bb1b997]
13:02:15.895 INFO [qtp1682691455-188] |Connection status is: connected|
...

Activate Cisco NSO service using Directed Graph

We are now going to activate the ACL service we created in this tutorial, by executing activateACL directed graph.

Execute SLI-API:execute-graph RPC with this payload:

{
  "input": {
    "module-name": "NSO-operations",
    "rpc-name": "activateACL",
    "mode": "sync",
    "sli-parameter": [
        {
            "parameter-name": "nodeId",
            "string-value": "nso"
        },
        {
            "parameter-name": "aclName",
            "string-value": "aclFromDG"
        },
        {
            "parameter-name": "aclDirection",
            "string-value": "in"
        },
        {
            "parameter-name": "aclDeviceName",
            "string-value": "c1"
        },
        {
            "parameter-name": "aclInterfaceType",
            "string-value": "GigabitEthernet"
        },
        {
            "parameter-name": "aclInterfaceNumber",
            "string-value": "1/1"
        }
    ]
  }
}

Feel free to change the values of ACL parameters (but first check what types they are in the ACL service YANG model).

Unfortunately, at the time of writing this tutorial, there is a bug in the OpenDaylight NETCONF (NETCONF-568) with parsing output from this RPC call. It prevents the ODL from sending a response to the RESTCONF request we sent (SLI-API:execute-graph RPC) and we need to manually stop waiting for this response in the Postman (or another REST client you are using).

Now, the service should be activated! To check services activated in the Cisco NSO call GET request on URI:

http://localhost:8282/restconf/operational/network-topology:network-topology/topology/topology-netconf/node/nso/yang-ext:mount/tailf-ncs:services

In response, you should see all activated services including our with name “aclFromDG”:

...
        "acl-service:acl-service": [
            {
                "ACL_Name": "aclFromDG",
                "ACL_Direction": "in",
                "devices": [
                    {
                        "device_name": "c1",
                        "interfaces": [
                            {
                                "interface_type": "GigabitEthernet",
                                "interface_number": "1/1"
                            }
                        ]
                    }
                ],
                "directly-modified": {
                    "devices": [
                        "c1"
                    ]
                },
                "device-list": [
                    "c1"
                ],
                "modified": {
                    "devices": [
                        "c1"
                    ]
                }
            }
        ]
...

To check if the device was configured log into Cisco NSO CLI and execute show command:

ncs_cli -u admin
show configuration devices device c1 config ios:interface

You should see an output, similar to this:

admin@ncs> show configuration devices device c1 config ios:interface
FastEthernet 1/0;
GigabitEthernet 1/1 {
    ip {
        access-group {
            access-list aclFromDG;
            direction   in;
        }
    }
}

Congratulations

You have successfully connected SDN-C with the Cisco NSO and concluded our series! In case you would like a custom integration, feel free to contact us.

Our previous articles in this series include:

3/24/2020 Update: Small tweaks in the code used in our demonstration, enjoy!


You can contact us at https://pantheon.tech/

Explore our Pantheon GitHub.

Watch our YouTube Channel.

OpenAPI 3.0 & OpenDaylight: A PANTHEON.tech Initiative

PANTHEON.tech has created a commit in the official OpenDaylight repository, which updates the version of Swagger generator to OpenAPI 3.0.

This feature allows us to easily generate a JSON with RESTCONF API documentation of OpenDaylight RESTCONF applications and import it into various services, such as ServiceNow®. This feature is not only about the generation of JSON with OpenAPI. It also includes Swagger UI based on generated JSON.

What is RESTCONF API?

RESTCONF API is an interface, which allows access to datastores in the controller, via HTTP requests. OpenDaylight supports two versions of RESTCONF protocol:

What is OpenAPI?

OpenAPI, formerly known as Swagger UI, visualizes API resources and enables the user to interact with them. This kind of visualization provides an easier way to implement APIs in the back-end while automating the creation of documentation for the APIs in question.

OpenAPI Specification on the other hand (OAS for short), is a language-agnostic interface description for RESTful APIs. Its purpose is to visualize them and make the APIs readable for people and PCs alike, in YAML or JSON formats.

OAS 3.0 introduced several major changes, which made the specification structure clearer and more efficient. For a rundown of changes from OpenAPI 2 to version 3, make sure to visit this page detailing them.

How does it work?

OpenAPI is generated on the fly, with every manual request for the OpenAPI specification of the selected resource. The resource can be the OpenDaylight datastore or a device mount point. 

You can conveniently access the list of all available resources over the apidoc web application. The resources are located on the top right part of the screen. Once you select the resource you want to generate the OpenAPI specification for, you just pick the desired resource and the OpenAPI specification will be displayed below.

OpenAPI 3.0 (Swagger) in OpenDaylight

The apidoc is packed within the odl-restconf-all Karaf feature. To access it, you only need to type

feature:install odl-restconf-all

in the Karaf console. Then, you can use a web browser of your choice to access the apidoc web application over the following URL:

http://localhost:8181/apidoc/explorer/index.html

Once an option is selected, the page will load the documentation of your chosen resource, with the chosen protocol version.

The documentation of any resource endpoint (node, RPC’s, actions), is located under its module spoiler. When you click on the link:

http://localhost:8181/apidoc/openapi3/${RESTCONF_version}/apis/${RESOURCE}

you will get the OpenAPI JSON for the particular RESTCONF version and selected resource. Here is a code snippet from the resulting OpenAPI specification:

{
  "openapi": "3.0.3",
  "info": {
    "version": "1.0.0",
    "title": "simulator-device21 modules of RestConf version RFC8040"
  },
  "servers": [
    {
      "url": "http://localhost:8181/"
    }
  ],
  "paths": {
    "/rests/data/network-topology:network-topology/topology=topology-netconf/node=simulator-device21/yang-ext:mount": {
      "get": {
        "description": "Queries the operational (running) datastore on the mounted hosted.",
        "summary": "GET - simulator-device21 - data",
        "tags": [
          "mounted simulator-device21 GET root"
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/rests/operations/network-topology:network-topology/topology=topology-netconf/node=simulator-device21/yang-ext:mount": {
      "get": {
        "description": "Queries the available operations (RPC calls) on the mounted hosted.",
        "summary": "GET - simulator-device21 - operations",
        "tags": [
          "mounted simulator-device21 GET root"
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
...

You can look through the entire export by clicking here.

Our Commitment to Open-Source

PANTHEON.tech is one of the largest contributors to the OpenDaylight source-code, with extensive knowledge that goes beyond a general service or integration.

This just goes to show, that PANTHEON.tech is heavily involved in the development and progress of OpenDaylight. We are glad to be part of the open-source community and contributors.


You can contact us at https://pantheon.tech/

Explore our PANTHEOn.tech GitHub.

Watch our YouTube Channel.

[Hands-On] Network Automation with ServiceNow® & OpenDaylight

by Miroslav Kováč | Leave us your feedback on this post!

PANTHEON.tech s.r.o., its products or services, are not affiliated with ServiceNow®, neither is this post an advertisement of ServiceNow® or its products.

ServiceNow® is a complex cloud application, used to manage companies, their employees, and customers. It was designed to help you automate the IT aspects of your business – service, operations, and business management. It creates incidents where using flows, you can automate part of the work that is very often done manually. All this can be easily set up by any person, even if you are not a developer.

An Example

If a new employee is hired in the company, he will need access to several things, based on his position. An incident will be created in ServiceNow® by HR. This will trigger a pre-created, generic flow, which might, for example, notify his direct supervisor (probably manager) and he would be asked to approve this request of access.

Once approved, the flow may continue and set everything up for this employee. It may notify the network engineer, to provision the required network services like (VPN, static IPs, firewall rules, and more), in order to give a new employee a computer. Once done, he will just update the status of this task to done, which may trigger another action. It can automatically give him access to the company intranet. Once everything is done, it will notify everyone it needs to, about a successful job done, with an email or any other communication resource the company is using.

Showing the ServiceNow® Flow Designer

 

Setting Up the Flow

Let’s take it a step further, and try to replace the network engineer, who has to manually configure the services needed for the device.

In a simple environment with a few network devices, we could set up the ServiceNow® Workflow, so that it can access them directly and edit the configuration, according to the required parameters.

In a complex, multi-tenant environment we could leverage a network controller, that can serve the required service and maintain the configuration of several devices. This will make the required service functional. In that case, we will need ServiceNow® to communicate with the controller, which secures this required network service.

The ServiceNow® orchestration understands and reads REST, OpenDaylight & lighty.io – in our case, the controller. It provides us with the RESTCONF interface, with which we can easily integrate ServiceNow®, OpenDaylight, or lighty.io, thanks to the support of both these technologies.

Now, we look at how to simplify this integration. For this purpose, we used OpenAPI.

This is one of the features, thanks to which we can generate a JSON according to the OpenAPI specification for every OpenDaylight/lighty.io application with RESTCONF, which we can then import into ServiceNow®.

If your question is, whether it is possible to integrate a network controller, for example, OpenDaylight or lighty.io, the answer is yes. Yes, it is.

Example of Network Automation

Let’s say we have an application with a UI, that will let us manage the network with a control station. We want to connect a new device to it and set up its interfaces. Manually, you would have to make sure that the device is running. If not, we have to contact IT support to plug it in, create a request to connect to it. Once done, we have to create another request to set up the interfaces and verify the setup.

Using flows in ServiceNow® will let you do all that automatically. All your application needs to do, is create an incident in ServiceNow ®. This incident would be set up as a trigger, for a flow to start. It would try to create a connection using a REST request, that would be chosen from API operations, which we have from our OpenAPI JSON. This was automatically generated from YANG files, that are used in the project.

If a connection fails, then it would automatically send an email to IT support, creating a new, separate incident, that would have to be marked as done before this flow can continue. Once done, we can try to connect again using the same REST. When the connection is successful, we can choose a new API operation again, that would process the interfaces.

After that, we can choose another API operation that would get all the created settings and send that to the person, that created this incident using an email and mark this incident as done.

OpenAPI & oneOf

Showing the ServiceNow® API Operation

Since the “New York” release of ServiceNow®, the import of OpenAPI is a new feature, it has some limitations.

During usage, we noticed a few inconsistencies, which we would like to share with you. Here are some tips, what you should look out for when using this feature.

OpenAPI & ServiceNow®

OpenAPI supports the oneOf feature, which is something that is needed for choice keywords in YANG. You can choose, which nodes you want to use. Currently, the workaround for this is to use the Swagger 2.0 implementation, which does not support the oneOf feature and will list all the cases that exist in a choice statement. If you go to input variables, you may delete any input variables that you don’t want yourself.

JSONs & identical item names

Another issue is when we have a JSON that contains the same item names in different objects or levels. So if I need the following JSON:

{
    "username": "foo",
    "password": "bar":,
    "another-log-in": {
        "username": "foo",
        "password": "bar"
    }
}

The workaround is, to add other input variables manually, that will have the same name, like the one that is missing. Suddenly, it may appear twice in input variables, but during testing, it appears only once – where it’s supposed to. Therefore, you need to manually fill in all the missing variables using the “+” button in the input variables tab.we have the username and password twice. However, it would appear in the input variables just once. When testing the action, I was unable to fill it in like the above JSON.

showing the ServiceNow® inputs

Input Variables in ServiceNow®

The last issue that we have, is with ServiceNow® not requiring input variables. Imagine you create an action with REST Step. If there are some variables that you don’t need to set up, you would normally not assign any value to that variable and it would not be set.

Here, it would automatically set it to a default value or an empty string if there is no default value, which can cause some problems with decimals as well – since you should not put strings into a decimal variable.

Again, the workaround is to remove all the input variables, that you are not going to use.

This concludes our network automation with the ServiceNow guide. Leave us your feedback on this post!


You can contact us at https://pantheon.tech/

Explore our Pantheon GitHub.

Watch our YouTube Channel.

A Cloud-Native & Unified Firewall

by Filip Gschwandtner | Leave us your feedback on this post!

Updated 11/05/2020: Our Unified Firewall Demo was updated with additional insight, as to how we achieved great results with our solution.

We differentiate generally between a hardware and software firewall. Software firewalls can reside in the userspace (for example, VPP) or the kernel space (for example, NetFilter). These serve as a basis for cloud-native firewalls. The main advantage of software firewalls is the ability to scale without hardware. This is done in the virtual machines or containers (Docker), where these firewalls reside and function from.

One traditional firewall utility in Linux is named iptables. It is configured via command-line and acts as an enforcer of rules and configuration of Netfilter. You can find a great how-to in the Ubuntu Documentation on configuring iptables, which is found pre-installed in most Linux distributions.

For a more performance-oriented firewall solution, you can turn to the evergreen, Vector Packet Processing framework and Access Control Lists (ACLs).

Our CDNF.io Project offers such a cloud-native function – Access Control List (ACL)-based firewall between CNF interfaces with FD.io VPP dataplane and Ligato management plane.

If we have sparked your interest in this solution, make sure to contact us directly. Until then, make sure to watch our CDNF.io project closely – there is more to come!

Firewall Solutions

Multiple solutions mean a wide variety of a user or company is able to choose from. But since each firewall uses a different API, we can almost immediately see an issue with the management of multiple solutions. Some APIs are more fully-fledged than others while requiring various levels of access (high level vs. low-level API) and several layers of features.

At PANTHEON.tech, we found that having a unified API, above which a management system would reside, would make a perfectly balanced firewall.

Cloud-Native: We will be using the open-source Ligato, micro-services platform. The advantage is, Ligato being cloud-native.

Implementation: The current implementation unifies the ACL in FD.io‘s VPP and the NetFilter in the Linux Kernel. For this purpose, we will be using the open-source VPP-Agent from Ligato.

Separate Layers: This architecture enables us to extend it to any configurable firewall, as seen below.

Layer Responsibilities: Computer networks are divided into network layers, where each layer has a different responsibility. We have modeled (proto-model) a unification API and translation to technology-specific firewall configuration. The unified layer has a unified API, which it translates and sends to the technology-specific API. The current implementation is via the VPP-Agent Docker container.

Ligato and VPP-Agent: In this implementation, we make full-use of VPP-Agent and Ligato, via gRPC communication. Each firewall has an API, modeled like a proto-model. This makes resolving failures a breeze.

Resolving Failures: Imagine that, in a cloud, software can end with a fatal error. The common solution is to suspend the container and restart it. This means, however, that you need to set up the configuration again or synchronize it with an existing configuration from higher layers.

Fast Reading of Configurations: There is no need to load everything again throughout all layers, up until the concrete firewall technology. These can be often slow in loading the configuration. Ligato resolves this via the configurations residing in the Ligato platform, in an external key-value storage (ETCD, if integrated with Ligato).

How did we do this?

We created this unifying API by using a healthy subset of all technologies. We preferred simplified API writing – since, for example in iptables, there can be lots of rules which can be written in a more compact way.

We analyzed several firewall APIs, which we broke down into basic blocks. We defined the basic filters for packet traffic, meaning the way from which interface, which way the traffic is flowing. Furthermore, we defined rules, based on the selector being the final filter for rules and actions, which should occur for selected traffic (simple allow/deny operation).

There are several types of selectors:

  • L2 (according to the sources MAC address)
  • L3 (IP and ICMP Selector)
  • L4 (Only TCP traffic via flags and ports / UDP traffic via ports)

The read/write performance of our Unified Firewall Layer solution, was tested using VPP and iptables (netfilter), at 250k rules. The initial tests ended with poor writing speed. But we experimented with various combinations and ended up putting a lot of rules into a few rule-groups.

That did not go as planned either.

A deep analysis showed that the issue is not within Ligato, since task-manager showed that the VPP/Linux kernel was fully working. We made an additional verification for iptables, only by using go-iptables library. It was very slow when adding too many rules in one chain. Fortunately, iptables provides us with additional tools, which are able to export and import data fast. The disadvantage is, that the export format is poorly documented. However, I did an iptables export and insert of data closely before the commit, and imported the data back afterward.

# Generated by iptables-save v1.6.1
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
:testchain - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
<<insert new data here>>
COMMIT

Our Open-Source Commitment

We achieved a speed increase for 20k rules in 1 iptable chain – from 3 minutes and 14 seconds to a few seconds. This showed a perfect performance fix for the VPP-Agent, which we committed to the Ligato VPP-Agent repository.

This also benefited updates, since each updated has to be implemented as a delete and create case (recreated each time). I made it as an optional method with a custom number of rules, from which it applies. Using too few rules can result in great speed with the default approach (via API iptables rule). Now, we have a solution for using a lot of rules as well. Due to the lack of detailed documentation of the iptables-save output format, I decided on turning this option off by default.

The results of the performance test are:

  • 25 rule-groups x 10000 rules for each rule-group
  • Write: 1 minute 49 seconds
  • Read: 359.045785ms

Reading is super-fast, due to all data being in the RAM in the Unified Layer. This means, that it’s all about one gRPC call with encoding/decoding.

If we have sparked your interest in this solution, make sure to contact us directly. Until then, make sure to watch our CDNF.io project closely – there is more to come!

VPP 105: Memory Management & DPDK APIs

VPP 105: Memory Management & DPDK APIs

Welcome to the 5th part of our VPP Guide series! Today, we will be asking ourselves practical questions regarding the various technologies & libraries managed in VPP – their usage, advantages, and management. Let’s jump right into it and ask ourselves:

Why does DPDK use Hugepages?

Hugepages

Hugepages is one of the techniques used in virtual memory management. In a standard environment, CPU allocates memory (virtual) for each process. Those blocks of memory are called „pages“ and for efficiency in Linux kernel the size of allocated memory is 4kB. When a process wants to access its memory, CPU has to find where this virtual memory is – this is the task of Memory Management Unit and page table lookup. Using the page table structure CPU could map virtual to physical memory.

For example, when the process needs 1GB of memory, this leads to more than 200k of pages in the page table which the CPU has to lookup for. Of course, this leads to performance slowdown. Fortunately, nowadays CPUs support bigger pages – so-called Hugepages. They can reduce the number of pages to be lookup for and usage of huge pages increases performance.

Memory Management Unit uses one additional hardware cache – Translation Lookaside Buffers (TLB). When there is address translation from virtual memory to physical memory, translation is calculated in MMU, and this mapping is stored in the TLB. So next time accessing the same page will be first handled by TLB (which is fast) and then by MMU.

As TLB is a hardware cache, it has a limited number of entries, so a large number of pages will slow down the application. So a combination of TLB with Hugepages reduces the time it takes to translate a virtual page address to a physical page address and to lookup for and so again it will increase performance.

This is the reason why DPDK, and VPP as well, uses Hugepages for large memory pool allocation, used for packet buffers. By using Hugepages allocations, performance is increased since fewer pages and fewer lookups are needed and the management is more effective.

Cache prefetching

Cache prefetching is another technique used by VPP to boost execution performance. Prefetching data from their original storage in slower memory to a faster local memory before it is actually needed significantly increase performance. CPUs have fast and local cache memory in which prefetched data is held until it is required. Examples of CPU caches with a specific function are the D-cache (data cache), I-cache (instruction cache) and the TLB (translation lookaside buffer) for the MMU. Separated D-cache and I-cache makes it possible to fetch instructions and data in parallel. Moreover, instructions and data have different access patterns.

Cache prefetching is used mainly in nodes when processing packets. In VPP, each node has a registered function responsible for incoming traffic handling. An example of registration (abf and flowprobe nodes):

/*
 * Copyright (c) 2017 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

VLIB_REGISTER_NODE (abf_ip4_node) = {
  .function = abf_input_ip4,
  .name = "abf-input-ip4",

VLIB_REGISTER_NODE (flowprobe_ip4_node) = {
  .function = flowprobe_ip4_node_fn,
  .name = "flowprobe-ip4",

In abf processing function, we can see single loop handling – it loops over packets and handles them one by one.

/*
 * Copyright (c) 2017 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

abf_input_inline (vlib_main_t * vm,
      vlib_node_runtime_t * node,
      vlib_frame_t * frame, fib_protocol_t fproto)
{
...
      while (n_left_from > 0 && n_left_to_next > 0)
  {
...	
    abf_next_t next0 = ABF_NEXT_DROP;
    vlib_buffer_t *b0;
    u32 bi0, sw_if_index0;
...
    bi0 = from[0];
    to_next[0] = bi0;
    from += 1;
    to_next += 1;
    n_left_from -= 1;
    n_left_to_next -= 1;

    b0 = vlib_get_buffer (vm, bi0);
    sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];

    ASSERT (vec_len (abf_per_itf[fproto]) > sw_if_index0);
    attachments0 = abf_per_itf[fproto][sw_if_index0];
...
    /* verify speculative enqueue, maybe switch current next frame */
    vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
             to_next, n_left_to_next, bi0,
             next0);
  }
      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    }

In flowprobe node, we can see quad/single loop using prefetching which can significantly increase performance. In the first loop:

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

( while (n_left_from >= 4 ... ) )

it processes buffers b0 and b1 (and moreover, the next two buffers are prefetched), and in the next loop

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

( while (n_left_from > 0 ... ) )

remaining packets are processed.

/*
 * Copyright (c) 2018 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

flowprobe_node_fn (vlib_main_t * vm,
       vlib_node_runtime_t * node, vlib_frame_t * frame,
       flowprobe_variant_t which)
{
...
      /*
      * While we have at least 4 vector elements (pkts) to process..
      */

      while (n_left_from >= 4 && n_left_to_next >= 2)
  {
...
    /* Prefetch next iteration. */
    {
      vlib_buffer_t *p2, *p3;

      p2 = vlib_get_buffer (vm, from[2]);
      p3 = vlib_get_buffer (vm, from[3]);

      vlib_prefetch_buffer_header (p2, LOAD);
      vlib_prefetch_buffer_header (p3, LOAD);

      CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
      CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
    }
...
    /* speculatively enqueue b0 and b1 to the current next frame */
    b0 = vlib_get_buffer (vm, bi0);
    b1 = vlib_get_buffer (vm, bi1);


    /* verify speculative enqueues, maybe switch current next frame */
    vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
             to_next, n_left_to_next,
             bi0, bi1, next0, next1);
  }
      /*
      * Clean up 0...3 remaining packets at the end of the frame
      */
      while (n_left_from > 0 && n_left_to_next > 0)
  {
    u32 bi0;
    vlib_buffer_t *b0;
    u32 next0 = FLOWPROBE_NEXT_DROP;
    u16 len0;

    /* speculatively enqueue b0 to the current next frame */
    bi0 = from[0];
    to_next[0] = bi0;
    from += 1;
    to_next += 1;
    n_left_from -= 1;
    n_left_to_next -= 1;

    b0 = vlib_get_buffer (vm, bi0);

    vnet_feature_next (&next0, b0);

    len0 = vlib_buffer_length_in_chain (vm, b0);
    ethernet_header_t *eh0 = vlib_buffer_get_current (b0);
    u16 ethertype0 = clib_net_to_host_u16 (eh0->type);

    if (PREDICT_TRUE ((b0->flags & VNET_BUFFER_F_FLOW_REPORT) == 0))
      {
        flowprobe_trace_t *t = 0;
        if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
         && (b0->flags & VLIB_BUFFER_IS_TRACED)))
    t = vlib_add_trace (vm, node, b0, sizeof (*t));

        add_to_flow_record_state (vm, node, fm, b0, timestamp, len0,
          flowprobe_get_variant
          (which, fm->context[which].flags,
           ethertype0), t);
      }

    /* verify speculative enqueue, maybe switch current next frame */
    vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
             to_next, n_left_to_next,
             bi0, next0);
  }

VPP I/O Request Handling

Why is polling faster than IRQs? How do the hardware/software IRQs work?

I/O device (NIC) event handling is a significant part of VPP. The CPU doesn’t know when an I/O event can occur, but it has to respond. There are two different approaches – IRQ and Polling, which are different from each other in many aspects.

From a CPU point of view, IRQ seems to be better, as the device disturbs the CPU only when it needs servicing, instead of constantly checking device status in case of polling. But from an efficiency point of view, interruptions are inefficient when the devices keep on interrupting the CPU repeatedly and polling is inefficient when the CPU device is rarely ready for servicing.

As in the case of packet processing in VPP, it is expected that traffic will be permanent. In such a case, the number of interruptions would rapidly increase. On the other hand, the device will be ready for service all the time. So polling seems to be more efficient for packet processing and it is the reason why VPP uses polling when processing the incoming packet.

VPP & DPDK

What API does DPDK offer? How does VPP use this library?

DPDK networking drivers are classified in two categories:

  • physical for real devices
  • virtual for emulated devices

The DPDK ethdev layer exposes APIs, in order to use the networking functions of these devices. For a full list of the supported features and APIs, click here.

In VPP, DPDK support has been moved from core to plugin to simplify enabling/disabling and handling DPDK interfaces. To simplify and store all DPDK relevant info, a DPDK device implementation (src/plugin/dpdk/device/dpdk.h) has a structure with DPDK data:

/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright(c) 2010-2014 Intel Corporation
 */

typedef struct
{
...
  struct rte_eth_conf port_conf;
  struct rte_eth_txconf tx_conf;
...
  struct rte_flow_error last_flow_error;
...
  struct rte_eth_link link;
...
  struct rte_eth_stats stats;
  struct rte_eth_stats last_stats;
  struct rte_eth_xstat *xstats;
...
} dpdk_device_t;

containing all relevant DPDK structs used in VPP, to store DPDK relevant info.

DPDK APIs are used in the DPDK plugin only. Here is a list of DPDK features and their API’s used in VPP, with a few examples of usage.

Speed Capabilities / Runtime Rx / Tx Queue Setup

Supports getting the speed capabilities that the current device is capable of. Supports Rx queue setup after the device started.

API: rte_eth_dev_info_get()

/*
 * Copyright (c) 2017 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

dpdk_device_setup (dpdk_device_t * xd)
{
  dpdk_main_t *dm = &dpdk_main;
...
  struct rte_eth_dev_info dev_info;
...
  if (xd->flags & DPDK_DEVICE_FLAG_ADMIN_UP)
    {
      vnet_hw_interface_set_flags (dm->vnet_main, xd->hw_if_index, 0);
      dpdk_device_stop (xd);
    }

  /* Enable flow director when flows exist */
  if (xd->pmd == VNET_DPDK_PMD_I40E)
    {
      if ((xd->flags & DPDK_DEVICE_FLAG_RX_FLOW_OFFLOAD) != 0)
  xd->port_conf.fdir_conf.mode = RTE_FDIR_MODE_PERFECT;
      else
  xd->port_conf.fdir_conf.mode = RTE_FDIR_MODE_NONE;
    }

  rte_eth_dev_info_get (xd->port_id, &dev_info);

Link Status

Supports getting the link speed, duplex mode and link-state (up/down).

API: rte_eth_link_get_nowait()

/*
 *Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

dpdk_update_link_state (dpdk_device_t * xd, f64 now)
{
  vnet_main_t *vnm = vnet_get_main ();
  struct rte_eth_link prev_link = xd->link;
...
  /* only update link state for PMD interfaces */
  if ((xd->flags & DPDK_DEVICE_FLAG_PMD) == 0)
    return;

  xd->time_last_link_update = now ? now : xd->time_last_link_update;
  clib_memset (&xd->link, 0, sizeof (xd->link));
  rte_eth_link_get_nowait (xd->port_id, &xd->link);

Lock-Free Tx Queue

If a PMD advertises DEV_TX_OFFLOAD_MT_LOCKFREE capable, multiple threads can invoke rte_eth_tx_burst() concurrently on the same Tx queue without SW lock.

API: rte_eth_tx_burst()

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

static clib_error_t *
dpdk_lib_init (dpdk_main_t * dm)
{
...
  dpdk_device_t *xd;
...
      if (xd->pmd == VNET_DPDK_PMD_FAILSAFE)
  {
    /* failsafe device numerables are reported with active device only,
     * need to query the mtu for current device setup to overwrite
     * reported value.
     */
    uint16_t dev_mtu;
    if (!rte_eth_dev_get_mtu (i, &dev_mtu))
      {
        mtu = dev_mtu;
        max_rx_frame = mtu + sizeof (ethernet_header_t);

        if (dpdk_port_crc_strip_enabled (xd))
    {
      max_rx_frame += 4;
    }
      }
  }

Promiscuous Mode

Supports enabling/disabling promiscuous mode for a port.

API: rte_eth_promiscuous_enable(), rte_eth_promiscuous_disable(), rte_eth_promiscuous_get()

Allmulticast Mode

Supports enabling/disabling receiving multicast frames.

API: rte_eth_allmulticast_enable(), rte_eth_allmulticast_disable(), rte_eth_allmulticast_get()

/*
 * Copyright (c) 2017 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

dpdk_device_stop (dpdk_device_t * xd)
{
  if (xd->flags & DPDK_DEVICE_FLAG_PMD_INIT_FAIL)
    return;

  rte_eth_allmulticast_disable (xd->port_id);
  rte_eth_dev_stop (xd->port_id);
...

Unicast MAC Filter

Supports adding MAC addresses to enable white-list filtering to accept packets.

APIrte_eth_dev_default_mac_addr_set(), rte_eth_dev_mac_addr_add(), rte_eth_dev_mac_addr_remove(), rte_eth_macaddr_get()

VLAN Filter

Supports filtering of a VLAN Tag identifier.

API: rte_eth_dev_vlan_filter()

VLAN Offload

Supports VLAN offload to hardware.

API: rte_eth_dev_set_vlan_offload(), rte_eth_dev_get_vlan_offload()

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

dpdk_subif_add_del_function (vnet_main_t * vnm,
           u32 hw_if_index,
           struct vnet_sw_interface_t *st, int is_add)
{
...
  dpdk_device_t *xd = vec_elt_at_index (xm->devices, hw->dev_instance);
  int r, vlan_offload;
...
  vlan_offload = rte_eth_dev_get_vlan_offload (xd->port_id);
  vlan_offload |= ETH_VLAN_FILTER_OFFLOAD;

  if ((r = rte_eth_dev_set_vlan_offload (xd->port_id, vlan_offload)))
    {
      xd->num_subifs = prev_subifs;
      err = clib_error_return (0, "rte_eth_dev_set_vlan_offload[%d]: err %d",
             xd->port_id, r);
      goto done;
    }

  if ((r =
       rte_eth_dev_vlan_filter (xd->port_id,
        t->sub.eth.outer_vlan_id, is_add)))
    {
      xd->num_subifs = prev_subifs;
      err = clib_error_return (0, "rte_eth_dev_vlan_filter[%d]: err %d",
             xd->port_id, r);
      goto done;
    }

Basic Stats

Support basic statistics such as: ipackets, opackets, ibytes, obytes, imissed, ierrors, oerrors, rx_nombuf. And per queue stats: q_ipackets, q_opackets, q_ibytes, q_obytes, q_errors.

API: rte_eth_stats_get, rte_eth_stats_reset()

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

dpdk_update_counters (dpdk_device_t * xd, f64 now)
{
  vlib_simple_counter_main_t *cm;
  vnet_main_t *vnm = vnet_get_main ();
  u32 thread_index = vlib_get_thread_index ();
  u64 rxerrors, last_rxerrors;

  /* only update counters for PMD interfaces */
  if ((xd->flags & DPDK_DEVICE_FLAG_PMD) == 0)
    return;

  xd->time_last_stats_update = now ? now : xd->time_last_stats_update;
  clib_memcpy_fast (&xd->last_stats, &xd->stats, sizeof (xd->last_stats));
  rte_eth_stats_get (xd->port_id, &xd->stats);

Extended Stats

Supports Extended Statistics, changes from driver to driver.

APIrte_eth_xstats_get(), rte_eth_xstats_reset(), rte_eth_xstats_get_names, rte_eth_xstats_get_by_id(), rte_eth_xstats_get_names_by_id(), rte_eth_xstats_get_id_by_name()

Module EEPROM Dump

Supports getting information and data of plugin module eeprom.

API: rte_eth_dev_get_module_info(), rte_eth_dev_get_module_eeprom()


VPP Library (vlib)

What funcionality does vlib offer?

Vlib is a vector processing library. It also handles various application management functions:

  • buffer, memory, and graph node management and scheduling
  • reliable multicast support
  • ultra-lightweight cooperative multi-tasking threads
  • physical memory, and Linux epoll support
  • maintaining and exporting counters
  • thread management
  • packet tracing.

Vlib also implements the debug CLI.

In VPP (vlib), a vector is an instance of the vlib_frame_t type:

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

typedef struct vlib_frame_t
{
  /* Frame flags. */
  u16 flags;

  /* Number of scalar bytes in arguments. */
  u8 scalar_size;

  /* Number of bytes per vector argument. */
  u8 vector_size;

  /* Number of vector elements currently in frame. */
  u16 n_vectors;

  /* Scalar and vector arguments to next node. */
  u8 arguments[0];
} vlib_frame_t;

As shown, vectors are dynamically resized arrays with user-defined “headers”. Many data structures in VPP (buffers, hash, heap, pool) are vectors with different headers.

The memory layout looks like this:

© Copyright 2018, Linux Foundation


User header (optional, uword aligned)
                  Alignment padding (if needed)
                  Vector length in elements
User's pointer -> Vector element 0
                  Vector element 1
                  ...
                  Vector element N-1

Vectors are not only used in vppinfra data structures (hash, heap, pool, …) but also in vlib – in nodes, buffers, processes and more.

Buffers

Vlib buffers are used to reach high performance in packet processing. To do so, one allocates/frees N-buffers at once, rather than one at a time – except for directly processing specific buffer (its packets in given node), one deals with buffer indices instead of buffer pointers. Vlib buffers have a structure of a vector:

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

/** VLIB buffer representation. */
typedef union
{
  struct
  {
    CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);

    /** signed offset in data[], pre_data[] that we are currently
      * processing. If negative current header points into predata area.  */
    i16 current_data;

    /** Nbytes between current data and the end of this buffer.  */
    u16 current_length;
...
    /** Opaque data used by sub-graphs for their own purposes. */
    u32 opaque[10];
...
    /**< More opaque data, see ../vnet/vnet/buffer.h */
    u32 opaque2[14];

    /** start of third cache line */
      CLIB_CACHE_LINE_ALIGN_MARK (cacheline2);

    /** Space for inserting data before buffer start.  Packet rewrite string
      * will be rewritten backwards and may extend back before
      * buffer->data[0].  Must come directly before packet data.  */
    u8 pre_data[VLIB_BUFFER_PRE_DATA_SIZE];

    /** Packet data */
    u8 data[0];
  };
#ifdef CLIB_HAVE_VEC128
  u8x16 as_u8x16[4];
#endif
#ifdef CLIB_HAVE_VEC256
  u8x32 as_u8x32[2];
#endif
#ifdef CLIB_HAVE_VEC512
  u8x64 as_u8x64[1];
#endif
} vlib_buffer_t;

Each vlib_buffer_t (packet buffer) carries the buffer metadata, which describes the current packet-processing state.

  • u8 data[0]: Ordinarily, hardware devices use data as the DMA target but there are exceptions. Do not access data directly, use vlib_buffer_get_current.
  • u32 opaque[10]: primary vnet-layer opaque data
  • u32 opaque2[14]: secondary vnet-layer opaque data

There are several functions to get data from vector (vlib/node_funcs.h):

To get a pointer to frame vector data

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

always_inline void *
vlib_frame_vector_args (vlib_frame_t * f)
{
  return (void *) f + vlib_frame_vector_byte_offset (f->scalar_size);
}
-	to get pointer to scalar data
always_inline void *
vlib_frame_scalar_args (vlib_frame_t * f)
{
  return vlib_frame_vector_args (f) - f->scalar_size;
}

Get pointer to scalar data

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

always_inline void *
vlib_frame_scalar_args (vlib_frame_t * f)
{
  return vlib_frame_vector_args (f) - f->scalar_size;
}

Translate the buffer index into buffer pointer

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

always_inline vlib_buffer_t *
vlib_get_buffer (vlib_main_t * vm, u32 buffer_index)
{
  vlib_buffer_main_t *bm = vm->buffer_main;
  vlib_buffer_t *b;

  b = vlib_buffer_ptr_from_index (bm->buffer_mem_start, buffer_index, 0);
  vlib_buffer_validate (vm, b);
  return b;
}

Get the pointer to current (packet) data from a buffer to process

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

always_inline void *
vlib_buffer_get_current (vlib_buffer_t * b)
{
  /* Check bounds. */
  ASSERT ((signed) b->current_data >= (signed) -VLIB_BUFFER_PRE_DATA_SIZE);
  return b->data + b->current_data;

Get vnet primary buffer metadata in the reserved opaque field

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0<br >
 */

#define vnet_buffer(b) ((vnet_buffer_opaque_t *) (b)->opaque)

An example to retrieve vnet buffer data:

/*
 * Copyright (c) 2017 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

add_to_flow_record_state (vlib_main_t * vm, vlib_node_runtime_t * node,
        flowprobe_main_t * fm, vlib_buffer_t * b,
        timestamp_nsec_t timestamp, u16 length,
        flowprobe_variant_t which, flowprobe_trace_t * t)
{
...
  u32 rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];

Get vnet primary buffer metadata in reserved opaque2 field

/*
 * Copyright (c) 2017 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

#define vnet_buffer2(b) ((vnet_buffer_opaque2_t *) (b)->opaque2)

Let’s take a look at flowprobe node processing function. Vlib functions always start with a vlib_ prefix.

/*
 * Copyright (c) 2017 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

flowprobe_node_fn (vlib_main_t * vm,
       vlib_node_runtime_t * node, vlib_frame_t * frame,
       flowprobe_variant_t which)
{
  u32 n_left_from, *from, *to_next;
  flowprobe_next_t next_index;
  flowprobe_main_t *fm = &flowprobe_main;
  timestamp_nsec_t timestamp;

  unix_time_now_nsec_fraction (&timestamp.sec, &timestamp.nsec);
  
// access frame vector data
  from = vlib_frame_vector_args (frame);
  n_left_from = frame->n_vectors;
  next_index = node->cached_next_index;

  while (n_left_from > 0)
    {
      u32 n_left_to_next;

      // get pointer to next vector data
      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);

// dual loop – we are processing two buffers and prefetching next two buffers
      while (n_left_from >= 4 && n_left_to_next >= 2)
  {
    u32 next0 = FLOWPROBE_NEXT_DROP;
    u32 next1 = FLOWPROBE_NEXT_DROP;
    u16 len0, len1;
    u32 bi0, bi1;
    vlib_buffer_t *b0, *b1;

    /* Prefetch next iteration. */
             // prefetching packets p3 and p4 while p1 and p2 are processed
    {
      vlib_buffer_t *p2, *p3;

      p2 = vlib_get_buffer (vm, from[2]);
      p3 = vlib_get_buffer (vm, from[3]);

      vlib_prefetch_buffer_header (p2, LOAD);
      vlib_prefetch_buffer_header (p3, LOAD);

      CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
      CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
    }
/* speculatively enqueue b0 and b1 to the current next frame */
// frame contains buffer indecies (bi0, bi1) instead of pointers
    to_next[0] = bi0 = from[0];
    to_next[1] = bi1 = from[1];
    from += 2;
    to_next += 2;
    n_left_from -= 2;
    n_left_to_next -= 2;

// translate buffer index to buffer pointer
    b0 = vlib_get_buffer (vm, bi0);
    b1 = vlib_get_buffer (vm, bi1);
// select next node based on feature arc
    vnet_feature_next (&next0, b0);
    vnet_feature_next (&next1, b1);

    len0 = vlib_buffer_length_in_chain (vm, b0);
// get current data (header) from packet to process
// currently we are on L2 so get etehernet header, but if we
// are on L3 for example we can retrieve L3 header, i.e.
// ip4_header_t *ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) 
    ethernet_header_t *eh0 = vlib_buffer_get_current (b0);
    u16 ethertype0 = clib_net_to_host_u16 (eh0->type);

    if (PREDICT_TRUE ((b0->flags & VNET_BUFFER_F_FLOW_REPORT) == 0))
      add_to_flow_record_state (vm, node, fm, b0, timestamp, len0,
              flowprobe_get_variant
              (which, fm->context[which].flags,
               ethertype0), 0);
...
/* verify speculative enqueue, maybe switch current next frame */
    vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
             to_next, n_left_to_next,
             bi0, next0);
  }

      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    }
  return frame->n_vectors;
}

Nodes

As we said – vlib is also designed for graph node management. When creating a new feature, one has to initialize it, using the VLIB_INIT_FUNCTION macro. This constructs a vlib_node_registration_t, most often via the VLIB_REGISTER_NODE macro. At runtime, the framework processes the set of such registrations into a directed graph.

/*
 * Copyright (c) 2016 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0<br >
 */

static clib_error_t *
flowprobe_init (vlib_main_t * vm)
{
  /* ... initialize things ... */
 
  return 0;
}

VLIB_INIT_FUNCTION (flowprobe_init);

...

VLIB_REGISTER_NODE (flowprobe_l2_node) = {
  .function = flowprobe_l2_node_fn,
  .name = "flowprobe-l2",
  .vector_size = sizeof (u32),
  .format_trace = format_flowprobe_trace,
  .type = VLIB_NODE_TYPE_INTERNAL,
  .n_errors = ARRAY_LEN(flowprobe_error_strings),
  .error_strings = flowprobe_error_strings,
  .n_next_nodes = FLOWPROBE_N_NEXT,
  .next_nodes = FLOWPROBE_NEXT_NODES,
};

VLIB_REGISTER_NODE (flowprobe_walker_node) = {
  .function = flowprobe_walker_process,
  .name = "flowprobe-walker",
  .type = VLIB_NODE_TYPE_INPUT,
  .state = VLIB_NODE_STATE_INTERRUPT,
};

Type member in node registration specifies the purpose of the node:

  • VLIB_NODE_TYPE_PRE_INPUT – run before all other node types
  • VLIB_NODE_TYPE_INPUT – run as often as possible, after pre_input nodes
  • VLIB_NODE_TYPE_INTERNAL – only when explicitly made runnable by adding pending frames for processing
  • VLIB_NODE_TYPE_PROCESS – only when explicitly made runnable.

The initialization of feature is executed at some point in the application’s startup. However, constraints must be used to specify an order (when one feature has to be initialized after/before another one). To hook feature into specific feature arc VNET_FEATURE_INT macro can be used.

/*
 * Copyright (c) 2016 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_src, static) = {
  .arc_name = "ip4-output",
  .node_name = "nat44-ed-hairpin-src",
  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
};

VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
{
  .arc_name = "ip4-local",
  .node_name = "nat44-hairpinning",
  .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
};

Since VLIB_NODE_TYPE_INPUT nodes are the starting point of a feature arc, they are responsible for generating packets from some source, like a NIC or PCAP file and injecting them into the rest of the graph.

When registering a node, one can provide a .next_node parameter with an indexed list of the upcoming nodes in the graph. For example, a flowprobe node below:

/*
 * Copyright (c) 2017 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0<br >
 */

...
next_nodes = FLOWPROBE_NEXT_NODES,
...

#define FLOWPROBE_NEXT_NODES {				\
    [FLOWPROBE_NEXT_DROP] = "error-drop",		\
    [FLOWPROBE_NEXT_IP4_LOOKUP] = "ip4-lookup",		\
}

vnet_feature_next is commonly used to select the next node. This selection is based on the feature mechanism, as in the flowprobe example above:

/*
 * Copyright (c) 2017 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

flowprobe_node_fn (vlib_main_t * vm,
       vlib_node_runtime_t * node, vlib_frame_t * frame,
       flowprobe_variant_t which)
{
...
    b0 = vlib_get_buffer (vm, bi0);
    b1 = vlib_get_buffer (vm, bi1);
        // select next node based on feature arc
    vnet_feature_next (&next0, b0);
    vnet_feature_next (&next1, b1);

The graph node dispatcher pushes the work-vector through the directed graph, subdividing it as needed until the original work-vector has been completely processed.

Graph node dispatch functions call vlib_get_next_frame to set (u32 *)to_next to the right place in the vlib_frame_t, corresponding to the ith arc (known as next0) from the current node, to the indicated next node.

Before a dispatch function returns, it’s required to call vlib_put_next_frame for all of the graph arcs it actually used. This action adds a vlib_pending_frame_t to the graph dispatcher’s pending frame vector.

/*
 * Copyright (c) 2015 Cisco and/or its affiliates. Licensed under the Apache License, Version 2.0. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
 */

      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    }
  return frame->n_vectors;
}

Pavel Kotúček

Thank you for reading through the 5th part of our PANTHEON.tech VPP Guide! As always, feel free to contact us if you are interested in customized solutions!


You can contact us at https://pantheon.tech/

Explore our Pantheon GitHub.

Watch our YouTube Channel.

[Guide] Intro to Vector Packet Processing (VPP)

Welcome to our new series on how to build and program FD.io‘s Vector Packet Processing framework, also known as VPP.

The name stems from VPP’s usage of vector processing, which can process multiple packets at a time with low latency. Single packet processing and high latency were a common occurrence in the older, scalar processing approach, which VPP aims to make obsolete.

What will this series include?

This four-part series will include the following features, with the ultimate goal on getting to know your VPP framework and adapting it to your network:

  1. Binary API
  2. Honeycomb/hc2vpp
  3. Ligato VPP Agent
  4. gRPC/REST
  5. Memory Management & DPDK APIs

Why should I start using Vector Package Processing?

The main advantages are:

  • high performance with a proven technology
  • production level quality
  • flexible and extensible

The principle of VPP is, that you can plugin a new graph node, adapt it to your networks purposes and run it right off the bat. Including a new plugin does not mean, you need to change your core-code with each new addition. Plugins can be either included in the processing graph, or they can be built outside the source tree and become an individual component in your build.

Furthermore, this separation of plugins makes crashes a matter of a simple process restart, which does not require your whole build to be restarted because of one plugin failure.

For a full list of features, please visit the official Vector Package Processing Wiki.You can also check our previous installments on VPP integration.

Preparation of VPP packages

In order to build and start with VPP yourself, you will have to:

  1. Download VPP’s repository from this page or follow the installation instructions
  2. Clone the repository inside your system, or from VPP’s GitHub

Enjoy and explore the repository as you wish. We will continue exploring the Binary API in the next part of our series.


You can contact us at https://pantheon.tech/

Explore our Pantheon GitHub.

Watch our YouTube Channel.

lighty.io BGP EVPN Route Reflector featured image

[lighty.io] BGP EVPN Route-Reflector

In our previous blog post, we have introduced you with a Border Gateway Protocol Route-Reflector (BGP-RR) function in SDN controller based on lighty.io. In this article, we’re going to extend the BGP function of an SDN controller with an EVPN extension in the BGP control-plane.

Functionality

This article will discuss BGP-EVPN functions in an SDN controller and how the lighty.io BGP-function can replace existing legacy route-reflectors running in service provider’s WAN/DC networks. BGP-EVPN provides:

  • Advanced Layer 2 MAC and Layer 3 IP reachability information capabilities in control-plane
  • Route-Type 2: advertising MAC/IP address, instead of traditional MAC learning mechanisms
  • Route-Type 5: advertising the IP prefix subnet prefix route

We’re going to show you a BGP-EVPN IP subnet routing use-case

A BGP-EVPN control-plane can also co-exist with various data-planes, such as MPLS, VXLAN, and PBB.

Use-case: Telecom Data-Center

In this blog, we’re going to show you the BGP-EVPN control-plane working together with VXLAN data-plane. The perfect use case for this combination would be a telecom data-center.

Virtual Extensible LAN (VXLAN) is an overlay technology for network virtualization. It provides Layer 2 extension over a shared Layer 3 underlay infrastructure network, by using the MAC address in an IP/User Datagram Protocol (MAC in IP/UDP) tunneling encapsulation. The initial IETF VXLAN standards defined a multicast-based flood-and-learn VXLAN without a control plane.

It relies on data-based flood-and-learn behavior for remote VXLAN tunnel endpoint (VTEP) peer-discovery and remote end-host learning. BGP-EVPN, as the control plane for VXLAN, overcomes the limitations of flood-and-learn mechanism.

Test Bed

Test Bed Visualization

In this demo, we will use:

  • five Docker containers & three Docker networks.
  • Docker auto-generated user-defined bridge networks with mask /16
  • Arista’s cEOS software, as we did in our previous demo

Remember, that an Arista cEOS switch creates an EtX port when starting up in the container, which is bridged to EthX port in Docker.

These auto-generated EtX ports are accessible and configurable from cEOS Cli and on start are in default L2 switching mode. This means they don’t have an IP address assigned.

Well, let’s expand our previous demo topology with few more network elements. Here is a list of Docker containers used in this demo:

  • leaf1 & leaf2: WAN switch & access/node
  • host1 & host2: Ubuntu VM
  • BGP-RR: BGP-EVPN Route Reflector

Here is a list of Docker user-defined networks used in this demo:

  • net1 (172.18.0.0/16): connects leaf1 & host1
  • net2 (172.19.0.0/16): connects leaf2 & host2
  • net3 (172.20.0.0/16: connects leaf1, leaf2 & bgp-rr

Our Goal: Routing

At the end of this blog, we want to be able to reach IP connectivity between virtual machine host1 and host2. For that, we need BGP to advertise loopback networks and VLAN information between nodes.

In this example, we are using one AS-50.

To demonstrate route-reflector EVPN functionality leaf1 & leaf2 doesn’t make an IBGP pair but creates a pair with lighty-BGP instead. This will act as a route-reflector. In VxLAN configuration we don’t set up flood vtep. This information should redistribute Route Routing to peers.

The container with lighty-BGP MUST NOT be used as forwarding node since it doesn’t know manipulate the routing table.

Configuration

This demo configuration is prepared and tested on Ubuntu 18.04.2.

Docker Configuration

Before you start, please make sure that you have Docker (download instructions, use version 18.09.6 or higher) & Postman downloaded and installed.

1. Download lighty-BGP Docker image. PANTHEON.tech has its own

https://hub.docker.com/u/pantheontech
sudo docker pull pantheontech/lighty-rr:9.2.0-dev

2. Download the Docker image for Arista cEOS (we used v. 4.21.0F)

sudo docker import cEOS-lab.tar.xz ceosimage:4.21.0F

3. Download the Ubuntu image from DockerHub

sudo docker pull ubuntu:latest

4. Check the Docker images, successfully installed in the repository

sudo docker images

Preparing the Docker Environment

1. Create Docker networks

sudo docker network create net1
sudo docker network create net2
sudo docker network create net3

2. Check all Docker networks, that have been created

sudo docker network ls

3. Create containers in Docker

sudo docker create --name=bgp-rr --privileged -e INTFTYPE=eth -it pantheontech/lighty-rr:9.2.0-dev
sudo docker create --name=leaf1 --privileged -e CEOS=1 -e container=docker -e EOS_PLATFORM=ceoslab -e SKIP_ZEROTOUCH_BARRIER_IN_SYSDBINIT=1 -e ETBA=1 -e INTFTYPE=eth -i -t ceosimage:4.21.0F /sbin/init
sudo docker create --name=leaf2 --privileged -e CEOS=2 -e container=docker -e EOS_PLATFORM=ceoslab -e SKIP_ZEROTOUCH_BARRIER_IN_SYSDBINIT=1 -e ETBA=1 -e INTFTYPE=eth -i -t ceosimage:4.21.0F /sbin/init
docker create  --privileged --name host1 -i -t ubuntu:latest /bin/bash
docker create  --privileged --name host2 -i -t ubuntu:latest /bin/bash

4. Connect containers to Docker networks

sudo docker network connect net1 leaf1
sudo docker network connect net1 host1
sudo docker network connect net2 leaf2
sudo docker network connect net2 host2
sudo docker network connect net3 bgp-rr
sudo docker network connect net3 leaf1
sudo docker network connect net3 leaf2

5. Start all containers

sudo docker start leaf1
sudo docker start leaf2
sudo docker start host1
sudo docker start host2
sudo docker start bgp-rr

6. Enable permanent IPv4 forwarding in cEOS containers

sudo docker exec -it leaf1 /sbin/sysctl net.ipv4.conf.all.forwarding=1
sudo docker exec -it leaf2 /sbin/sysctl net.ipv4.conf.all.forwarding=1

7. Check, whether all Docker containers have started successfully

sudo docker container ls

Optional: Use this, if you’re looking for detailed information about running Docker containers (X is replaced by device/host number)

sudo docker container inspect [leaf[X] | bgp-rr | host[X]]

Preparing Ubuntu Environment

1. Get into the machine (X is replaced by device/host number)

sudo docker exec -it host[X] bash

2. Update the machine

apt-get update

3. Install the required packages

apt-get install iproute2
apt-get install iputils-ping

4. Exit the Docker Container (CTRL+D). Repeat steps 2 & 3.

Arista cEOS Switch configuration

Now, we will configure Arista cEOS switches. We will split the configuration of Arista cEOS Switches in several steps.

Click here for full configurations of Arista switches ‘leaf1‘ & ‘leaf2‘.

Ethernet interfaces & connectivity check

1. Go into the Arista switch leaf1

sudo docker exec -it leaf1 Cli

2. Set Privilege, and go to configure-mode

enable
configure terminal

3. Setup the switch’s name

hostname leaf1

4. Setup Ethernet interface. If you use more devices than your devices could be connected in another Ethernet

interface ethernet 2
no switchport
ip address 172.20.0.2/16

5. Check if BGP-RR is reachable from the configured interface.

  • When you can’t ping ‘BGP-RR’, check if ‘leaf1′ and ‘BGP-RR’ are located in the same Docker network, or delete the previous step and try it on another Ethernet interface.
ping 172.20.0.4 source ethernet2

6. Repeat Step 5 for ‘leaf2′ & go into the Arista switch leaf2

sudo docker exec -it leaf2 Cli
enable
config t
hostname leaf2
interface ethernet 2 
no switchport
ip address 172.20.0.3/16
ping 172.20.0.4 source ethernet2

Configuring the Border Gateway Protocol

We will have identical configurations for ‘leaf1′ & ‘leaf2′. Exceptions will be highlighted in the instructions below.

1. Enable BGP in Arista switch

  • If you are still in the previous settings interface, go to the root of Arista configuration with repeating the “exit” command.
service routing protocols model multi-agent
ip routing

2. Setup

  • For ‘leaf2’, use the Router-ID ‘router-id 172.20.0.3
router bgp 50
router-id 172.20.0.2
neighbor 172.20.0.4 remote-as 50
neighbor 172.20.0.4 next-hop-self
neighbor 172.20.0.4 send-community extended
redistribute connected
redistribute attached-host

3. Setup EVPN in BGP

address-family evpn
neighbor 172.20.0.4 activate

Configuring VxLAN Interface & VLAN

We will have identical configurations for leaf1 & leaf2. Exceptions will be highlighted in the instructions below.

1. Enable VLAN with ID 10.

  • Make sure that this command is typed in root of Arista and not in BGP
  • If you are still in the BGP configuration, use the command ‘exit’
vlan 10

2. Configure loopback 0, which will be used as a VTEP (VxLAN tunnel endpoint) for VxLAN.

  • In ‘leaf2’, use IP ‘10.10.10.2/32’, instead of IP ‘10.10.10.1/32’
interface loopback 0
ip address 10.10.10.1/32

3. Configure VxLAN Interface

  • Here we’ll set up loopback 0 as a VTEP and configure VNI (VXLAN Network Identifier) to 3322.
interface Vxlan1
vxlan source-interface Loopback0
vxlan udp-port 4789
vxlan vlan 10 vni 3322
vxlan learn-restrict any

4. Assign Ethernet interface to VLAN

interface Ethernet 1
switchport mode access
switchport access vlan 10

5. Share loopback 0 to BGP-RR

  • In ‘leaf2‘, use IP ‘10.10.10.2/32’ instead of ‘10.10.10.1/32’
router bgp 50
address-family ipv4
network 10.10.10.1/32

6. Configure VLAN in BGP

  • Here we share the information about VLAN to BGP-RR
router bgp 50
vlan 10
rd 50:3322
route-target both 10:3322
redistribute learned

lighty.io & BGP Route Reflector

In this part, we will add Border Gateway Protocol configuration into the lighty.io-BGP.

There is a lot to configure, so crucial parts are commented to break it down a little.

If we want to see the logs from lighty.io, we can attach them to the started container:

sudo docker attach bgp-rr

We can start the BGP-RR container with the command:

sudo docker start bgp-rr --attach

to see logs from the beginning. Afterward, send a PUT request to BGP-RR. We should see the following messages in the logs.

More RESTCONF commands can be found here.

Verify device state

Now, we will check if all configurations were set up successfully. We will also check if VxLAN is created and the Virtual PCs are able ‘ping’ each other.

1. Check if EVPN BGP peering is established

leaf1(config)#sh bgp evpn summary
BGP summary information for VRF default
Router identifier 172.20.0.2, local AS number 50
Neighbor Status Codes: m - Under maintenance
  Neighbor         V  AS           MsgRcvd   MsgSent  InQ OutQ  Up/Down State  PfxRcd PfxAcc
  172.20.0.4       4  50                 3         6    0    0 00:00:09 Estab  0      0
leaf2(config)#sh bgp evpn summary
BGP summary information for VRF default
Router identifier 172.20.0.3, local AS number 50
Neighbor Status Codes: m - Under maintenance
  Neighbor         V  AS           MsgRcvd   MsgSent  InQ OutQ  Up/Down State  PfxRcd PfxAcc
  172.20.0.4       4  50               267       315    0    0 00:01:16 Estab  1      1

If your devices are in the state ‘Connected‘ or ‘Active‘, then you have checked this right after you sent a request to lighty.io. Usually, it takes, at most, one minute to establish a connection.

If you still see this state, then there could be something wrong in the BGP configuration. Please check your configuration in Arista CLI, by typing command ‘show running-config‘ and compare it with the full Arista configuration above.

After you verify the Arista configuration, then there could be a problem in the BGP-RR container. This can be fixed restarting the BGP-RR container.

2. Check ip route for available loopbacks from other devices

leaf1(config)#sh ip route
VRF: default
Codes: C - connected, S - static, K - kernel,
       O - OSPF, IA - OSPF inter area, E1 - OSPF external type 1,
       E2 - OSPF external type 2, N1 - OSPF NSSA external type 1,
       N2 - OSPF NSSA external type2, B I - iBGP, B E - eBGP,
       R - RIP, I L1 - IS-IS level 1, I L2 - IS-IS level 2,
       O3 - OSPFv3, A B - BGP Aggregate, A O - OSPF Summary,
       NG - Nexthop Group Static Route, V - VXLAN Control Service,
       DH - DHCP client installed default route, M - Martian,
       DP - Dynamic Policy Route
 
Gateway of last resort is not set
 
 C      10.10.10.1/32 is directly connected, Loopback0
 B I    10.10.10.2/32 [200/0] via 172.20.0.3, Ethernet2
 C      172.20.0.0/16 is directly connected, Ethernet2
leaf2(config)#sh ip route
VRF: default
Codes: C - connected, S - static, K - kernel,
       O - OSPF, IA - OSPF inter area, E1 - OSPF external type 1,
       E2 - OSPF external type 2, N1 - OSPF NSSA external type 1,
       N2 - OSPF NSSA external type2, B I - iBGP, B E - eBGP,
       R - RIP, I L1 - IS-IS level 1, I L2 - IS-IS level 2,
       O3 - OSPFv3, A B - BGP Aggregate, A O - OSPF Summary,
       NG - Nexthop Group Static Route, V - VXLAN Control Service,
       DH - DHCP client installed default route, M - Martian,
       DP - Dynamic Policy Route
 
Gateway of last resort is not set
 
 B I    10.10.10.1/32 [200/0] via 172.20.0.2, Ethernet2
 C      10.10.10.2/32 is directly connected, Loopback0
 C      172.20.0.0/16 is directly connected, Ethernet2

3. Check the VxLAN interface, if it creates and contains VTEP

leaf1#sh interfaces vxlan 1
Vxlan1 is up, line protocol is up (connected)
  Hardware is Vxlan
  Source interface is Loopback0 and is active with 10.10.10.1
  Replication/Flood Mode is headend with Flood List Source: EVPN
 Remote MAC learning via EVPN
  VNI mapping to VLANs
  Static VLAN to VNI mapping is
    [10, 3322]      
  Note: All Dynamic VLANs used by VCS are internal VLANs.
        Use 'show vxlan vni' for details.
  Static VRF to VNI mapping is not configured
  Headend replication flood vtep list is:
    10 10.10.10.2    
  VTEP address mask is None
leaf2(config)#sh interfaces vxlan 1
Vxlan1 is up, line protocol is up (connected)
  Hardware is Vxlan
  Source interface is Loopback0 and is active with 10.10.10.2
  Replication/Flood Mode is headend with Flood List Source: EVPN
 Remote MAC learning via EVPN
  VNI mapping to VLANs
  Static VLAN to VNI mapping is
    [10, 3322]      
  Note: All Dynamic VLANs used by VCS are internal VLANs.
        Use 'show vxlan vni' for details.
  Static VRF to VNI mapping is not configured
  Headend replication flood vtep list is:
    10 10.10.10.1    
  VTEP address mask is None

If you don’t see IP in the section ‘Headend replication flood vtep list is:‘, then the BGP-RR container is not started correctly. This problem can be fixed by removing BGP-RR container and starting it again.

Restarting BGP-RR container

1. Stop the container

sudo docker stop bgp-rr

2. Remove BGP-RR container

sudo docker rm bgp-rr

3. Create a new container

sudo docker create --name=bgp-rr --privileged -e INTFTYPE=eth -it pantheontech/lighty-rr:9.2.0-dev

4. Connect BGP-RR to docker network

sudo docker network connect net3 bgp-rr

5. Start the container again

sudo docker start bgp-rr

Optional: If you want to see logs from light.io, attached them to the container:

sudo docker attach bgp-rr

Testing IP Connectivity

If everything worked out, we can test IP connectivity in a virtual PC.

1. Open Virtual PC host1

sudo docker exec -it host1 bash

2. Setup IP address for this device

ip addr add 31.1.1.1/24 dev eth1

3. Perform the same configuration at host2

sudo docker exec -it host1 bash
ip addr add 31.1.1.2/24 dev eth1

4. Try to ping host2 to host1

ping 31.1.1.1
root@e344ec43c089:/# ip route
default via 172.17.0.1 dev eth0
31.1.1.0/24 dev eth1 proto kernel scope link src 31.1.1.2
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.5
172.19.0.0/16 dev eth1 proto kernel scope link src 172.19.0.3
 
root@e344ec43c089:/# hostname -I
172.17.0.5 172.19.0.3 31.1.1.2
 
root@e344ec43c089:/# ping 31.1.1.1
PING 31.1.1.1 (31.1.1.1) 56(84) bytes of data.
64 bytes from 31.1.1.1: icmp_seq=1 ttl=64 time=114 ms
64 bytes from 31.1.1.1: icmp_seq=2 ttl=64 time=55.5 ms
64 bytes from 31.1.1.1: icmp_seq=3 ttl=64 time=53.0 ms
64 bytes from 31.1.1.1: icmp_seq=4 ttl=64 time=56.1 ms
^C
--- 31.1.1.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 53.082/69.892/114.757/25.929 ms

When we go back to the Arista switch, we can check routed MAC address information.

leaf1#sh mac address-table
          Mac Address Table
------------------------------------------------------------------
 
Vlan    Mac Address       Type        Ports      Moves   Last Move
----    -----------       ----        -----      -----   ---------
  10    0242.211d.8954    DYNAMIC     Et1        1       0:00:54 ago
  10    0242.8b29.b7ea    DYNAMIC     Vx1        1       0:00:40 ago
  10    0242.ac12.0003    DYNAMIC     Et1        1       0:00:14 ago
  10    0242.ac13.0003    DYNAMIC     Vx1        1       0:00:13 ago
  10    ce9a.ca0c.88a1    DYNAMIC     Et1        1       0:00:54 ago
Total Mac Addresses for this criterion: 5
 
          Multicast Mac Address Table
------------------------------------------------------------------
 
Vlan    Mac Address       Type        Ports
----    -----------       ----        -----
Total Mac Addresses for this criterion: 0
leaf2#sh mac address-table
          Mac Address Table
------------------------------------------------------------------
 
Vlan    Mac Address       Type        Ports      Moves   Last Move
----    -----------       ----        -----      -----   ---------
  10    0242.211d.8954    DYNAMIC     Vx1        1       0:00:48 ago
  10    0242.8b29.b7ea    DYNAMIC     Et1        1       0:01:03 ago
  10    0242.ac12.0003    DYNAMIC     Vx1        1       0:00:22 ago
  10    0242.ac13.0003    DYNAMIC     Et1        1       0:00:22 ago
  10    ce9a.ca0c.88a1    DYNAMIC     Vx1        1       0:00:48 ago
Total Mac Addresses for this criterion: 5
 
          Multicast Mac Address Table
------------------------------------------------------------------
 
Vlan    Mac Address       Type        Ports
----    -----------       ----        -----
Total Mac Addresses for this criterion: 0

Conclusion

We have successfully shown the lighty.io BGP functionality, which is able to replace legacy Route-Reflectors. This situation can be applied to telecom data-centers and other use-cases. It demonstrates lighty.io’s versatility and usability. Contact us for more information!

Peter Šuňa & Peter Lučanský


You can contact us at https://pantheon.tech/

Explore our Pantheon GitHub.

Watch our YouTube Channel.