End to End EPIPE Service Configuration

Overview

This tutorial is to create a point-to-point Layer 2 service. It also performs an OAM test to ensure the service is correctly configured and applies statistics collection to monitor performance.

The basic steps are:

  • Configure ports for service creation
  • Create an L2 EPIPE service between two network elements
  • Create and execute CFM Loopback test to verify service configuration
  • Enable egress queue statistics for ongoing service monitoring

Prerequisites

This tutorial requires at least two model driven SROS based network elements that have been discovered by NSP. There must be a MPLS topology connecting the nodes, including LSPs and Paths. The examples require that the hardware port 1/1/10 are available on both nodes and can be configured as ethernet access ports with Dot1Q encapsulation.

Release

This tutorial has been tested with and is supported in NSP 23.8

Postman

All steps in this tutorial are provided in the End to End EPIPE Service Tutorial Postman Collection. Example responses for each request are also included.

The collection can be run using "Postman Runner" to perform the complete configuration. The following environment variables must be defined in order to run the collection:

  • server -- IP address of NSP server
  • user -- NSP OSS user
  • password -- password for the user
  • nodeA -- Router ID of first network element
  • nodeB -- Router ID of second network element
  • portA -- Port ID of first EPIPE SAP
  • portB -- Port ID of second EPIPE SAP
  • lspAtoB -- name of LSP path from node A to node B
  • lspBtoA -- name of LSP path from node B to node A

Where required, "tests" have been provided in the Postman examples that retrieve identifiers from results that are used in subsequent requests. Tests have also been provided that retry certain requests for polling purposes (i.e. retrying until the service is in a fully deployed state) or that introduce a slight delay to ensure objects are created and propagated through the system.

Artifacts

The following artifacts from ALED are required to run this tutorial:

  • Telemetry model
  • EPIPE predefined intent type
  • ICM access port predefined intent type

Disclaimer

This tutorial is meant as a proof of concept and as an example method for configuring a service. It is not designed to be implemented, and must not be used as is, in a production network. It is intended to guide development of an OSS.

Kafka

Many of the requests for this tutorial are asynchronous, meaning a response is received before the request has been fully processed. For the purposes of the Postman collection, polling is used to monitor the creation of objects and their current status.

Instead of polling, an application can use Kafka notifications to monitor these events. Where applicable, example notifications are provided below in order to facilitate a Kafka integration.

For further details on using Kafka, see Kafka Notification Service

Tutorial

Install required intent types

This tutorial makes use of two intent types:

  • EPIPE predefined intent type
  • ICM access port intent type

Both need to be imported into Intent Manager. The EPIPE IT is subsequently imported into service fulfillment and the ICM IT are imported into Intent Configuration Manager. Before executing the Postman examples for this step they must be updated to point to files on the local file system.

Intent types for EPIPEs, Service Tunnels, Access Ports can be imported into Intent Manager with the "import" API:

POST /mdt/rest/ibn/import HTTP/1.1
Content-Disposition: form-data; name=""; filename="epipe_2308.zip"
Content-Type: application/zip

The EPIPE and Service Tunnel intent types need to be exported to Service Fulfillment using the "exportToIbsf" API:

POST /mdt/exportToIbsf/epipe/2 HTTP/1.1

The Access Port intent type can be imported to ICM using the import-intent-types API:

POST /restconf/operations/nsp-icm:import-intent-types HTTP/1.1

{
    "input": {
        "imported-intent-types": [
            {
                "name": "icm-equipment-port-access",
                "version": 2
            }
        ]
    }
}

Load data sync mapping files

In order to synchronize services between the network and service fulfillment, data mapping files are required to be installed. The mapping files are part of the predefined intents and can be installed using the command line from the deployer host.

.../tools/mdm/bin/json-files.bash --user admin --pass NokiaNsp1! --add ...pathTo/intentType/data-sync-mapping/MDM/MDC/Sros/operational-model/

Load telemetry yang files

The NSP is preinstalled with a limited number of statistics that can be augmented by adding the yang model that represents the statistics of interest. This can be done by using the API, with reference to the corresponding yang file.

.../tools/mdm/bin/json-files.bash --user admin --pass NokiaNsp1! --add .../pathTo/telemetryMapping
.../tools/mdm/bin/yang-files.bash --user admin --pass NokiaNsp1! --add .../pathTo/telemetryMapping/sros/sros-service-vprn-telemetry.yang --modulesetname telemetry

Create workflow to "admin up" ports

Service fulfillment has the capability to run a workflow at various stages in the service lifecycle. This tutorial uses that functionality to administratively enable the endpoint ports before creating the service. This step is to create and publish the workflow that sets the admin state on the network element.

For the purposes of this tutorial it is assumed that access ports are administratively disabled until services are provisioned to them.

The "workflow" API accepts as input a YAML document that describes the workflow. The adminUpPort workflow iterates over the endpoints of the service being configured and sends a netconf request to each applicable node in order to administratively enable the access ports:

POST /wfm/api/v1/workflow HTTP/1.1

