Add tool to measure southbound notification performance 15/94915/7
authorOleksii Mozghovyi <oleksii.mozghovyi@pantheon.tech>
Wed, 27 Jan 2021 12:37:19 +0000 (14:37 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Sun, 21 Feb 2021 11:36:51 +0000 (12:36 +0100)
This is an updated version of the tool existed in coretutorials project,
aligned with the latest API changes
- Tool is packaged into a new feature odl-netconf-test-tools
- For the testing purposes models from the original coretutorials
project are used
- Tool listens for mounted devices with prefix "perf-"
- Notification counter is only applied for devices that end with the following
pattern '*-notif-([0-9]+)', and the number after notif suffix indicates
how many notifications should be counted
- Once the mounted device is ready tool invokes create subscription
  request towards device, and counts incoming notifications

JIRA: NETCONF-759
Change-Id: I5a584032dca9a40e90dec23186562543f8752bad
Signed-off-by: Oleksii Mozghovyi <oleksii.mozghovyi@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
13 files changed:
artifacts/pom.xml
features/netconf/features-netconf-testing/pom.xml [new file with mode: 0644]
features/netconf/odl-netconf-test-tools/pom.xml [new file with mode: 0644]
features/netconf/pom.xml
karaf/pom.xml
netconf/tools/netconf-test-perf/pom.xml [new file with mode: 0644]
netconf/tools/netconf-test-perf/src/main/java/org/opendaylight/netconf/test/perf/MountedDeviceListener.java [new file with mode: 0644]
netconf/tools/netconf-test-perf/src/main/java/org/opendaylight/netconf/test/perf/notifications/NotificationsCounter.java [new file with mode: 0644]
netconf/tools/netconf-test-perf/src/main/java/org/opendaylight/netconf/test/perf/utils/TestUtils.java [new file with mode: 0644]
netconf/tools/netconf-test-perf/src/main/yang/Cisco-IOS-XR-ip-static-cfg@2013-07-22.yang [new file with mode: 0644]
netconf/tools/netconf-test-perf/src/main/yang/Cisco-IOS-XR-types@2015-01-19.yang [new file with mode: 0644]
netconf/tools/netconf-test-perf/src/main/yang/Example-notifications@2015-06-11.yang [new file with mode: 0644]
netconf/tools/pom.xml

index abc67088aebf97b35e07f25d3d979be5371ec377..44de193148ab2d40df6e315b40f94fb7f90b68fc 100644 (file)
                 <artifactId>netconf-testtool</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>netconf-test-perf</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>netconf-util</artifactId>
                 <type>xml</type>
                 <classifier>features</classifier>
             </dependency>
+
+            <!-- Testing features -->
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>features-netconf-testing</artifactId>
+                <version>${project.version}</version>
+                <type>xml</type>
+                <classifier>features</classifier>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>odl-netconf-test-tools</artifactId>
+                <version>${project.version}</version>
+                <type>xml</type>
+                <classifier>features</classifier>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 </project>
diff --git a/features/netconf/features-netconf-testing/pom.xml b/features/netconf/features-netconf-testing/pom.xml
new file mode 100644 (file)
index 0000000..dd0089f
--- /dev/null
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2021 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+      <groupId>org.opendaylight.odlparent</groupId>
+      <artifactId>feature-repo-parent</artifactId>
+      <version>8.1.0</version>
+      <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.netconf</groupId>
+  <artifactId>features-netconf-testing</artifactId>
+  <version>1.10.0-SNAPSHOT</version>
+  <packaging>feature</packaging>
+
+  <dependencyManagement>
+      <dependencies>
+          <dependency>
+              <groupId>${project.groupId}</groupId>
+              <artifactId>netconf-artifacts</artifactId>
+              <version>${project.version}</version>
+              <scope>import</scope>
+              <type>pom</type>
+          </dependency>
+      </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-aaa-netconf-plugin</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-aaa-netconf-plugin-no-cluster</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-netconf-all</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-netconf-api</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-netconf-client</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-netconf-impl</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-netconf-mapping-api</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-netconf-mdsal</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-netconf-netty-util</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-netconf-notifications-api</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-netconf-notifications-impl</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-netconf-ssh</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-netconf-tcp</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+      <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>odl-netconf-util</artifactId>
+          <type>xml</type>
+          <classifier>features</classifier>
+      </dependency>
+  </dependencies>
+</project>
diff --git a/features/netconf/odl-netconf-test-tools/pom.xml b/features/netconf/odl-netconf-test-tools/pom.xml
new file mode 100644 (file)
index 0000000..82a41d6
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2021 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>single-feature-parent</artifactId>
+        <version>8.1.0</version>
+        <relativePath/>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.opendaylight.netconf</groupId>
+    <artifactId>odl-netconf-test-tools</artifactId>
+    <version>1.10.0-SNAPSHOT</version>
+    <packaging>feature</packaging>
+
+    <name>OpenDaylight :: NETCONF Test Tools :: Tools used for performance testing</name>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>netconf-artifacts</artifactId>
+                <version>1.10.0-SNAPSHOT</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>odl-netconf-mdsal</artifactId>
+            <type>xml</type>
+            <classifier>features</classifier>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-test-perf</artifactId>
+        </dependency>
+    </dependencies>
+</project>
index 12ed3c76e618ec04a03e3e9e59e0c95c8f1d48b7..bb26b9fc635b630aab182e452045788a09b649c5 100644 (file)
     <module>odl-netconf-ssh</module>
     <module>odl-netconf-tcp</module>
     <module>odl-netconf-util</module>
+
+    <!-- CSIT features -->
+    <module>features-netconf-testing</module>
+    <module>odl-netconf-test-tools</module>
   </modules>
 
   <scm>
index b6fe8dde18c18a59f385db390bb499f2862983c8..c7517c234a4f18df3dc5c8eee37d8dbb52708a54 100644 (file)
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>features-netconf-testing</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
   </dependencies>
 </project>
diff --git a/netconf/tools/netconf-test-perf/pom.xml b/netconf/tools/netconf-test-perf/pom.xml
new file mode 100644 (file)
index 0000000..2b76375
--- /dev/null
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.opendaylight.netconf</groupId>
+        <artifactId>netconf-parent</artifactId>
+        <version>1.10.0-SNAPSHOT</version>
+        <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>netconf-test-perf</artifactId>
+    <description>NETCONF performance test tools</description>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.mdsal</groupId>
+            <artifactId>mdsal-dom-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal</groupId>
+            <artifactId>mdsal-dom-spi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal</groupId>
+            <artifactId>mdsal-binding-dom-codec-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal.model</groupId>
+            <artifactId>ietf-topology</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.netconf</groupId>
+            <artifactId>ietf-netconf-notifications</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.netconf</groupId>
+            <artifactId>mdsal-netconf-notification</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.netconf</groupId>
+            <artifactId>netconf-notifications-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.guicedee.services</groupId>
+            <artifactId>javax.inject</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>javax.annotation</groupId>
+            <artifactId>javax.annotation-api</artifactId>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.component.annotations</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>NETCONF performance test tools</Bundle-Name>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/netconf/tools/netconf-test-perf/src/main/java/org/opendaylight/netconf/test/perf/MountedDeviceListener.java b/netconf/tools/netconf-test-perf/src/main/java/org/opendaylight/netconf/test/perf/MountedDeviceListener.java
new file mode 100644 (file)
index 0000000..62682f8
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2021 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.test.perf;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.Iterator;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMMountPointListener;
+import org.opendaylight.mdsal.dom.api.DOMMountPointService;
+import org.opendaylight.mdsal.dom.api.DOMNotificationService;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.netconf.test.perf.notifications.NotificationsCounter;
+import org.opendaylight.netconf.test.perf.utils.TestUtils;
+import org.opendaylight.yang.gen.v1.org.opendaylight.coretutorials.ncmount.example.notifications.rev150611.VrfRouteNotification;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInput;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+@Component(immediate = true)
+public class MountedDeviceListener implements DOMMountPointListener {
+    private static final Logger LOG = LoggerFactory.getLogger(MountedDeviceListener.class);
+    private static final String TEST_NODE_PREFIX = "perf-";
+    private static final String STREAM_DEFAULT_NAME = "STREAM-PERF-DEFAULT";
+    private static final QName CREATE_SUBSCRIPTION_QNAME = QName.create(CreateSubscriptionInput.QNAME,
+        "create-subscription");
+
+    private final ConcurrentMap<YangInstanceIdentifier, ListenerRegistration<?>> listeners = new ConcurrentHashMap<>();
+    private final DOMMountPointService mountPointService;
+    private final BindingNormalizedNodeSerializer serializer;
+    private final ListenerRegistration<?> reg;
+
+    @Inject
+    @Activate
+    public MountedDeviceListener(final @Reference DOMMountPointService mountPointService,
+                                 final @Reference BindingNormalizedNodeSerializer serializer) {
+        this.mountPointService = requireNonNull(mountPointService);
+        this.serializer = requireNonNull(serializer);
+        reg = mountPointService.registerProvisionListener(this);
+    }
+
+    @PreDestroy
+    @Deactivate
+    public void stop() {
+        reg.close();
+        final Iterator<ListenerRegistration<?>> it = listeners.values().iterator();
+        while (it.hasNext()) {
+            it.next().close();
+            it.remove();
+        }
+    }
+
+    @Override
+    public void onMountPointCreated(final YangInstanceIdentifier path) {
+        final Optional<String> optNodeId = TestUtils.getNodeId(path);
+        if (optNodeId.isPresent() && optNodeId.get().startsWith(TEST_NODE_PREFIX)) {
+            LOG.info("Test node mounted: {}", optNodeId.get());
+            trackNotificationsPerformance(path);
+        }
+    }
+
+    @Override
+    public void onMountPointRemoved(final YangInstanceIdentifier path) {
+        final ListenerRegistration<?> listener = listeners.remove(path);
+        if (listener != null) {
+            listener.close();
+        }
+    }
+
+    private void trackNotificationsPerformance(final YangInstanceIdentifier path) {
+        // 1. get nodeId from the path
+        final String nodeId = TestUtils.getNodeId(path).get();
+
+        // 2. extract needed services from the mount point
+        final DOMMountPoint mountPoint = mountPointService.getMountPoint(path)
+            .orElseThrow(() -> new RuntimeException("Unable to get mountpoint"));
+        final DOMRpcService rpcService = mountPoint.getService(DOMRpcService.class)
+            .orElseThrow(() -> new RuntimeException("Unable to get RPC Service from the mountpoint"));
+        final DOMNotificationService notificationService = mountPoint.getService(DOMNotificationService.class)
+            .orElseThrow(() -> new RuntimeException("Unable to get NotificationService from the mountpoint"));
+
+        // 3. create a listener for the notifications
+        listeners.put(path, notificationService.registerNotificationListener(
+            new NotificationsCounter(nodeId, serializer), Absolute.of(VrfRouteNotification.QNAME)));
+
+        // 4. send 'create-subscription' request to the device
+        final StreamNameType streamNameType = new StreamNameType(STREAM_DEFAULT_NAME);
+        final CreateSubscriptionInputBuilder subscriptionInputBuilder = new CreateSubscriptionInputBuilder();
+        subscriptionInputBuilder.setStream(streamNameType);
+        final CreateSubscriptionInput input = subscriptionInputBuilder.build();
+        final ContainerNode inputNode = serializer.toNormalizedNodeRpcData(input);
+        final ListenableFuture<? extends DOMRpcResult> resultFuture = rpcService.invokeRpc(CREATE_SUBSCRIPTION_QNAME,
+            inputNode);
+        Futures.addCallback(resultFuture, new FutureCallback<DOMRpcResult>() {
+            @Override
+            public void onSuccess(@Nullable final DOMRpcResult rpcResult) {
+                LOG.info("Notification stream subscription succesfully completed");
+            }
+
+            @Override
+            public void onFailure(final Throwable throwable) {
+                LOG.error("Notification stream subscription failed");
+            }
+        }, MoreExecutors.directExecutor());
+    }
+}
diff --git a/netconf/tools/netconf-test-perf/src/main/java/org/opendaylight/netconf/test/perf/notifications/NotificationsCounter.java b/netconf/tools/netconf-test-perf/src/main/java/org/opendaylight/netconf/test/perf/notifications/NotificationsCounter.java
new file mode 100644 (file)
index 0000000..38a3dbd
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2021 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.test.perf.notifications;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Stopwatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.mdsal.dom.api.DOMNotification;
+import org.opendaylight.mdsal.dom.api.DOMNotificationListener;
+import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.cisco.ios.xr.ip._static.cfg.rev130722.VRFPREFIXTABLE;
+import org.opendaylight.yangtools.yang.binding.Notification;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NotificationsCounter implements DOMNotificationListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NotificationsCounter.class);
+
+    /**
+     * Custom pattern to identify nodes where performance should be measured.
+     */
+    private static final Pattern NOTIFICATION_NUMBER_PATTERN = Pattern.compile(".*-notif-([0-9]+)");
+
+    private final String nodeId;
+    private final BindingNormalizedNodeSerializer serializer;
+    private final AtomicLong notifCounter;
+    private final long expectedNotificationCount;
+    private Stopwatch stopWatch;
+    private long totalPrefixesReceived = 0;
+
+    public NotificationsCounter(final String nodeId, final BindingNormalizedNodeSerializer serializer) {
+        this.nodeId = nodeId;
+        this.serializer = serializer;
+        final Matcher matcher = NOTIFICATION_NUMBER_PATTERN.matcher(nodeId);
+        Preconditions.checkArgument(matcher.matches());
+        expectedNotificationCount = Long.parseLong(matcher.group(1));
+        Preconditions.checkArgument(expectedNotificationCount > 0);
+        this.notifCounter = new AtomicLong(this.expectedNotificationCount);
+    }
+
+
+    @Override
+    public void onNotification(@NonNull DOMNotification domNotification) {
+        final long andDecrement = notifCounter.getAndDecrement();
+
+        if (andDecrement == expectedNotificationCount) {
+            this.stopWatch = Stopwatch.createStarted();
+            LOG.info("First notification received at {}", stopWatch);
+        }
+
+        LOG.debug("Notification received, {} to go.", andDecrement);
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Notification received: {}", domNotification);
+        }
+
+        final Notification notification = serializer.fromNormalizedNodeNotification(domNotification.getType(),
+            domNotification.getBody());
+        if (notification instanceof VRFPREFIXTABLE) {
+            totalPrefixesReceived += ((VRFPREFIXTABLE)notification).getVrfPrefixes().getVrfPrefix().size();
+        }
+
+        if (andDecrement == 1) {
+            this.stopWatch.stop();
+            LOG.info("Last notification received at {}", stopWatch);
+            LOG.info("Elapsed ms for {} notifications: {}", expectedNotificationCount,
+                stopWatch.elapsed(TimeUnit.MILLISECONDS));
+            LOG.info("Performance (notifications/second): {}",
+                (expectedNotificationCount * 1.0 / stopWatch.elapsed(TimeUnit.MILLISECONDS)) * 1000);
+            LOG.info("Performance (prefixes/second): {}",
+                (totalPrefixesReceived * 1.0 / stopWatch.elapsed(TimeUnit.MILLISECONDS)) * 1000);
+        }
+    }
+
+}
diff --git a/netconf/tools/netconf-test-perf/src/main/java/org/opendaylight/netconf/test/perf/utils/TestUtils.java b/netconf/tools/netconf-test-perf/src/main/java/org/opendaylight/netconf/test/perf/utils/TestUtils.java
new file mode 100644 (file)
index 0000000..4c33957
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.test.perf.utils;
+
+import java.util.Optional;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+
+public final class TestUtils {
+
+    private static final QName NODE_QNAME = QName.create(Node.QNAME, "node-id").intern();
+
+    private TestUtils() {
+    }
+
+    public static Optional<String> getNodeId(final YangInstanceIdentifier path) {
+        if (path.getLastPathArgument() instanceof NodeIdentifierWithPredicates) {
+            final NodeIdentifierWithPredicates nodeIId = ((NodeIdentifierWithPredicates) path.getLastPathArgument());
+            return Optional.ofNullable(nodeIId.getValue(NODE_QNAME, String.class));
+        } else {
+            return Optional.empty();
+        }
+    }
+}
diff --git a/netconf/tools/netconf-test-perf/src/main/yang/Cisco-IOS-XR-ip-static-cfg@2013-07-22.yang b/netconf/tools/netconf-test-perf/src/main/yang/Cisco-IOS-XR-ip-static-cfg@2013-07-22.yang
new file mode 100644 (file)
index 0000000..ed778cb
--- /dev/null
@@ -0,0 +1,371 @@
+module Cisco-IOS-XR-ip-static-cfg {
+
+  /*** NAMESPACE / PREFIX DEFINITION ***/
+
+  namespace "http://cisco.com/ns/yang/Cisco-IOS-XR-ip-static-cfg";
+
+
+  prefix "ip-static-cfg";
+
+  /*** LINKAGE (IMPORTS / INCLUDES) ***/
+
+  import ietf-inet-types { prefix "inet"; }
+
+  import Cisco-IOS-XR-types { prefix "xr"; }
+
+  /*** META INFORMATION ***/
+
+  organization "Cisco Systems, Inc.";
+
+  contact
+    "Cisco Systems, Inc.
+     Customer Service
+
+     Postal: 170 West Tasman Drive
+     San Jose, CA 95134
+
+     Tel: +1 800 553-NETS
+
+     E-mail: cs-yang@cisco.com";
+
+  description
+    "This module contains a collection of YANG definitions
+     for Cisco IOS-XR ip-static package configuration.
+
+     This module contains definitions
+     for the following management objects:
+       router-static: This class represents router static
+         configuration
+
+     Copyright (c) 2013 by Cisco Systems, Inc.
+     All rights reserved.";
+
+  revision "2013-07-22" {
+    description
+      "Initial revision.";
+  }
+
+
+  grouping VRF-ROUTE {
+    description "Common node of vrf-prefix, vrf-prefix-topology";
+
+    container vrf-route {
+      xr:xr-xml-map "ip_static_cfg:VRFRoute";
+      description "A connected or recursive  static route";
+
+      container vrf-next-hops {
+        xr:xr-xml-map "ip_static_cfg:VRFNextHopTable";
+        description
+          "A forwarding interface and/or the address of a
+          nexthop router for this route (one of these
+          must be specified)";
+
+        grouping VRF-NEXT-HOP-CONTENT {
+          description "Content grouping.";
+          leaf bfd-fast-detect {
+            xr:xr-xml-map "ip_static_cfg:BFDFastDetect";
+            type boolean;
+            default "false";
+            description "If set, bfd is enabled";
+          }
+          leaf minimum-interval {
+            xr:xr-xml-map "ip_static_cfg:MinimumInterval";
+            type uint32 {
+              range "3..30000";
+            }
+            units "millisecond";
+            default "100";
+            description "BFD Hello interval in milliseconds";
+          }
+          leaf detect-multiplier {
+            xr:xr-xml-map "ip_static_cfg:DetectMultiplier";
+            type uint32 {
+              range "1..10";
+            }
+            default "3";
+            description "BFD Detect Multiplier";
+          }
+          leaf metric {
+            xr:xr-xml-map "ip_static_cfg:Metric";
+            type uint32 {
+              range "1..254";
+            }
+            default "1";
+            description "Distance metric for this path";
+          }
+          leaf tag {
+            xr:xr-xml-map "ip_static_cfg:Tag";
+            type uint32 {
+              range "1..4294967295";
+            }
+            description "Tag for this path";
+          }
+          leaf permanent {
+            xr:xr-xml-map "ip_static_cfg:Permanent";
+            type boolean;
+            default "false";
+            description "If set, path is permanent";
+          }
+          leaf vrf-lable {
+            xr:xr-xml-map "ip_static_cfg:VRFLable";
+            type uint32 {
+              range "0..4294967295";
+            }
+            default "0";
+            description "VRF LABEL";
+          }
+          leaf tunnel-id {
+            xr:xr-xml-map "ip_static_cfg:TunnelID";
+            type uint32 {
+              range "0..65535";
+            }
+            default "0";
+            description "Tunnel ID for this path";
+          }
+          leaf object-name {
+            xr:xr-xml-map "ip_static_cfg:ObjectName";
+            type xr:Cisco-ios-xr-string {
+              length "0..32";
+            }
+            description "Name of the object to track";
+          }
+          leaf description {
+            xr:xr-xml-map "ip_static_cfg:Description";
+            type string;
+            description "Short Description of Static Route";
+          }
+        }
+
+        list interface-name-and-next-hop-address {
+          xr:xr-xml-map "ip_static_cfg:VRFNextHop";
+          key "interface-name next-hop-address";
+          description "keys: interface-name, next-hop-address";
+          leaf interface-name {
+            xr:xr-xml-map "ip_static_cfg:InterfaceName";
+            type xr:Interface-name;
+            description "Forwarding interface";
+          }
+          leaf next-hop-address {
+            xr:xr-xml-map "ip_static_cfg:NextHopAddress";
+            type inet:ip-address;
+            description "Next hop address";
+          }
+          uses VRF-NEXT-HOP-CONTENT;
+        }
+
+        list interface-name {
+          xr:xr-xml-map "ip_static_cfg:VRFNextHop";
+          key "interface-name";
+          description "keys: interface-name";
+          leaf interface-name {
+            xr:xr-xml-map "ip_static_cfg:InterfaceName";
+            type xr:Interface-name;
+            description "Forwarding interface";
+          }
+          uses VRF-NEXT-HOP-CONTENT;
+        }
+
+        list next-hop-address {
+          xr:xr-xml-map "ip_static_cfg:VRFNextHop";
+          key "next-hop-address";
+          description "keys: next-hop-address";
+          leaf next-hop-address {
+            xr:xr-xml-map "ip_static_cfg:NextHopAddress";
+            type inet:ip-address;
+            description "Next hop address";
+          }
+          uses VRF-NEXT-HOP-CONTENT;
+        }
+      }
+    }
+  }
+
+  grouping TOPOLOGY-TABLE {
+    description "Common node of vrf-unicast, vrf-multicast";
+
+    container topologies {
+      xr:xr-xml-map "ip_static_cfg:TopologyTable";
+      description "Topology static configuration container";
+
+      list topology {
+        xr:xr-xml-map "ip_static_cfg:Topology";
+        key "topology-name";
+        description "Topology static configuration";
+        leaf topology-name {
+          xr:xr-xml-map "ip_static_cfg:TopologyName";
+          type xr:Cisco-ios-xr-string;
+          description "Topology name";
+        }
+        uses VRF-PREFIX-TOPOLOGY-TABLE;
+      }
+    }
+  }
+
+  grouping VRF-PREFIX-TABLE {
+    description "Common node of vrf-unicast, vrf-multicast";
+
+    container vrf-prefixes {
+      xr:xr-xml-map "ip_static_cfg:VRFPrefixTable";
+      description "The set of all Static Topologies for this AFI.";
+
+      list vrf-prefix {
+        xr:xr-xml-map "ip_static_cfg:VRFPrefix";
+        key "prefix prefix-length";
+        description "A static route";
+        leaf prefix {
+          xr:xr-xml-map "ip_static_cfg:Prefix";
+          type inet:ip-address;
+          description "Destination prefix";
+        }
+        leaf prefix-length {
+          xr:xr-xml-map "ip_static_cfg:PrefixLength";
+          type uint32 {
+            range "0..128";
+          }
+          description "Destination prefix length";
+        }
+        uses VRF-ROUTE;
+      }
+    }
+  }
+
+  grouping ADDRESS-FAMILY {
+    description "Common node of default-vrf, vrf";
+
+    container address-family {
+      xr:xr-xml-map "ip_static_cfg:AddressFamily";
+      description "Address family configuration";
+
+      container vrfipv4 {
+        xr:xr-xml-map "ip_static_cfg:VRFIPV4";
+        description "IPv4 static configuration";
+        uses VRF-UNICAST;
+        uses VRF-MULTICAST;
+      }
+
+      container vrfipv6 {
+        xr:xr-xml-map "ip_static_cfg:VRFIPV6";
+        description "IPv6 static configuration";
+        uses VRF-UNICAST;
+        uses VRF-MULTICAST;
+      }
+    }
+  }
+
+  grouping VRF-PREFIX-TOPOLOGY-TABLE {
+    description "Common node of default-topology, topology";
+
+    container vrf-prefix-topologies {
+      xr:xr-xml-map "ip_static_cfg:VRFPrefixTopologyTable";
+      description "The set of all Static Topologies for this AFI.";
+
+      list vrf-prefix-topology {
+        xr:xr-xml-map "ip_static_cfg:VRFPrefixTopology";
+        key "prefix prefix-length";
+        description "A static route";
+        leaf prefix {
+          xr:xr-xml-map "ip_static_cfg:Prefix";
+          type inet:ip-address;
+          description "Destination prefix";
+        }
+        leaf prefix-length {
+          xr:xr-xml-map "ip_static_cfg:PrefixLength";
+          type uint32 {
+            range "0..128";
+          }
+          description "Destination prefix length";
+        }
+        uses VRF-ROUTE;
+      }
+    }
+  }
+
+  grouping DEFAULT-TOPOLOGY {
+    description "Common node of vrf-unicast, vrf-multicast";
+
+    container default-topology {
+      xr:xr-xml-map "ip_static_cfg:DefaultTopology";
+      description "Default topology configuration";
+      uses VRF-PREFIX-TOPOLOGY-TABLE;
+    }
+  }
+
+  grouping VRF-UNICAST {
+    description "Common node of vrfipv4, vrfipv6";
+
+    container vrf-unicast {
+      xr:xr-xml-map "ip_static_cfg:VRFUnicast";
+      description "Unicast static configuration";
+      uses TOPOLOGY-TABLE;
+      uses VRF-PREFIX-TABLE;
+      uses DEFAULT-TOPOLOGY;
+    }
+  }
+
+  grouping VRF-MULTICAST {
+    description "Common node of vrfipv4, vrfipv6";
+
+    container vrf-multicast {
+      xr:xr-xml-map "ip_static_cfg:VRFMulticast";
+      description "Multicast static configuration";
+      uses TOPOLOGY-TABLE;
+      uses VRF-PREFIX-TABLE;
+      uses DEFAULT-TOPOLOGY;
+    }
+  }
+
+  container router-static {
+    xr:xr-xml-map "ip_static_cfg:RouterStatic";
+    description "This class represents router static configuration";
+
+    container vrfs {
+      xr:xr-xml-map "ip_static_cfg:VRFTable";
+      description "VRF static configuration container";
+
+      list vrf {
+        xr:xr-xml-map "ip_static_cfg:VRF";
+        key "vrf-name";
+        description "VRF static configuration";
+        leaf vrf-name {
+          xr:xr-xml-map "ip_static_cfg:VRFName";
+          type xr:Cisco-ios-xr-string;
+          description "VRF name";
+        }
+        uses ADDRESS-FAMILY;
+      }
+    }
+
+    container default-vrf {
+      xr:xr-xml-map "ip_static_cfg:DefaultVRF";
+      description "Default VRF configuration";
+      uses ADDRESS-FAMILY;
+    }
+
+    container maximum-routes {
+      xr:xr-xml-map "ip_static_cfg:MaximumRoutes";
+      description
+        "The maximum number of static routes that can be
+        configured.";
+      leaf ipv6-routes {
+        xr:xr-xml-map "ip_static_cfg:IPV6Routes";
+        type uint32 {
+          range "1..140000";
+        }
+        default "4000";
+        description
+          "The maximum number of static routes that can be
+          configured for this AFI";
+      }
+      leaf ipv4-routes {
+        xr:xr-xml-map "ip_static_cfg:IPV4Routes";
+        type uint32 {
+          range "1..140000";
+        }
+        default "4000";
+        description
+          "The maximum number of static routes that can be
+          configured for this AFI";
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/netconf/tools/netconf-test-perf/src/main/yang/Cisco-IOS-XR-types@2015-01-19.yang b/netconf/tools/netconf-test-perf/src/main/yang/Cisco-IOS-XR-types@2015-01-19.yang
new file mode 100644 (file)
index 0000000..d6dce98
--- /dev/null
@@ -0,0 +1,391 @@
+module Cisco-IOS-XR-types {
+
+  namespace "http://cisco.com/ns/yang/cisco-xr-types";
+  prefix "xr";
+
+  organization "Cisco Systems, Inc.";
+
+  contact 
+    "Cisco Systems, Inc.
+     Customer Service
+
+     Postal: 170 W Tasman Drive
+     San Jose, CA 95134
+
+     Tel: +1 1800 553-NETS
+
+     E-mail: cs-yang@cisco.com";
+
+
+  description       
+    "This module contains a collection of IOS-XR derived YANG data 
+     types.
+    
+     Copyright (c) 2013-2015 by Cisco Systems, Inc.
+     All rights reserved.";
+
+  revision "2015-01-19" {
+    description
+     "This revision adds the following new data types:
+      - Bgp-ipv4-flowspec-address
+      - Bgp-ipv6-flowspec-address";
+  }
+
+  extension xr-cli-map {
+    argument "cli-command";
+    description "The xr-cli-map statement takes as an argument
+                 relevant CLI configuration command.";
+  }
+  
+  extension xr-xml-map {
+    argument "xr-xml-node";
+    description "The xr-xml-map statement takes as an argument
+                 relevant Cisco XML Schema node name.";
+  }
+  
+  typedef Route-dist {
+    type string {
+      pattern "[a-fA-F0-9]{16}";
+    }
+    description "Route distinguisher in hexadecimal notation.";
+  }
+
+  typedef Bgp-l2vpn-evpn-addrs {
+    type string {
+      pattern "[a-fA-F0-9]{58}";
+    }
+    description "L2VPN EVPN Address in hexadecimal notation.";
+  }
+
+  typedef Bgp-ls-addr {
+    type string {
+      pattern "[a-fA-F0-9]+";
+    }
+    description "BGP link state unicast address in hexadecimal
+                 notation.";
+  }
+
+  typedef Bgp-ipv6-mvpn-addr {
+    type string {
+      pattern "[a-fA-F0-9]{104}";
+    }
+    description "An IPV6 MVPN address in hexadecimal notation.";
+  }
+
+  typedef Bgp-ipv4-mvpn-addr {
+    type string {
+      pattern "[a-fA-F0-9]{56}";
+    }
+    description "An IPV4 MVPN address in hexadecimal notation.";
+  }
+
+  typedef Bgp-rt-constrt-addr {
+    type string {
+      pattern "[a-fA-F0-9]{24}";
+    }
+    description 
+      "An IPV4 RTConstraint address in hexadecimal notation.";
+  }
+
+  typedef Bgp-ipv4-mdt-addr {
+    type string {
+      pattern "(([a-f0-9]{16}-)(([1-9]?[0-9]|1[0-9][0-9]|2[0-4]"+
+        "[0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]"+
+        "|25[0-5]))";
+    }
+    description "An IPV4 MDT address in dotted decimal notation.
+                 An IPv4 MDT address should be of the form 
+                 0000006400000065-129.29.83.45. This datatype 
+                 restricts the value of each field 16 digits in 
+                 hexadecimal for RD field and between 0 and 255
+                 for IPv4 address field, i.e. 
+                 [0000000000000000-ffffffffffffffff]-
+                 [0-255].[0-255].[0-255].[0-255].";
+  }
+
+  typedef Bgp-ipv4-tunnel-addr {
+    type string {
+      pattern "((0:|[1-9][0-9]{0,4}:)"+
+        "(([1-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}"+
+        "([1-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]))";
+    }
+    description "An IPV4 tunnel address in dotted decimal notation.
+                 An IPv4 tunnel address should be of the form 
+                 65535:129.29.83.45. This datatype restricts the 
+                 value of each field between 0 and 65535 for prefix
+                 field and 0 and 255 for IPv4 address field, i.e.
+                 [0-65535]:[0-255].[0-255].[0-255].[0-255]";
+  }
+
+  typedef Cisco-ios-xr-port-number {
+    type uint16 {
+      range "1..65535";
+    }
+    description "Port number of range from 1 to 65535";
+  }
+
+  typedef Interface-name {
+    type string {
+      pattern "(([a-zA-Z0-9_]*\d+/){3}\d+)|"+
+              "(([a-zA-Z0-9_]*\d+/){4}\d+)|"+
+              "(([a-zA-Z0-9_]*\d+/){3}\d+\.\d+)|"+
+              "(([a-zA-Z0-9_]*\d+/){2}([a-zA-Z0-9_]*\d+))|"+
+              "([a-zA-Z0-9_-]*\d+)|"+
+              "([a-zA-Z0-9_-]*\d+\.\d+)|"+
+              "(mpls)|(dwdm)";
+    }
+    description "An interface name specifying an interface type and 
+                 instance.
+                 Interface represents a string defining an interface
+                 type and instance, e.g. MgmtEth0/4/CPU1/0 or
+                 TenGigE0/2/0/0.2 or Bundle-Ether9 or 
+                 Bundle-Ether9.98";
+  }
+  
+  typedef Cisco-ios-xr-string {
+    type string {
+      pattern "[\w\-\.:,_@#%$\+=\|;]+";
+    }
+    description "Special characters are not allowed.";
+  }
+
+  typedef Ipv4-prefix-length {
+    type uint8 {
+      range "0..32";
+    }
+    description "An IPv4 address prefix length. 
+                 Must lie between 0 and 32 inclusive.";
+  }
+  
+  typedef Ipv6-prefix-length {
+    type uint8 {
+      range "0..128";
+    }
+    description "An IPv6 address prefix length. 
+                 Must lie between 0 and 32 inclusive.";
+  }
+  
+  typedef Rack-id {
+    type string {
+      pattern "[a-zA-Z0-9_]*\d+";
+    }
+    description "Names the rack portion of a NodeID 
+                 Rack/Slot/Instance triple";
+  }
+  
+  typedef Slot-id {
+    type string {
+      pattern "[a-zA-Z0-9_]*\d+";
+    }
+    description "Names the slot portion of a NodeID 
+                 Rack/Slot/Instance triple";
+  }
+  
+  typedef Instance-id {
+    type string {
+      pattern "[a-zA-Z0-9_]*\d+";
+    }
+    description "Names the instance portion of a NodeID 
+                 Rack/Slot/Instance triple";
+  }
+  
+  typedef Sub-instance-id {
+    type string {
+      pattern "[a-zA-Z0-9_]*\d+";
+    }
+    description "Names the sub-instance portion of an extended
+                 NodeID Rack/Slot/Instance/SubInstance";
+  }
+  
+  typedef Encryption-type {
+    type enumeration {
+      enum none {
+        value "0";
+        description "The password string is clear text.";
+      }
+      enum md5 {
+        value "1";
+        description "The password is encrypted to an MD5 digest.";
+      }
+      enum proprietary {
+        value "2";
+        description "The password is encrypted using Cisco type 7 
+                     password encryption.";
+      }
+    }
+    description "The type of encryption used on a password string.";
+  
+  }
+  
+  typedef Hex-integer {
+    type string {
+      pattern "[0-9a-fA-F]{1,8}";
+    }
+    description "An unsigned 32-bit integer represented in
+                 hexadecimal format.";
+  }
+  
+  typedef Osi-system-id {
+    type string {
+      pattern "[a-fA-F0-9]{4}(\.[a-fA-F0-9]{4}){2}";
+    }
+    description "An OSI system ID should be of the form 
+                 0123.4567.89ab. This data type restricts each
+                 character to a hex character.";
+  }
+  
+  typedef Osi-area-address {
+    type string {
+      pattern "[a-fA-F0-9]{2}(\.[a-fA-F0-9]{4}){0,6}";
+    }
+    description "An OSI area address should consist of an odd number
+                 of octets, and be of the form 01 or 01.2345 etc up
+                 to 01.2345.6789.abcd.ef01.2345.6789. This data type
+                 restricts each character to a hex character.";
+  }
+  
+  typedef Isis-node-id {
+    type string {
+      pattern "[a-fA-F0-9]{4}(\.[a-fA-F0-9]{4}){2}\.[a-fA-F0-9]{2}";
+    }
+    description "An ISIS node ID should be of the form 
+                 0123.4567.89ab.cd. This data type restricts each
+                 character to a hex character.";
+  }
+  
+  typedef Isis-snpa {
+    type string {
+      pattern "[a-fA-F0-9]{4}(\.[a-fA-F0-9]{4}){2}";
+    }
+    description "String representation of a SNPA, 802.2 MAC address
+                 in canonical format, e.g. 0123.4567.89ab";
+  }
+  
+  typedef Isis-lsp-id {
+    type string {
+      pattern "[a-fA-F0-9]{4}(\.[a-fA-F0-9]{4}){2}\.[a-fA-F0-9]{2}"+
+               "\-[a-fA-F0-9]{2}";
+    }
+    description "An ISIS LSP ID should be of the form 
+                 0123.4567.89ab.cd-ef. This data type restricts each
+                 character to a hex character.";
+  }
+  
+  typedef Osi-net {
+    type string {
+      pattern 
+        "[a-fA-F0-9]{2}(\.[a-fA-F0-9]{4}){3,9}\.[a-fA-F0-9]{2}";
+    }
+    description "An OSI NET should consist of an even number of 
+                 octets, and be of the form 01.2345.6789.abcd.ef etc
+                 up to 
+                 01.2345.6789.abcd.ef01.2345.6789.abcd.ef01.2345.67.
+                 This data type restricts each character to a hex
+                 character.";
+  }
+  
+  typedef String-identifier {
+    type string {
+      pattern "[a-zA-Z][\w\-]*";
+    }
+    description "A string for specifying identifier.";
+  }
+
+  typedef Extended-node-id {
+    type string {
+      pattern "([a-zA-Z0-9_]*\d+/){3}([a-zA-Z0-9_]*\d+)";
+    }
+    description "A location used as value information and specified
+                 as a Rack/Slot/Instance/SubInstance, e.g. 
+                 0/1/CPU0/NPU0";
+  }
+  
+  typedef Node-id {
+    type string {
+      pattern "([a-zA-Z0-9_]*\d+/){2}([a-zA-Z0-9_]*\d+)";
+    }
+    description "A location used as value information and specified
+                 as a Rack/Slot/Instance triple, e.g. F0/SC1/0.";
+  }
+
+  typedef Pq-node-id {
+    type string {
+      pattern "((([a-zA-Z0-9_]*\d+)|(\*))/){2}(([a-zA-Z0-9_]*\d+)"+
+              "|(\*))";
+    }
+    description "Partially qualified location which is used for 
+                 wildcarding location specifications, e.g. 1/*/*";
+  }  
+  
+  typedef Md5-password {
+    type string {
+      pattern "(!.+)|([^!].+)";
+    }
+    description 
+      "The Md5-password type is used to store password using the MD5
+       hash function.
+       When a clear text value is set to a leaf of this type, the
+       server calculates a password hash and stores the result
+       in the datastore. The password is never stored in clear text.
+
+       When a leaf of this type is read, the stored password hash is
+       returned.
+
+       A value of this type matches one of the forms:
+
+         !<clear text password>
+         <password hash>
+         
+       The '!' prefix signals that the value is clear text. When
+       such a value is received by the server, a hash value is
+       calculated. This value is stored in the configuration data 
+       store.
+
+       If a value starting without '!' is received, the server knows 
+       that the value already represents a hashed value, and stores 
+       it as is in the data store.";
+  }
+  
+  typedef Proprietary-password {
+    type string {
+      pattern "(!.+)|([^!].+)";
+    }
+    description 
+      "The Proprietary-password type is used to store password 
+       using the Cisco proprietary hash function.
+       When a clear text value is set to a leaf of this type, the
+       server calculates a password hash and stores the result
+       in the datastore. The password is never stored in clear text.
+
+       When a leaf of this type is read, the stored password hash is
+       returned.
+
+       A value of this type matches one of the forms:
+
+         !<clear text password>
+         <password hash>
+         
+       The '!' prefix signals that the value is clear text. When
+       such a value is received by the server, a hash value is
+       calculated. This value is stored in the configuration data 
+       store.
+
+       If a value starting without '!' is received, the server knows 
+       that the value already represents a hashed value, and stores 
+       it as is in the data store.";
+  }
+  
+  typedef Bgp-ipv4-flowspec-address {
+    type string {
+      pattern "[a-fA-F0-9]{4096}";
+    }
+    description "An IPV4 Flowspec address in hexadecimal notation.";
+  }
+
+  typedef Bgp-ipv6-flowspec-address {
+    type string {
+      pattern "[a-fA-F0-9]{4096}";
+    }
+    description "An IPV6 Flowspec address in hexadecimal notation.";
+  }
+}
diff --git a/netconf/tools/netconf-test-perf/src/main/yang/Example-notifications@2015-06-11.yang b/netconf/tools/netconf-test-perf/src/main/yang/Example-notifications@2015-06-11.yang
new file mode 100644 (file)
index 0000000..18412c2
--- /dev/null
@@ -0,0 +1,24 @@
+module Example-notifications {
+
+  namespace "org:opendaylight:coretutorials:ncmount:example:notifications";
+
+  prefix "ex-not";
+
+  import Cisco-IOS-XR-ip-static-cfg { prefix "ip-static-cfg"; }
+
+  description
+    "Sample model used for notification utilization demonstration.
+    This model is not used by XR or any other netconf server.";
+
+  revision "2015-06-11" {
+    description
+      "Initial revision.";
+  }
+
+  notification vrf-route-notification {
+    uses ip-static-cfg:VRF-PREFIX-TABLE;
+    description "Artificial notification based on Cisco-IOS-XR-ip-static-cfg model";
+  }
+
+
+}
\ No newline at end of file
index 1f5d483f01d6a3c5cc71ee64a17746c08facb6d6..40069e31a149608641d142a3df9978680ce94dc7 100644 (file)
@@ -28,6 +28,7 @@
   </properties>
 
   <modules>
+    <module>netconf-test-perf</module>
     <module>netconf-testtool</module>
   </modules>
 </project>