{
    "yaml": "version: '2.0'\n\nadminUpPort_Epipe:\n  type: direct\n\n  input:\n    - serviceName\n    - payload\n    - intentType\n    - user: \"admin\"\n    - pass: \"admin\"\n    - token_auth: \"\"\n    \n  tags:\n    - ServiceFulfillment\n  \n  vars:\n    restconfUrl: https://restconf-gateway/restconf\n\n  tasks:\n    findPorts:\n      with-items: neId in <% [$.payload[\"nsp-service-intent:intent\"][0][\"intent-specific-data\"][\"epipe:epipe\"][\"site-a\"], $.payload[\"nsp-service-intent:intent\"][0][\"intent-specific-data\"][\"epipe:epipe\"][\"site-b\"]] %>\n      action: nsp.https\n      input:\n        method: POST\n        url: <% $.restconfUrl %>/operations/nsp-inventory:find\n        body:\n          input:\n            xpath-filter: \"/nsp-equipment:network/network-element[ne-id='<% $.neId[\\\"device-id\\\"] %>']/hardware-component/port\"\n            depth: \"2\"\n            fields: \"ne-id;name\"\n      publish:\n        portData: <% task().result.content %>\n      on-success: getPorts\n      \n    getPorts:\n      action: nsp.python\n      input:\n        context: \n          payload: <% $.payload[\"nsp-service-intent:intent\"][0][\"intent-specific-data\"][\"epipe:epipe\"] %>\n          portDataA: <% $.portData[0][\"nsp-inventory:output\"][\"data\"] %>\n          portDataB: <% $.portData[1][\"nsp-inventory:output\"][\"data\"] %>\n        script: |\n          import urllib.parse\n          epList = []\n          epDetails = {}\n          epSources = {}\n          \n          siteA = context[\"payload\"][\"site-a\"]\n          siteB = context[\"payload\"][\"site-b\"]\n          \n          for port in context[\"portDataA\"]:\n           id = port[\"ne-id\"] + \":\" + port[\"name\"].replace(\"Port \",\"\")\n           epDetails[id] = port[\"@\"][\"nsp-model:identifier\"]\n           epSources[id] = port[\"@\"][\"nsp-model:sources\"][0]\n\n          for port in context[\"portDataB\"]:\n            id = port[\"ne-id\"] + \":\" + port[\"name\"].replace(\"Port \",\"\")\n            epDetails[id] = port[\"@\"][\"nsp-model:identifier\"]\n            epSources[id] = port[\"@\"][\"nsp-model:sources\"][0]\n            \n          for ep in [siteA, siteB]:\n            epItem = {}\n            epItem[\"site\"] = ep[\"device-id\"]\n            epItem[\"port\"] = ep[\"endpoint\"][0][\"port-id\"]\n            id = ep[\"device-id\"] + \":\" + ep[\"endpoint\"][0][\"port-id\"].replace(\"Port \",\"\")\n            epItem[\"targetIdentifierValue\"] = epDetails[id]\n            epItem[\"targetIdentifierValueEncoded\"] = urllib.parse.quote(epDetails[id], safe='')\n            \n            if \"realm:sam\" in epSources[id]:           \n              epItem[\"targetPort\"] = ep[\"endpoint\"][0][\"port-id\"]\n              epItem[\"targetPortEncoded\"] = urllib.parse.quote(ep[\"endpoint\"][0][\"port-id\"], safe='')\n            else:\n              epItem[\"targetPort\"] = ep[\"endpoint\"][0][\"port-id\"].replace(\"Port \",\"\")\n              epItem[\"targetPortEncoded\"] = urllib.parse.quote(ep[\"endpoint\"][0][\"port-id\"].replace(\"Port \",\"\"), safe='')\n              \n            epList.append(epItem)\n            \n          return epList\n            \n      publish:\n        epList: <% task().result %>\n      on-success: getPortIntent\n  \n    getPortIntent:\n      with-items: id in <% $.epList %>\n      action: nsp.https   \n      input:\n        method: GET\n        url: <% $.restconfUrl %>/data/nsp-icm:icm/deployments/deployment=Default%20Port,<% $.id.targetIdentifierValueEncoded %>,<% $.id.targetPortEncoded %>\n\n      publish:\n        portIntents: <% task().result %>\n      on-success: updatePortIntent\n    \n    updatePortIntent:\n      with-items: id in <% $.portIntents %>\n      action: nsp.https\n      input:\n        method: POST\n        url: <% $.restconfUrl %>/operations/nsp-icm:update-deployments\n        body:\n          input:\n            deployments:\n            - template-name: '<% $.id.content[\"nsp-icm:deployment\"][0][\"template-name\"] %>'\n              target-data: '<% $.id.content[\"nsp-icm:deployment\"][0][\"target-data\"].replace(\"\\\"admin-state\\\":\\\"disable\\\"\",\"\\\"admin-state\\\":\\\"enable\\\"\") %>'\n              targets:\n               - target: '<% $.id.content[\"nsp-icm:deployment\"][0][\"target\"] %>'\n                 target-identifier-value: '<% $.id.content[\"nsp-icm:deployment\"][0][\"target-identifier-value\"] %>'\n              deployment-action: deploy\n              merge: true\n\n      publish:\n        result: <% task().result %>\n\n      \n\n      \n\n    \n\n\n\n"
}

Before it can be executed, the workflow must be published, which can be done with the "status" API:

PUT /wfm/api/v1/workflow/{{workflowId}}/status HTTP/1.1

{
  "status": "PUBLISHED"
}

Configure ports as access ports

In order to configure services on a port they must first be configured as access (or hybrid) ports with the required ethernet parameters. ICM will be used to configure the access ports with:

  • Dot1Q encapsulation
  • speed of 100Mbps
  • MTU 1492
  • auto-negotiate limited
  • administrative state disabled

Use the "templates" API to create a configuration template that will allow for Access Port configuration:

POST /restconf/data/nsp-icm:icm/templates/ HTTP/1.1

{
    "template": [
        {
            "name": "Default Port",
            "description": "Configure an access port",
            "life-cycle-state": "released",
            "intent-type": "icm-equipment-port-access",
            "intent-type-version": 2,
            "schema-form-name": "default.schemaForm"
        }
    ]
}

Use the " /nsp-equipment:network/network-element/hardware-component/port" API to retrieve the "nsp-model:identifier" and "component-id" of the Access Ports.

GET /restconf/data/nsp-equipment:network/network-element=92.168.96.61/hardware-component/port?fields=ne-id;name;component-id HTTP/1.1
GET /restconf/data/nsp-equipment:network/network-element=92.168.96.17/hardware-component/port?fields=ne-id;name;component-id HTTP/1.1

Use the "create-deployments" API to deploy the correct access port configuration to the nodes:

POST /restconf/operations/nsp-icm:create-deployments HTTP/1.1

{
    "input": {
        "deployments": [
            {
                "deployment-action": "deploy",
                "template-name": "Default Port",
                "target-data": "{\"port\":{\"description\":null,\"ethernet\":{\"dot1q-etype\":null,\"pbb-etype\":null,\"qinq-etype\":null,\"speed\":\"100\",\"hold-time\":{},\"down-when-looped\":{},\"lldp\":{\"dest-mac\":[]},\"autonegotiate\":\"limited\",\"encap-type\":\"dot1q\",\"mtu\":1492,\"mode\":\"access\"},\"admin-state\":\"disable\"}}",
                "targets": [
                    {
                        "target": "/nsp-equipment:network/network-element[ne-id='92.168.96.61']/hardware-component/port[component-id='shelf=1/cardSlot=1/card=1/mdaSlot=1/mda=1/port=1/1/c1/breakout-port=1/1/c1/10']",
                        "target-identifier-value": "1/1/c1/10"
                    },
                    {
                        "target": "/nsp-equipment:network/network-element[ne-id='92.168.96.17']/hardware-component/port[component-id='shelf=1/cardSlot=1/card=1/mdaSlot=1/mda=1/port=1/1/c1/breakout-port=1/1/c1/10']",
                        "target-identifier-value": "1/1/c1/10"
                    }
                ]
            }
        ]
    }
}

Creating deployments can take a significant amount of time, especially if many ports are being configured at once. Kafka notifications can be used to monitor when each port has been aligned with the intended configuration and that the configuration is correct.

{
   "nsp-model-notification:object-modification": {
      "changes": [
         {
            "name": "status",
            "old-value": "intent-aligning",
            "new-value": "intent-aligned"
         },
         {
            "name": "message",
            "old-value": "alignment started",
            "new-value": "Alignment Successful"
         },
         {
            "name": "detailed-message",
            "old-value": "alignment started",
            "new-value": "Alignment Successful"
         },
         {
            "name": "deployment-status",
            "old-value": "aligning",
            "new-value": "deployed-aligned"
         },
         {
            "name": "deployment-status-message",
            "old-value": "alignment is in progress",
            "new-value": "Alignment Successful"
         },
         {
            "name": "last-modified-time",
            "old-value": "2022-11-22T14:37:16.193Z",
            "new-value": "2022-11-22T14:37:20.454Z"
         },
         {
            "name": "align-end-time",
            "old-value": "2022-11-22T14:37:16.193Z",
            "new-value": "2022-11-22T14:37:20.454Z"
         }
      ],
      "schema-nodeid": "/nsp-icm:icm/deployments/deployment",
      "instance-id": "/nsp-icm:icm/deployments/deployment[template-name='Default Port'][target='/nsp-equipment:network/network-element[ne-id='92.168.96.46']/hardware-component/port[component-id='shelf=1/cardSlot=1/card=1/mdaSlot=1/mda=1/port=1/1/10']'][target-identifier-value='1/1/10']",
      "context": "nsp-infra-config-server-app",
      "tree": {
         "/nsp-icm:icm/deployments/deployment": {
            "@": {
               "nsp-model:schema-nodeid": "/nsp-icm:icm/deployments/deployment",
               "nsp-model:identifier": "/nsp-icm:icm/deployments/deployment[template-name='Default Port'][target='/nsp-equipment:network/network-element[ne-id='92.168.96.46']/hardware-component/port[component-id='shelf=1/cardSlot=1/card=1/mdaSlot=1/mda=1/port=1/1/10']'][target-identifier-value='1/1/10']"
            }
         }
      },
      "event-time": "2022-11-22T14:37:20.475Z"
   }
}
{
   "nsp-model-notification:object-modification": {
      "changes": [
         {
            "name": "encap-type",
            "old-value": "nullEncap",
            "new-value": "qinq"
         },
         {
            "name": "mtu-value",
            "old-value": "null",
            "new-value": "1492"
         },
         {
            "name": "port-index",
            "old-value": "10",
            "new-value": "11"
         },
         {
            "name": "port-mode",
            "old-value": "trunk",
            "new-value": "access"
         },
         {
            "name": "rate",
            "old-value": "null",
            "new-value": "100"
         }
      ],
      "schema-nodeid": "/nsp-equipment:network/network-element/hardware-component/port/port-details",
      "instance-id": "/nsp-equipment:network/network-element[ne-id='92.168.96.46']/hardware-component/port[component-id='shelf=1/cardSlot=1/card=1/mdaSlot=1/mda=1/port=1/1/10']/port-details",
      "context": "nsp-db-synchronizer",
      "tree": {
         "/nsp-equipment:network/network-element/hardware-component/port/port-details": {
            "@": {
               "nsp-model:schema-nodeid": "/nsp-equipment:network/network-element/hardware-component/port/port-details",
               "nsp-model:identifier": "/nsp-equipment:network/network-element[ne-id='92.168.96.46']/hardware-component/port[component-id='shelf=1/cardSlot=1/card=1/mdaSlot=1/mda=1/port=1/1/10']/port-details",
               "nsp-model:sources": [
                  "fdn:yang:nsp-network:/nsp-network:network/node[node-id='92.168.96.46']/node-root/nokia-state:state/port[port-id='1/1/10']",
                  "fdn:app:mdm-ami-cmodel:92.168.96.46:equipment:PortDetails:/port[port-id='1/1/10']",
                  "fdn:yang:nsp-network:/nsp-network:network/node[node-id='92.168.96.46']/node-root/nokia-conf:configure/port[port-id='1/1/10']"
               ]
            },
            "rate": "100",
            "port-mode": "access",
            "actual-rate-units": "mbps",
            "mtu-value": 1492,
            "duplex": "unknown",
            "port-type": "ethernet-port",
            "auto-negotiate": "unknown",
            "operational-duplex": "unknown",
            "port-index": 11,
            "actual-rate": 0,
            "encap-type": "qinq"
         }
      },
      "event-time": "2022-11-22T14:37:21.844Z"
   }
}

Create service artifacts

Before service creation, the following must also be configured:

  • service tunnels between the endpoint nodes
  • customer for service ownership

Service tunnels are created by first configuring a tunnel template using the "templates" API:

POST /restconf/data/tunnel-template:templates HTTP/1.1

{
    "template": [
        {
            "name": "TunnelTemplate",
            "description": "This is a service template for creating Service Tunnels",
            "intent-type": "tunnel",
            "intent-version": 2,
            "state": "released",
            "ui-config": "default",
            "workflows": []
        }
    ]
}

The service tunnel is then created using the "intent-base" API (note this step is done twice, with endpoints reversed, as tunnels are required in both directions of the two site EPIPE that is being created):

POST /restconf/data/nsp-tunnel-intent:intent-base HTTP/1.1

{
    "nsp-tunnel-intent:intent": [
        {
            "source-ne-id": "{{nodeA}}",
            "sdp-id": "50",
            "intent-type": "tunnel",
            "intent-type-version": "2",
            "olc-state": "deployed",
            "template-name": "TunnelTemplate",
            "intent-specific-data": {
                "tunnel:tunnel": {
                    "destination-ne-id": "{{nodeB}}",
                    "admin-state": "unlocked",
                    "transport-type": "mpls",
                    "signaling": "tldp",
                    "mpls": {
                        "mixed-lsp-mode": false,
                        "enable-ldp": false,
                        "enable-bgp-tunnel": false,
                        "sr-isis": false,
                        "sr-ospf": false,
                        "lsp": "{{lspAtoB}}"
                    },
                    "hello-parameters": {
                        "keep-alive-enabled": false
                    },
                    "name": "SDP50"
                }
            }
        }
    ]
}

Service tunnels are created asynchronously, so the response will be received before the request is fully processed. The Postman collection has implemented a delay to wait for the service tunnel to be created, but Kafka notifications also indicate when the tunnels have been successfully deployed. The following notification is an example of a service tunnel being updated to "deployed" after it has been configured in the network:

{
   "nsp-model-notification:object-modification": {
      "changes": [
         {
            "name": "last-updated-time",
            "old-value": "2022-11-22T14:24:57.153Z",
            "new-value": "2022-11-22T14:25:01.579Z"
         },
         {
            "name": "occurred-at",
            "old-value": "2022-11-22T14:24:57.153Z",
            "new-value": "2022-11-22T14:25:01.579Z"
         },
         {
            "name": "from-state",
            "old-value": "saved",
            "new-value": "planned"
         },
         {
            "name": "to-state",
            "old-value": "planned",
            "new-value": "deployed"
         },
         {
            "name": "logs",
            "old-value": [
               "Successfully updated the tunnel slc state from saved to planned"
            ],
            "new-value": [
               "Successfully deployed tunnel to network",
               "Successfully updated the tunnel slc state from planned to deployed"
            ]
         }
      ],
      "schema-nodeid": "/nsp-service:services/tunnel-layer/mpls-tunnel/service-extension:mpls-tunnel-ext/slc-details",
      "instance-id": "/nsp-service:services/tunnel-layer/mpls-tunnel[id='5000'][source-ne-id='92.168.96.46']/service-extension:mpls-tunnel-ext/slc-details",
      "context": "sf_app",
      "tree": {
         "/nsp-service:services/tunnel-layer/mpls-tunnel/service-extension:mpls-tunnel-ext/slc-details": {
            "@": {
               "nsp-model:schema-nodeid": "/nsp-service:services/tunnel-layer/mpls-tunnel/service-extension:mpls-tunnel-ext/slc-details",
               "nsp-model:identifier": "/nsp-service:services/tunnel-layer/mpls-tunnel[id='5000'][source-ne-id='92.168.96.46']/service-extension:mpls-tunnel-ext/slc-details",
               "nsp-model:sources": []
            }
         }
      },
      "event-time": "2022-11-22T14:25:01.640Z"
   }
}

The "customers" API is used to create the customer:

POST /restconf/data/nsp-customer:customers HTTP/1.1

{
    "customer": [
        {
            "id" : 25,
            "name" : "Sample Customer",
            "description" : "Customer for tutorial purposes",
            "phone-number" : "1-800-555-1234",
            "contact" : "Customer Name"
        }
   ]
}

Create service

Similar to creating a service tunnel, the service requires both a template and a service. The "templates" API can be used to create the service template:

POST /restconf/data/service-template:templates HTTP/1.1

{
    "template": [
        {
            "name": "EPIPETemplate",
            "description": "This is a service template used for creating services via API",
            "intent-type": "epipe",
            "intent-version": 2,
            "state": "released",
            "ui-config": "default",
            "workflows": [
                {
                    "service-lifecycle-state": "saved",
                    "service-lifecycle-case": "success",
                    "workflow-id": "adminUpPort_Epipe",
                    "blocking": true,
                    "execution-timeout": 60
                }
            ]
        }
    ]
}

The "intent-base" API is then used to create the service itself:

POST /restconf/data/nsp-service-intent:intent-base HTTP/1.1

{
    "nsp-service-intent:intent": [
        {
            "service-name": "epipe tutorial",
            "intent-type": "epipe",
            "intent-type-version": "2",
            "olc-state": "deployed",
            "template-name": "EPIPETemplate",
            "intent-specific-data": {
                "epipe:epipe": {
                    "site-a": {
                        "endpoint": [
                            {
                                "enable-filter": false,
                                "inner-vlan-tag": -1,
                                "ingress": {},
                                "outer-vlan-tag": 400,
                                "port-id": "Port 1/1/c1/10",
                                "admin-state": "unlocked",
                                "enable-qos": false,
                                "collect-stats": true,
                                "accounting-policy-id": 20,
                                "egress": {}
                            }
                        ],
                        "device-id": "92.168.96.61",
                        "mtu": 1400
                    },
                    "customer-id": 25,
                    "site-b": {
                        "endpoint": [
                            {
                                "enable-filter": false,
                                "inner-vlan-tag": -1,
                                "ingress": {},
                                "outer-vlan-tag": 400,
                                "port-id": "Port 1/1/c1/10",
                                "admin-state": "unlocked",
                                "enable-qos": false,
                                "collect-stats": true,
                                "accounting-policy-id": 20,
                                "egress": {}
                            }
                        ],
                        "device-id": "92.168.96.17",
                        "mtu": 1400
                    },
                    "description": "epipe tutorial",
                    "admin-state": "unlocked",
                    "ne-service-id": 400,
                    "sdp-details": {
                        "sdp": [
                            {
                                "vc-type": "ether",
                                "source-device-id": "92.168.96.61",
                                "destination-device-id": "92.168.96.17",
                                "sdp-id": "50",
                                "admin-state": "unlocked",
                                "override-vc-id": false
                            },
                            {
                                "vc-type": "ether",
                                "source-device-id": "92.168.96.17",
                                "destination-device-id": "92.168.96.61",
                                "sdp-id": "50",
                                "admin-state": "unlocked",
                                "override-vc-id": false
                            }
                        ]
                    },
                    "mtu": 1400
                }
            }
        }
    ]
}

Poll the service to determine it's status, and when it is fully configured:

GET /restconf/data/nsp-service:services/service-layer/eline=epipe%20tutorial?fields=service-extension:eline-svc/slc-state HTTP/1.1

Instead of polling for successful service creation, Kafka notifications can be monitored to confirm that the service lifecycle state enters the "deployed" state. If there are errors during deployment, the "logs" attribute in this same notification will indicate what errors occurred:

{
  "nsp-model-notification:object-modification": {
    "changes": [
      {
        "name": "last-audited-by",
        "old-value": null,
        "new-value": "admin"
      },
      {
        "name": "last-audited-time",
        "old-value": null,
        "new-value": "2023-09-14T09:35:51.241850Z"
      },
      {
        "name": "logs",
        "old-value": [
          "Successfully updated the service slc state from planned to deployed",
          "Successfully deployed service to network"
        ],
        "new-value": [
          "Successfully updated the service slc state from planned to deployed",
          "Successfully deployed service to network",
          "Successfully completed service audit at 2023-09-14T09:35:51.246997Z"
        ]
      }
    ],
    "schema-nodeid": "/nsp-service:services/service-layer/eline/service-extension:eline-svc/slc-details",
    "instance-id": "/nsp-service:services/service-layer/eline[service-id\u003d\u0027epipe tutorial\u0027]/service-extension:eline-svc/slc-details",
    "context": "sf_app",
    "tree": {
      "/nsp-service:services/service-layer/eline/service-extension:eline-svc/slc-details": {
        "@": {
          "nsp-model:schema-nodeid": "/nsp-service:services/service-layer/eline/service-extension:eline-svc/slc-details",
          "nsp-model:identifier": "/nsp-service:services/service-layer/eline[service-id\u003d\u0027epipe tutorial\u0027]/service-extension:eline-svc/slc-details",
          "nsp-model:sources": []
        }
      }
    },
    "event-time": "2023-09-14T09:35:51.280327Z"
  }
}

Run OAM test

A CFM OAM test can be executed to validate that the service was correctly configured and that traffic is passing through it. At this time, CFM MD, MA and MEPs must be manually created on each service site.

Use the "oam-pm" API to create bin groups:

POST /restconf/data/nsp-oam-config:oam-pm HTTP/1.1

{
    "bin-groups": [
        {
            "bin-group-id": 21,
            "ne-id": "92.168.96.61",
            "admin-state": "enable",
            "deployment-asynchronous": false,
            "description": "certMD-OAM-BG21",
            "bin-type": [
                {
                    "bin-metric": "fd",
                    "delay-event": [
                        {
                            "direction": "forward",
                            "lowest-bin": 2,
                            "raise-threshold": 4321,
                            "clear-threshold": 1234,
                            "exclude-lowest-bin": 3
                        }
                    ],
                    "bin": [
                        {
                            "bin-number": 2,
                            "lower-bound": 5500
                        },
                        {
                            "bin-number": 3,
                            "lower-bound": 6000
                        }
                    ]
                }
            ]
        }
    ]
}

Create CFM maintenance domains on both sites:

POST /restconf/data/nsp-eth-cfm-config:eth-cfm HTTP/1.1

{
    "domain" :  
        [{
            "deployment-asynchronous": "true",
            "ne-id" : "92.168.96.61",
            "md-admin-name":"CFM_MD_epipe_tutorial",
            "md-index":"99714",
            "level" : 4,
            "name" : "MD_epipe_tutorial"           
        }]          
}
POST /restconf/data/nsp-eth-cfm-config:eth-cfm HTTP/1.1

{
    "domain" :  
        [{
            "deployment-asynchronous": "true",
            "ne-id" : "92.168.96.17",
            "md-admin-name":"CFM_MD_epipe_tutorial",
            "md-index":"99715",
            "level" : 4,
            "name" : "MD_epipe_tutorial"           
        }]          
}

Create CFM maintenance associations on each site:

POST /restconf/data/nsp-eth-cfm-config:eth-cfm/domain=92.168.96.61,CFM_MD_epipe_tutorial/ HTTP/1.1

{
    "association": [
        {
            "ma-admin-name": "CFM_MA_epipe_tutorial",
            "string": "CFM_MA_epipe_tutorial",
            "temporary": false,
            "ccm-interval": "10s",
            "ma-index":"77162",
            "auto-mep-discovery": true,
            "facility-id-permission": "none",
            "bridge-identifier": [
                {
                    "bridge-name": "epipe_tutorial_bridge",
                    "mip-ltr-priority": 7
                }
            ]
        }
    ]
}
POST /restconf/data/nsp-eth-cfm-config:eth-cfm/domain=92.168.96.17,CFM_MD_epipe_tutorial/ HTTP/1.1

{
    "association": [
        {
            "ma-admin-name": "CFM_MA_epipe_tutorial",
            "string": "CFM_MA_epipe_tutorial",
            "temporary": false,
            "ccm-interval": "10s",
            "ma-index":"77163",
            "auto-mep-discovery": true,
            "facility-id-permission": "none",
            "bridge-identifier": [
                {
                    "bridge-name": "epipe_tutorial_bridge",
                    "mip-ltr-priority": 7
                }
            ]
        }
    ]
}

Create CFM MEPs on both sites:

POST /restconf/data/nsp-eth-cfm-config:eth-cfm/domain=92.168.96.61,CFM_MD_epipe_tutorial/association=CFM_MA_epipe_tutorial HTTP/1.1

{
    "mep": [
        {
            "mep-id": 16,
            "direction": "up",
            "service-type": "eline",
            "service-name": "epipe tutorial",
            "mac-address": "C6-86-01-01-00-0A",
            "install-mep": "false",
            "admin-state": "enable",
            "ccm": "true"
        }
    ]
}
POST /restconf/data/nsp-eth-cfm-config:eth-cfm/domain=92.168.96.17,CFM_MD_epipe_tutorial/association=CFM_MA_epipe_tutorial HTTP/1.1

{
    "mep": [
        {
            "mep-id": 17,
            "direction": "up",
            "service-type": "eline",
            "service-name": "epipe tutorial",
            "mac-address": "C6-4E-01-01-00-0A",
            "install-mep": "false",
            "admin-state": "enable",
            "ccm": "true"
        }
    ]
}

CFM Loopback test

The "oam-test" API is used to create a CFM Loopback test:

POST /restconf/data/nsp-oam:tests/oam-test:tests HTTP/1.1

{
    "cfm-loopback": [
        {
            "deployment-asynchronous": false,
            "template": "/nsp-oam:templates/oam-test:templates/cfm-loopback[name='Quick Validate (on-demand)']",
            "md-name": "MD_epipe_tutorial",
            "level": 6,
            "ma-name": "CFM_MA_epipe_tutorial",
            "reuse-existing-mep": true,
            "source-mep-id": "16",
            "remote-mep-id": "17",
            "sap-mep-direction": "up",
            "binding-mep-direction": "down",
            "test-id": "15",
            "priority": 0,
            "timeout": 5,
            "interval": 1,
            "probe-count": 5,
            "app-id": "NSP",
            "execute-type": "on-demand",
            "bulk-result": null,
            "notify-target-ne": "never",
            "name": "testAB",
            "description": null,
            "entities": [
                {
                    "entity-type": "source",
                    "entity-reference": "/nsp-service:services/service-layer/eline[service-id='epipe tutorial']/endpoint[endpoint-id='92.168.96.61-1/1/c1/10:400']"
                },
                {
                    "entity-type": "destination",
                    "entity-reference": "/nsp-service:services/service-layer/eline[service-id='epipe tutorial']/endpoint[endpoint-id='92.168.96.17-1/1/c1/10:400']"
                }
            ],
            "domain": {
                "name": "TEMP_CFM"
            },
            "association": {
                "string": "srv:epipe tutorial"
            }
        }
    ]
}

The "tests" API can be used to execute the on-demand CFM Loopback test:

POST /restconf/data/nsp-oam:tests/oam-test:tests/cfm-loopback=92.168.96.61,testAB/start HTTP/1.1

{
    "input": {
        "publish-results": "true",
        "test-timeout": "90",
        "result-classifier": "default",
        "sync-mode": "sync-execute",
        "stop-test-after-result": "false",
        "extra-fields-profile": "default"
    }
}

Retrieve the results of the execution using the "get-results" API:

POST /restconf/data/nsp-oam:tests/oam-test:tests/cfm-loopback=92.168.96.61,testAB/get-results HTTP/1.1

{
    "input": {
        "limit": 1
    }
}

Response:

{
    "nsp-oam:output": {
        "max-time-captured": "2023-09-14T10:12:32.298Z[GMT]",
        "result": [
            {
                "time-captured": "1694686352298",
                "test-id": "15",
                "target-hw-mac-address": "",
                "reason": "",
                "execution-id": "69",
                "service-id": "epipe tutorial",
                "probes-sent": "5",
                "source-mep-id": "16",
                "forward-sum-of-squares": "0",
                "probes-lost": "0",
                "execute-type": "on-demand",
                "forward-average": "0",
                "loss-ratio": "0.00",
                "ma-name": "",
                "two-way-min": "0",
                "forward-max": "0",
                "app-id": "NSP",
                "backward-average": "0",
                "remote-mep-id": "17",
                "source-hw-mac-address": "",
                "two-way-average-jitter": "0",
                "forward-min": "0",
                "probes-received": "5",
                "system-id": "92.168.96.61",
                "outbound-jitter": "0",
                "oam-test-name": "testAB",
                "two-way-min-jitter": "0",
                "time-issued": "1694686352309",
                "node-id": "92.168.96.61",
                "two-way-average": "0",
                "backward-max": "0",
                "time-logged": "1694686352297",
                "result-status": "success",
                "destination-ne-id": "",
                "two-way-max": "0",
                "cfm-target": "",
                "two-way-max-jitter": "0",
                "dest-mac-address": "",
                "md-name": "",
                "backward-min": "0",
                "result-classification": "PASS",
                "owner": "",
                "backward-sum-of-squares": "0",
                "test-path": "/nsp-oam:tests/oam-test:tests/cfm-loopback[ne-id='92.168.96.61'][name='testAB']",
                "test-suite": "",
                "message": "",
                "two-way-sum-of-squares": "0",
                "time-captured-periodic": "596503",
                "inbound-jitter": "0",
                "ts-execution-id": "0",
                "service": "/nsp-service:services/service-layer/eline[service-id='epipe tutorial']",
                "object-id": "/execute-cfm-loopback/output",
                "kpiType": "telemetry:/base/oam-result/loopback-result",
                "dataType": "1"
            }
        ],
        "min-time-captured": "2023-09-14T10:12:32.298Z[GMT]",
        "count": 1
    },
    "statusCode": "OK"
}

Results of executing test suites are also notified to the oam.test_execution

Kafka topic:

{
  "time-issued" : "1694685755809",
  "app-id" : "NSP",
  "test-id" : "15",
  "node-id" : "92.168.96.61",
  "execution-id" : "67",
  "service-id" : "epipe tutorial",
  "probes-sent" : "5",
  "source-mep-id" : "16",
  "time-logged" : "1694685755774",
  "result-status" : "success",
  "probes-lost" : "0",
  "execute-type" : "on-demand",
  "loss-ratio" : "0.0",
  "oam-nsp-class-id" : "telemetry:/base/oam-result/loopback-result",
  "result-classification" : "PASS",
  "owner" : null,
  "test-path" : "/nsp-oam:tests/oam-test:tests/cfm-loopback[ne-id='92.168.96.61'][name='testAB']",
  "remote-mep-id" : "17",
  "time-captured-periodic" : "0",
  "probes-received" : "5",
  "system-id" : "92.168.96.61",
  "service" : "/nsp-service:services/service-layer/eline[service-id='epipe tutorial']",
  "time-captured" : "1694685755795",
  "oam-test-name" : "testAB",
  "object-id" : "/execute-cfm-loopback/output"
}

Clean up the test artifacts by deleting the test, temporary CFM objects:

DELETE /restconf/data/nsp-oam:tests/oam-test:tests/cfm-loopback=92.168.96.61,testAB HTTP/1.1
DELETE /restconf/data/nsp-eth-cfm-config:eth-cfm/domain=92.168.96.61,MD_epipe_tutorial HTTP/1.1
DELETE /restconf/data/nsp-eth-cfm-config:eth-cfm/domain=92.168.96.17,MD_epipe_tutorial HTTP/1.1

CFM DMM test

The "oam-test" API is used to create a CFM DMM test:

POST /restconf/data/nsp-oam:tests/oam-test:tests HTTP/1.1

{
    "cfm-dmm":
    [
        {
            "test-id":"12",
            "ne-id":null,
            "deployment-asynchronous":false,
            "template":"/nsp-oam:templates/oam-test:templates/cfm-dmm[name='Delay Streaming (proactive)']",
            "md-name":"MD_epipe_tutorial",
            "level":6,
            "ma-name":"CFM_MA_epipe_tutorial",
            "reuse-existing-mep":true,
            "source-mep-id":16,
            "sap-mep-direction":"up",
            "binding-mep-direction":"down",
            "interval":100,
            "data-tlv-size":0,
            "priority":0,
            "bin-group":1,
            "measurement-interval":5,
            "admin-state":"disable",
            "test-duration":null,
            "streaming-template":"default",
            "owner":null,
            "app-id":"NSP",
            "execute-type":"proactive",
            "bulk-result":true,
            "notify-target-ne":"never",
            "description":null,
            "entities":
            [
                {
                    "entity-type":"source",
                    "entity-reference":"/nsp-service:services/service-layer/eline[service-id='epipe tutorial']/endpoint[endpoint-id='92.168.96.61-1/1/c1/10:400']"
                },
                {
                    "entity-type":"destination",
                    "entity-reference":"/nsp-service:services/service-layer/eline[service-id='epipe tutorial']/endpoint[endpoint-id='92.168.96.17-1/1/c1/10:400']"
                }
            ],
            "name":"EPIPE OAM DMM test",
            "remote-mep-id":17
        }
    ]
}

The "tests" API can be used to execute the CFM DMM test:

POST /restconf/data/nsp-oam:tests/oam-test:tests/cfm-dmm=92.168.96.61,EPIPE%20OAM%20DMM%20test/start HTTP/1.1

{
	"input":{
	  "publish-results" : "true",
	  "test-timeout" : "90",
	  "result-classifier" : "default",
	  "sync-mode" : "sync-execute",
	  "stop-test-after-result" : "false",
	  "extra-fields-profile" : "default"
	}
}

Retrieve the results of the execution using the "get-results" API:

POST /restconf/data/nsp-oam:tests/oam-test:tests/cfm-dmm=92.168.96.61,EPIPE%20OAM%20DMM%20test/get-results HTTP/1.1

{
    "input": {
        "start": "2023-07-26T00:35:02-04:00",
        "end": "2023-09-14T23:09:55-04:00",
        "limit": 200
    }
}

The "tests" API can be used to stop the CFM DMM test:

POST /restconf/data/nsp-oam:tests/oam-test:tests/cfm-dmm=92.168.96.61,EPIPE%20OAM%20DMM%20test/stop HTTP/1.1

{
}

Clean up the test artifacts by deleting the test & temporary CFM objects

DELETE /restconf/data/nsp-oam:tests/oam-test:tests/cfm-dmm=92.168.96.61,EPIPE%20OAM%20DMM%20test HTTP/1.1
DELETE /restconf/data/nsp-eth-cfm-config:eth-cfm/domain=92.168.96.61,MD_epipe_tutorial HTTP/1.1
DELETE /restconf/data/nsp-eth-cfm-config:eth-cfm/domain=92.168.96.17,MD_epipe_tutorial HTTP/1.1

CFM SLM test

The "oam-test" API is used to create a CFM SLM test:

POST /restconf/data/nsp-oam:tests/oam-test:tests HTTP/1.1

{
    "cfm-slm": [
        {
            "deployment-asynchronous": false,
            "template": "/nsp-oam:templates/oam-test:templates/cfm-slm[name='Synthetic Loss - SLM (proactive)']",
            "md-name": "TEMP_CFM",
            "level": 6,
            "ma-name": "srv:${service-id}",
            "reuse-existing-mep": true,
            "source-mep-id": 1,
            "sap-mep-direction": "up",
            "binding-mep-direction": "down",
            "interval": 100,
            "data-tlv-size": 0,
            "flr-threshold": 50,
            "hli-force-count": false,
            "frames-per-delta-t": 10,
            "consec-delta-t": 10,
            "chli-threshold": 5,
            "priority": 0,
            "bin-group": 1,
            "measurement-interval": 5,
            "admin-state": "disable",
            "app-id": "NSP",
            "execute-type": "proactive",
            "bulk-result": true,
            "notify-target-ne": "never",
            "name": "EPIPE OAM SLM TEST",
            "entities": [
                {
                    "entity-type": "source",
                    "entity-reference": "/nsp-service:services/service-layer/eline[service-id='epipe tutorial']/endpoint[endpoint-id='92.168.96.61-1/1/c1/10:400']"
                },
                {
                    "entity-type": "destination",
                    "entity-reference": "/nsp-service:services/service-layer/eline[service-id='epipe tutorial']/endpoint[endpoint-id='92.168.96.17-1/1/c1/10:400']"
                }
            ],
            "domain": {
                "name": "TEMP_CFM"
            },
            "association": {
                "string": "srv:${service-id}"
            },
            "test-id": "18",
            "remote-mep-id": 2
        }
    ]
}

The "tests" API can be used to execute the CFM SLM test:

POST /restconf/data/nsp-oam:tests/oam-test:tests/cfm-slm=92.168.96.61,EPIPE%20OAM%20SLM%20TEST/start HTTP/1.1

{
    "input": {
        "publish-results": "true",
        "stop-test-after-result": "false",
        "test-timeout": "120",
        "result-classifier": "default",
        "sync-mode": "sync-execute",
        "extra-fields-profile": "default",
        "save-results-to-db": "true",
        "perform-result-classification": "true"
    }
}

Retrieve the results of the execution using the "get-results" API:

POST /restconf/data/nsp-oam:tests/oam-test:tests/cfm-slm=92.168.96.61,EPIPE%20OAM%20SLM%20TEST/get-results HTTP/1.1

{
    "input": {
        "start": "2023-07-26T00:35:02-04:00",
        "end": "2023-09-13T23:09:55-04:00",
        "limit": 200
    }
}

The "tests" API can be used to stop the CFM SLM test:

POST /restconf/data/nsp-oam:tests/oam-test:tests/cfm-slm=92.168.96.61,EPIPE%20OAM%20SLM%20TEST/stop HTTP/1.1

{
}

Clean up the test artifacts by deleting the test & temporary CFM objects

DELETE /restconf/data/nsp-oam:tests/oam-test:tests/cfm-slm=92.168.96.61,EPIPE%20OAM%20SLM%20TEST HTTP/1.1
DELETE /restconf/data/nsp-eth-cfm-config:eth-cfm/domain=92.168.96.61,MD_epipe_tutorial HTTP/1.1
DELETE /restconf/data/nsp-eth-cfm-config:eth-cfm/domain=92.168.96.17,MD_epipe_tutorial HTTP/1.1

Once the OAM testing is completed, delete the CFM Domain & MDM OAM bin groups from both sites:

DELETE /restconf/data/nsp-eth-cfm-config:eth-cfm/domain=92.168.96.61,CFM_MD_epipe_tutorial HTTP/1.1
DELETE /restconf/data/nsp-eth-cfm-config:eth-cfm/domain=92.168.96.17,CFM_MD_epipe_tutorial HTTP/1.1
DELETE /restconf/data/nsp-oam-config:oam-pm/bin-groups=92.168.96.61,21 HTTP/1.1
DELETE /restconf/data/nsp-oam-config:oam-pm/bin-groups=92.168.96.17,21 HTTP/1.1

Enable statistics collection

Statistics can be enabled in order to monitor the service and provide metrics on the service usage. SAP egress queue statistics will be enabled using the "subscription" API:

POST /restconf/data/md-subscription:/subscriptions/subscription HTTP/1.1

{
    "subscription": [
        {
            "type": "telemetry:/base/sros-service-epipe/service_epipe_sap_egress_qos_sap-egress_queue_statistics",
            "name": "EPIPE Queue Stats",
            "period": 900,
            "db": "enabled",
            "state": "enabled",
            "notification": "enabled",
            "fields": [],
            "sync-time": "00:00",
            "filter": null
        }
    ]
}

To monitor statistics, it is recommended to use Kafka notifications. The topic that will publish the statistics can be determined by retrieving the subscription after it is created:

GET /restconf/data/md-subscription:/subscriptions/subscription=EPIPE Queue Stats HTTP/1.1

An example of the Kafka notification is:

{
  "data": {
    "ietf-restconf:notification": {
      "eventTime": "2023-09-14T10:15:01Z",
      "nsp-kpi:real_time_kpi-event": {
        "profile_in-inplus-profile-forwarded-packets": 0,
        "profile_in-inplus-profile-forwarded-octets": 0,
        "profile_out-exceed-profile-forwarded-packets": 0,
        "profile_out-exceed-profile-forwarded-octets": 0,
        "profile_in-inplus-profile-dropped-packets": 0,
        "profile_in-inplus-profile-dropped-octets": 0,
        "profile_out-exceed-profile-dropped-packets": 0,
        "profile_out-exceed-profile-dropped-octets": 0,
        "system-id": "92.168.96.17",
        "time-captured": 1694686493062,
        "profile_out-exceed-profile-forwarded-packets-periodic": 0,
        "time-captured-periodic": 899998,
        "profile_out-exceed-profile-forwarded-octets-periodic": 0,
        "profile_in-inplus-profile-dropped-octets-periodic": 0,
        "profile_out-exceed-profile-dropped-packets-periodic": 0,
        "profile_in-inplus-profile-forwarded-octets-periodic": 0,
        "profile_out-exceed-profile-dropped-octets-periodic": 0,
        "profile_in-inplus-profile-forwarded-packets-periodic": 0,
        "profile_in-inplus-profile-dropped-packets-periodic": 0,
        "neId": "92.168.96.17",
        "kpiType": "telemetry:/base/sros-service-epipe/service_epipe_sap_egress_qos_sap-egress_queue_statistics",
        "objectId": "/state/service/epipe[service-name\u003d\u0027epipe tutorial\u0027]/sap[sap-id\u003d\u00271/1/c1/10:400\u0027]/egress/qos/sap-egress/queue[queue-id\u003d\u00271\u0027]/statistics/profile",
        "dataType": 1
      }
    }
  }
}

On this page