@line 36: **delegated-lsps-count** - The number of delegated LSPs (tunnels) from PCC.
@line 37: **synchronized** - Represents synchronization status.
+
+
+Following RPC can be used to fetch PCEP session statistics. If PCEP topology and/or PCC node is not specified in input,
+statistics for all PCEP sessions under the context are returned.
+
+Usage
+'''''
+
+**URL:** ``/restconf/operations/pcep-topology-stats-rpc:get-stats``
+
+**Method:** ``POST``
+
+**Content-Type:** ``application/xml``
+
+**Request Body:**
+
+.. code-block:: xml
+
+ <input xmlns="urn:opendaylight:params:xml:ns:yang:pcep:topology:stats:rpc">
+ <topology>
+ <topology-id>pcep-topology</topology-id>
+ <node>
+ <node-id>pcc://43.43.43.43</node-id>
+ </node>
+ </topology>
+ </input>
+
+**Response Body:**
+
+.. code-block:: xml
+
+ <output xmlns="urn:opendaylight:params:xml:ns:yang:pcep:topology:stats:rpc">
+ <topology>
+ <topology-id>pcep-topology</topology-id>
+ <node>
+ <node-id>pcc://43.43.43.43</node-id>
+ <pcep-session-state>
+ <synchronized>true</synchronized>
+ <peer-capabilities>
+ <stateful xmlns="urn:opendaylight:params:xml:ns:yang:pcep:stateful:stats">true</stateful>
+ <instantiation xmlns="urn:opendaylight:params:xml:ns:yang:pcep:stateful:stats">true</instantiation>
+ <active xmlns="urn:opendaylight:params:xml:ns:yang:pcep:stateful:stats">true</active>
+ </peer-capabilities>
+ <local-pref>
+ <keepalive>30</keepalive>
+ <deadtimer>120</deadtimer>
+ <session-id>1</session-id>
+ <ip-address>127.0.0.1</ip-address>
+ </local-pref>
+ <session-duration>4:01:59:46</session-duration>
+ <messages>
+ <unknown-msg-received>0</unknown-msg-received>
+ <received-msg-count>11752</received-msg-count>
+ <error-messages>
+ <last-sent-error>
+ <error-type>0</error-type>
+ <error-value>0</error-value>
+ </last-sent-error>
+ <received-error-msg-count>0</received-error-msg-count>
+ <last-received-error>
+ <error-type>0</error-type>
+ <error-value>0</error-value>
+ </last-received-error>
+ <sent-error-msg-count>0</sent-error-msg-count>
+ </error-messages>
+ <sent-msg-count>11759</sent-msg-count>
+ <last-sent-msg-timestamp>1553547804</last-sent-msg-timestamp>
+ <reply-time>
+ <average-time>0</average-time>
+ <min-time>0</min-time>
+ <max-time>0</max-time>
+ </reply-time>
+ <received-rpt-msg-count xmlns="urn:opendaylight:params:xml:ns:yang:pcep:stateful:stats">1</received-rpt-msg-count>
+ <sent-init-msg-count xmlns="urn:opendaylight:params:xml:ns:yang:pcep:stateful:stats">0</sent-init-msg-count>
+ <last-received-rpt-msg-timestamp xmlns="urn:opendaylight:params:xml:ns:yang:pcep:stateful:stats">1553195032</last-received-rpt-msg-timestamp>
+ <sent-upd-msg-count xmlns="urn:opendaylight:params:xml:ns:yang:pcep:stateful:stats">0</sent-upd-msg-count>
+ </messages>
+ <peer-pref>
+ <keepalive>30</keepalive>
+ <deadtimer>120</deadtimer>
+ <session-id>8</session-id>
+ <ip-address>127.0.0.1</ip-address>
+ </peer-pref>
+ <delegated-lsps-count>0</delegated-lsps-count>
+ </pcep-session-state>
+ </node>
+ </topology>
+ </output>
import network-topology { prefix nt; revision-date 2013-10-21; }
import network-topology-pcep { prefix pn; revision-date 2018-11-09; }
import yang-ext { prefix ext; revision-date 2013-07-09; }
- import pcep-session-stats { prefix pss; revision-date 2017-11-13; }
import network-pcep-topology-stats { prefix npts; revision-date 2018-11-09; }
import odl-pcep-sync-optimizations { prefix opso; revision-date 2018-11-09; }
+ import pcep-topology-stats-rpc { prefix ptsr; revision-date 2019-03-21; }
description
"This module contains the PCEP Stateful stats YANG definitions for
uses stateful-messages-grouping;
}
+ augment "/ptsr:get-stats/ptsr:output/ptsr:topology/ptsr:node/ptsr:pcep-session-state/ptsr:messages" {
+ ext:augment-identifier stateful-messages-rpc-aug;
+ description "Augment Pcep session stats RPC output with Stateful session stats";
+
+ uses stateful-messages-grouping;
+ }
+
grouping stateful-preferences {
leaf instantiation {
description "Represents peer's instantiation capability.";
uses stateful-preferences;
}
+ augment "/ptsr:get-stats/ptsr:output/ptsr:topology/ptsr:node/ptsr:pcep-session-state/ptsr:peer-capabilities" {
+ ext:augment-identifier stateful-capabilities-rpc-aug;
+ description "Augment Pcep session stats RPC output with Remote peer's (PCC) advertised stateful capabilities.";
+
+ uses stateful-preferences;
+ }
+
augment "/nt:network-topology/nt:topology/nt:node/npts:pcep-session-state/npts:local-pref" {
when "../../../nt:topology-types/pn:topology-pcep";
ext:augment-identifier pcep-entity-id-stats-aug;
uses opso:speaker-entity-id;
}
-}
\ No newline at end of file
+
+ augment "/ptsr:get-stats/ptsr:output/ptsr:topology/ptsr:node/ptsr:pcep-session-state/ptsr:local-pref" {
+ ext:augment-identifier pcep-entity-id-rpc-aug;
+ description "Augment Pcep session stats RPC output with PCEP Entity Identifier";
+
+ uses opso:speaker-entity-id;
+ }
+}
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module pcep-topology-stats-rpc {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:pcep:topology:stats:rpc";
+ prefix ptsr;
+
+ import network-topology { prefix nt; revision-date 2013-10-21; }
+ import pcep-session-stats { prefix pss; revision-date 2017-11-13; }
+
+ description
+ "This module contains rpc for fetching PCEP session statistics.
+
+ Copyright (c) 2019 Lumina Networks, Inc. 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";
+
+ organization "Lumina Networks, Inc.";
+ contact "Ajay Lele <alele@luminanetworks.com>";
+
+ revision "2019-03-21" {
+ description
+ "Initial revision.";
+ }
+
+ rpc get-stats {
+ description
+ "Fetch PCEP session statistics for given PCEP topology and node.
+ If topology and/or node details are absent, statistics for all
+ nodes under the context are returned.";
+ input {
+ list topology {
+ key "topology-id";
+ leaf topology-id {
+ type nt:topology-id;
+ }
+ list node {
+ key "node-id";
+ leaf node-id {
+ type nt:node-id;
+ }
+ }
+ }
+ }
+ output {
+ list topology {
+ key "topology-id";
+ leaf topology-id {
+ type nt:topology-id;
+ }
+ list node {
+ key "node-id";
+ leaf node-id {
+ type nt:node-id;
+ }
+ uses pss:pcep-session-state-grouping;
+ }
+ }
+ }
+ }
+}
<groupId>${project.groupId}</groupId>
<artifactId>pcep-topology-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>pcep-ietf-stateful07</artifactId>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>pcep-topology-spi</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>programming-spi</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-binding-api</artifactId>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
+ <!--Test dependencies-->
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-dom-adapter</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-dom-adapter</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<scm>
<url>https://wiki.opendaylight.org/view/BGP_LS_PCEP:Main</url>
<tag>HEAD</tag>
</scm>
-</project>
\ No newline at end of file
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2019 Lumina Networks, Inc. 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.bgpcep.pcep.topology.stats.rpc;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Collectors;
+import org.opendaylight.bgpcep.programming.spi.SuccessfulRpcResult;
+import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.DataObjectModification;
+import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
+import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.PcepEntityIdRpcAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.PcepEntityIdRpcAugBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.PcepEntityIdStatsAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulCapabilitiesRpcAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulCapabilitiesRpcAugBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulCapabilitiesStatsAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulMessagesRpcAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulMessagesRpcAugBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulMessagesStatsAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.LocalPref;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.LocalPrefBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.Messages;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.MessagesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.PeerCapabilities;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.PeerCapabilitiesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.grouping.PcepSessionState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.grouping.PcepSessionStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.GetStatsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.GetStatsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.GetStatsOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.PcepTopologyStatsRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.stats.rev181109.PcepTopologyNodeStatsAug;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TopologyStatsRpcServiceImpl
+ implements PcepTopologyStatsRpcService, ClusteredDataTreeChangeListener<PcepSessionState>, AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(TopologyStatsRpcServiceImpl.class);
+
+ private final DataBroker dataBroker;
+ private final ConcurrentMap<InstanceIdentifier<PcepSessionState>, PcepSessionState> sessionStateMap =
+ new ConcurrentHashMap<>();
+ private ListenerRegistration<TopologyStatsRpcServiceImpl> listenerRegistration;
+
+ public TopologyStatsRpcServiceImpl(final DataBroker dataBroker) {
+ this.dataBroker = requireNonNull(dataBroker);
+ }
+
+ public synchronized void init() {
+ LOG.info("Initializing PCEP Topology Stats RPC service.");
+ this.listenerRegistration = this.dataBroker.registerDataTreeChangeListener(
+ DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL,
+ InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class).child(Node.class)
+ .augmentation(PcepTopologyNodeStatsAug.class).child(PcepSessionState.class).build()),
+ this);
+ }
+
+ @Override
+ public void onDataTreeChanged(final Collection<DataTreeModification<PcepSessionState>> changes) {
+ changes.forEach(change -> {
+ final InstanceIdentifier<PcepSessionState> iid = change.getRootPath().getRootIdentifier();
+ final DataObjectModification<PcepSessionState> mod = change.getRootNode();
+ switch (mod.getModificationType()) {
+ case SUBTREE_MODIFIED:
+ case WRITE:
+ sessionStateMap.put(iid, mod.getDataAfter());
+ break;
+ case DELETE:
+ sessionStateMap.remove(iid);
+ break;
+ default:
+ }
+ });
+ }
+
+ @Override
+ public synchronized void close() {
+ LOG.info("Closing PCEP Topology Stats RPC service.");
+ if (this.listenerRegistration != null) {
+ this.listenerRegistration.close();
+ this.listenerRegistration = null;
+ }
+ }
+
+ @Override
+ @SuppressWarnings("checkstyle:LineLength")
+ public ListenableFuture<RpcResult<GetStatsOutput>> getStats(final GetStatsInput input) {
+ final List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.input.Topology> iTopologies =
+ input.getTopology();
+ final List<TopologyId> iTopologyIds;
+ if (iTopologies != null) {
+ iTopologyIds = iTopologies.stream().map(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.input.Topology::getTopologyId)
+ .collect(Collectors.toList());
+ } else {
+ iTopologyIds = getAvailableTopologyIds();
+ }
+
+ final List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.output.Topology> oTopologies =
+ new ArrayList<>();
+ iTopologyIds.forEach(iTopologyId -> {
+ final List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.input.topology.Node> iNodes;
+ if (input.getTopology() != null) {
+ iNodes = input.getTopology().stream().filter(t -> t.getTopologyId().equals(iTopologyId)).findFirst()
+ .get().getNode();
+ } else {
+ iNodes = null;
+ }
+
+ final List<NodeId> iNodeIds;
+ if (iNodes != null) {
+ iNodeIds = iNodes.stream().map(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.input.topology.Node::getNodeId)
+ .collect(Collectors.toList());
+ } else {
+ iNodeIds = getAvailableNodeIds(iTopologyId);
+ }
+
+ final List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.output.topology.Node> oNodes =
+ new ArrayList<>();
+ iNodeIds.forEach(iNodeId -> {
+ final InstanceIdentifier<PcepSessionState> iid = InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(iTopologyId)).child(Node.class, new NodeKey(iNodeId))
+ .augmentation(PcepTopologyNodeStatsAug.class).child(PcepSessionState.class).build();
+ if (!sessionStateMap.containsKey(iid)) {
+ LOG.debug("Pcep session stats not available for node {} in topology {}", iNodeId.getValue(),
+ iTopologyId.getValue());
+ }
+ oNodes.add(
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.output.topology.NodeBuilder()
+ .setNodeId(iNodeId)
+ .setPcepSessionState(transformStatefulAugmentation(sessionStateMap.get(iid))).build());
+ });
+
+ oTopologies.add(
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.output.TopologyBuilder()
+ .setTopologyId(iTopologyId).setNode(oNodes).build());
+ });
+
+ final RpcResult<GetStatsOutput> res =
+ SuccessfulRpcResult.create(new GetStatsOutputBuilder().setTopology(oTopologies).build());
+ return Futures.immediateFuture(res);
+ }
+
+ /*
+ * Replace stateful topology augmentations with ones for rpc in PCEP session
+ * stats data
+ */
+ private PcepSessionState transformStatefulAugmentation(final PcepSessionState pcepSessionState) {
+ if (pcepSessionState == null) {
+ return null;
+ }
+
+ final PcepSessionStateBuilder sb = new PcepSessionStateBuilder(pcepSessionState);
+
+ final Messages topoMessage = pcepSessionState.getMessages();
+ if (topoMessage != null) {
+ final StatefulMessagesStatsAug messageStatsAug = topoMessage.augmentation(StatefulMessagesStatsAug.class);
+ if (messageStatsAug != null) {
+ final StatefulMessagesRpcAug messageRpcAug = new StatefulMessagesRpcAugBuilder()
+ .setLastReceivedRptMsgTimestamp(messageStatsAug.getLastReceivedRptMsgTimestamp())
+ .setReceivedRptMsgCount(messageStatsAug.getReceivedRptMsgCount())
+ .setSentInitMsgCount(messageStatsAug.getSentInitMsgCount())
+ .setSentUpdMsgCount(messageStatsAug.getSentUpdMsgCount()).build();
+ sb.setMessages(new MessagesBuilder(topoMessage).removeAugmentation(StatefulMessagesStatsAug.class)
+ .addAugmentation(StatefulMessagesRpcAug.class, messageRpcAug).build());
+ }
+ }
+
+ final PeerCapabilities topoPeerCapability = pcepSessionState.getPeerCapabilities();
+ if (topoPeerCapability != null) {
+ final StatefulCapabilitiesStatsAug capabilityStatsAug =
+ topoPeerCapability.augmentation(StatefulCapabilitiesStatsAug.class);
+ if (capabilityStatsAug != null) {
+ final StatefulCapabilitiesRpcAug capabilityRpcAug = new StatefulCapabilitiesRpcAugBuilder()
+ .setActive(capabilityStatsAug.isActive()).setInstantiation(capabilityStatsAug.isInstantiation())
+ .setStateful(capabilityStatsAug.isStateful()).build();
+ sb.setPeerCapabilities(new PeerCapabilitiesBuilder(topoPeerCapability)
+ .removeAugmentation(StatefulCapabilitiesStatsAug.class)
+ .addAugmentation(StatefulCapabilitiesRpcAug.class, capabilityRpcAug).build());
+ }
+ }
+
+ final LocalPref topoLocalPref = pcepSessionState.getLocalPref();
+ if (topoLocalPref != null) {
+ final PcepEntityIdStatsAug entityStatsAug = topoLocalPref.augmentation(PcepEntityIdStatsAug.class);
+ if (entityStatsAug != null) {
+ final PcepEntityIdRpcAug entityRpcAug = new PcepEntityIdRpcAugBuilder()
+ .setSpeakerEntityIdValue(entityStatsAug.getSpeakerEntityIdValue()).build();
+ sb.setLocalPref(new LocalPrefBuilder(topoLocalPref).removeAugmentation(PcepEntityIdStatsAug.class)
+ .addAugmentation(PcepEntityIdRpcAug.class, entityRpcAug).build());
+ }
+ }
+
+ return sb.build();
+ }
+
+ private List<TopologyId> getAvailableTopologyIds() {
+ return sessionStateMap.keySet().stream().map(iid -> iid.firstKeyOf(Topology.class).getTopologyId()).distinct()
+ .collect(Collectors.toList());
+ }
+
+ private List<NodeId> getAvailableNodeIds(final TopologyId topologyId) {
+ return sessionStateMap.keySet().stream()
+ .filter(iid -> iid.firstKeyOf(Topology.class).getTopologyId().equals(topologyId))
+ .map(iid -> iid.firstKeyOf(Node.class).getNodeId()).collect(Collectors.toList());
+ }
+}
<odl:clustered-app-config id="pcepStatsConfig"
binding-class="org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.pcep.stats.provider.config.rev171113.PcepProvider"/>
+ <bean id="topologyStatsRpcService"
+ class="org.opendaylight.bgpcep.pcep.topology.stats.rpc.TopologyStatsRpcServiceImpl"
+ init-method="init" destroy-method="close">
+ <argument ref="dataBroker"/>
+ </bean>
+ <odl:rpc-implementation ref="topologyStatsRpcService"/>
+
<bean id="topologyStatsRegistry"
class="org.opendaylight.bgpcep.pcep.topology.stats.provider.TopologyStatsProviderImpl"
init-method="init" destroy-method="close">
</bean>
<service ref="topologyStatsRegistry"
interface="org.opendaylight.bgpcep.pcep.topology.spi.stats.TopologySessionStatsRegistry"/>
-</blueprint>
\ No newline at end of file
+</blueprint>
--- /dev/null
+/*
+ * Copyright (c) 2019 Lumina Networks, Inc. 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.bgpcep.pcep.topology.stats.rpc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.mdsal.binding.api.WriteTransaction;
+import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractConcurrentDataBrokerTest;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.PcepEntityIdRpcAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.PcepEntityIdRpcAugBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.PcepEntityIdStatsAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.PcepEntityIdStatsAugBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulCapabilitiesRpcAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulCapabilitiesRpcAugBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulCapabilitiesStatsAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulCapabilitiesStatsAugBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulMessagesRpcAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulMessagesRpcAugBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulMessagesStatsAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulMessagesStatsAugBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.error.messages.grouping.ErrorMessages;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.error.messages.grouping.ErrorMessagesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.LocalPref;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.LocalPrefBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.Messages;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.MessagesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.PeerCapabilities;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.PeerCapabilitiesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.PeerPrefBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.grouping.PcepSessionState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.grouping.PcepSessionStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.reply.time.grouping.ReplyTime;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.reply.time.grouping.ReplyTimeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.GetStatsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.GetStatsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.GetStatsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.GetStatsOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.stats.rev181109.PcepTopologyNodeStatsAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.stats.rev181109.PcepTopologyNodeStatsAugBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class TopologyStatsRpcServiceImplTest extends AbstractConcurrentDataBrokerTest {
+ private static final String TOPOLOGY_ID1 = "pcep-topology-1";
+ private static final String TOPOLOGY_ID2 = "pcep-topology-2";
+ private static final String NONEXISTENT_TOPOLOGY = "nonexistent-topology";
+ private static final String NONPCEP_TOPOLOGY = "nonpcep-topology";
+ private static final String NODE_ID1 = "pcc://1.1.1.1";
+ private static final String NODE_ID2 = "pcc://2.2.2.2";
+ private static final String NODE_ID3 = "pcc://3.3.3.3";
+ private static final String NONEXISTENT_NODE = "pcc://4.4.4.4";
+ private static final String NONPCEP_NODE = "nonpcep-node";
+
+ TopologyStatsRpcServiceImpl rpcService;
+
+ @Before
+ public void setUp() throws Exception {
+ rpcService = new TopologyStatsRpcServiceImpl(getDataBroker());
+ rpcService.init();
+
+ // PCEP topology with one PCC node
+ final Topology t1 = createTopology(TOPOLOGY_ID1, Collections.singletonList(createPcepNode(NODE_ID1)));
+
+ // PCEP topology with two PCC node
+ final Topology t2 =
+ createTopology(TOPOLOGY_ID2, Arrays.asList(createPcepNode(NODE_ID2), createPcepNode(NODE_ID3)));
+
+ // Non-PCEP topology with one non-PCC node
+ final Topology t3 = createTopology(NONPCEP_TOPOLOGY,
+ Collections.singletonList(new NodeBuilder().setNodeId(new NodeId(NONPCEP_NODE)).build()));
+
+ final WriteTransaction wtx = getDataBroker().newWriteOnlyTransaction();
+ final NetworkTopologyBuilder ntb = new NetworkTopologyBuilder();
+ ntb.setTopology(Arrays.asList(t1, t2, t3));
+ wtx.put(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(NetworkTopology.class).build(),
+ ntb.build());
+ wtx.commit().get();
+ }
+
+ private Topology createTopology(final String topologyId, final List<Node> nodes) {
+ return new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).setNode(nodes).build();
+ }
+
+ private Node createPcepNode(final String nodeId) {
+ return new NodeBuilder().setNodeId(new NodeId(nodeId))
+ .addAugmentation(PcepTopologyNodeStatsAug.class,
+ new PcepTopologyNodeStatsAugBuilder().setPcepSessionState(createTopologySessionState()).build())
+ .build();
+ }
+
+ private PcepSessionState createTopologySessionState() {
+ final ReplyTime replyTime = new ReplyTimeBuilder().setAverageTime(1L).setMaxTime(3L).setMinTime(2L).build();
+
+ final ErrorMessages errorMsg =
+ new ErrorMessagesBuilder().setReceivedErrorMsgCount(1L).setSentErrorMsgCount(2L).build();
+
+ final StatefulMessagesStatsAug statefulMsg =
+ new StatefulMessagesStatsAugBuilder().setLastReceivedRptMsgTimestamp(1553183614L).setSentUpdMsgCount(1L)
+ .setReceivedRptMsgCount(2L).setSentInitMsgCount(3L).build();
+
+ final Messages messages = new MessagesBuilder().setLastSentMsgTimestamp(1553183734L).setUnknownMsgReceived(1)
+ .setSentMsgCount(5L).setReceivedMsgCount(4L).setReplyTime(replyTime).setErrorMessages(errorMsg)
+ .addAugmentation(StatefulMessagesStatsAug.class, statefulMsg).build();
+
+ final PeerCapabilities capabilities = new PeerCapabilitiesBuilder()
+ .addAugmentation(StatefulCapabilitiesStatsAug.class, new StatefulCapabilitiesStatsAugBuilder()
+ .setStateful(true).setInstantiation(true).setActive(true).build())
+ .build();
+
+ final LocalPref localPref =
+ new LocalPrefBuilder().setKeepalive((short) 30).setDeadtimer((short) 120).setIpAddress("127.0.0.1")
+ .setSessionId(0).addAugmentation(PcepEntityIdStatsAug.class, new PcepEntityIdStatsAugBuilder()
+ .setSpeakerEntityIdValue(new byte[] {0x01, 0x02, 0x03, 0x04}).build())
+ .build();
+
+ return new PcepSessionStateBuilder().setSynchronized(true).setSessionDuration("0:00:05:18")
+ .setDelegatedLspsCount(1).setLocalPref(localPref).setPeerPref(new PeerPrefBuilder(localPref).build())
+ .setPeerCapabilities(capabilities).setMessages(messages).build();
+ }
+
+ private PcepSessionState createRpcSessionState() {
+ final ReplyTime replyTime = new ReplyTimeBuilder().setAverageTime(1L).setMaxTime(3L).setMinTime(2L).build();
+
+ final ErrorMessages errorMsg =
+ new ErrorMessagesBuilder().setReceivedErrorMsgCount(1L).setSentErrorMsgCount(2L).build();
+
+ final StatefulMessagesRpcAug statefulMsg =
+ new StatefulMessagesRpcAugBuilder().setLastReceivedRptMsgTimestamp(1553183614L).setSentUpdMsgCount(1L)
+ .setReceivedRptMsgCount(2L).setSentInitMsgCount(3L).build();
+
+ final Messages messages = new MessagesBuilder().setLastSentMsgTimestamp(1553183734L).setUnknownMsgReceived(1)
+ .setSentMsgCount(5L).setReceivedMsgCount(4L).setReplyTime(replyTime).setErrorMessages(errorMsg)
+ .addAugmentation(StatefulMessagesRpcAug.class, statefulMsg).build();
+
+ final PeerCapabilities capabilities = new PeerCapabilitiesBuilder()
+ .addAugmentation(StatefulCapabilitiesRpcAug.class, new StatefulCapabilitiesRpcAugBuilder()
+ .setStateful(true).setInstantiation(true).setActive(true).build())
+ .build();
+
+ final LocalPref localPref =
+ new LocalPrefBuilder().setKeepalive((short) 30).setDeadtimer((short) 120).setIpAddress("127.0.0.1")
+ .setSessionId(0).addAugmentation(PcepEntityIdRpcAug.class, new PcepEntityIdRpcAugBuilder()
+ .setSpeakerEntityIdValue(new byte[] {0x01, 0x02, 0x03, 0x04}).build())
+ .build();
+
+ return new PcepSessionStateBuilder().setSynchronized(true).setSessionDuration("0:00:05:18")
+ .setDelegatedLspsCount(1).setLocalPref(localPref).setPeerPref(new PeerPrefBuilder(localPref).build())
+ .setPeerCapabilities(capabilities).setMessages(messages).build();
+ }
+
+ @Test
+ public void testGetStatsNoMatch() throws Exception {
+ GetStatsInput in;
+ GetStatsOutput out;
+
+ // Non-existing topology
+ in = createGetStatsInput(NONEXISTENT_TOPOLOGY, null);
+ out = createGetStatsOutput(NONEXISTENT_TOPOLOGY, Collections.emptyList(), null);
+ performTest(in, out);
+
+ // Non-existent node
+ in = createGetStatsInput(TOPOLOGY_ID1, Collections.singletonList(NONEXISTENT_NODE));
+ out = createGetStatsOutput(TOPOLOGY_ID1, Collections.singletonList(NONEXISTENT_NODE), null);
+ performTest(in, out);
+
+ // Non-PCEP topology
+ in = createGetStatsInput(NONPCEP_TOPOLOGY, Collections.singletonList(NONPCEP_NODE));
+ out = createGetStatsOutput(NONPCEP_TOPOLOGY, Collections.singletonList(NONPCEP_NODE), null);
+ performTest(in, out);
+ }
+
+ @Test
+ public void testGetStatsPartialMatch() throws Exception {
+ GetStatsInput in;
+ GetStatsOutput out;
+
+ // Match one PCEP topology
+ in = createGetStatsInput(TOPOLOGY_ID1, null);
+ out = createGetStatsOutput(TOPOLOGY_ID1, Collections.singletonList(NODE_ID1), createRpcSessionState());
+ performTest(in, out);
+
+ // Match one PCEP node in one topology
+ in = createGetStatsInput(TOPOLOGY_ID2, Collections.singletonList(NODE_ID3));
+ out = createGetStatsOutput(TOPOLOGY_ID2, Collections.singletonList(NODE_ID3), createRpcSessionState());
+ performTest(in, out);
+
+ // Match two PCEP nodes in one topology
+ in = createGetStatsInput(TOPOLOGY_ID2, Arrays.asList(NODE_ID2, NODE_ID3));
+ out = createGetStatsOutput(TOPOLOGY_ID2, Arrays.asList(NODE_ID2, NODE_ID3), createRpcSessionState());
+ performCountTest(in, out);
+ }
+
+ @Test
+ @SuppressWarnings("checkstyle:LineLength")
+ public void testGetStatsAllMatch() throws Exception {
+ GetStatsInput in;
+
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.output.Topology ot1 =
+ createGetStatsOutput(TOPOLOGY_ID1, Collections.singletonList(NODE_ID1), createRpcSessionState())
+ .getTopology().get(0);
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.output.Topology ot2 =
+ createGetStatsOutput(TOPOLOGY_ID2, Arrays.asList(NODE_ID2, NODE_ID3), createRpcSessionState())
+ .getTopology().get(0);
+ final GetStatsOutput out = new GetStatsOutputBuilder().setTopology(Arrays.asList(ot1, ot2)).build();
+
+ // Implicitly match all PCEP topologies and nodes
+ in = createGetStatsInput(null, null);
+ performCountTest(in, out);
+
+ // Explicitly match all PCEP topologies and nodes
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.input.Topology it1 =
+ createGetStatsInput(TOPOLOGY_ID1, Collections.singletonList(NODE_ID1)).getTopology().get(0);
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.input.Topology it2 =
+ createGetStatsInput(TOPOLOGY_ID2, Arrays.asList(NODE_ID2, NODE_ID3)).getTopology().get(0);
+ in = new GetStatsInputBuilder().setTopology(Arrays.asList(it1, it2)).build();
+ performCountTest(in, out);
+ }
+
+ private void performTest(final GetStatsInput in, final GetStatsOutput out) throws Exception {
+ final RpcResult<GetStatsOutput> result = rpcService.getStats(in).get();
+ assertEquals(result.getResult(), out);
+ assertTrue(result.isSuccessful());
+ assertTrue(result.getErrors().isEmpty());
+ }
+
+ /*
+ * When topology and/or node list is expected to contain more than one item,
+ * direct comparison will fail due to potential list ordering differences. So
+ * just compare the number of nodes
+ */
+ private void performCountTest(final GetStatsInput in, final GetStatsOutput out) throws Exception {
+ final RpcResult<GetStatsOutput> result = rpcService.getStats(in).get();
+ assertEquals(result.getResult().getTopology().size(), out.getTopology().size());
+ assertTrue(result.isSuccessful());
+ assertEquals(result.getResult().getTopology().stream().flatMap(t -> t.getNode().stream()).count(),
+ out.getTopology().stream().flatMap(t -> t.getNode().stream()).count());
+ assertTrue(result.isSuccessful());
+ assertTrue(result.getErrors().isEmpty());
+ }
+
+ @SuppressWarnings("checkstyle:LineLength")
+ private GetStatsInput createGetStatsInput(final String topologyId, final List<String> nodeIds) {
+ final List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.input.topology.Node> nodes;
+ if (nodeIds != null) {
+ nodes = nodeIds.stream().map(
+ nodeId -> new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.input.topology.NodeBuilder()
+ .setNodeId(new NodeId(nodeId)).build())
+ .collect(Collectors.toList());
+ } else {
+ nodes = null;
+ }
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.input.Topology topology;
+ if (topologyId != null) {
+ topology =
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.input.TopologyBuilder()
+ .setTopologyId(new TopologyId(topologyId)).setNode(nodes).build();
+ } else {
+ topology = null;
+ }
+ return new GetStatsInputBuilder().setTopology(topology != null ? Collections.singletonList(topology) : null)
+ .build();
+ }
+
+ @SuppressWarnings("checkstyle:LineLength")
+ private GetStatsOutput createGetStatsOutput(final String topologyId, final List<String> nodeIds,
+ final PcepSessionState state) {
+ final List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.output.topology.Node> nodes;
+ if (nodeIds != null) {
+ nodes = nodeIds.stream().map(
+ nodeId -> new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.output.topology.NodeBuilder()
+ .setNodeId(new NodeId(nodeId)).setPcepSessionState(state).build())
+ .collect(Collectors.toList());
+ } else {
+ nodes = null;
+ }
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.output.Topology topology;
+ if (topologyId != null) {
+ topology =
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.get.stats.output.TopologyBuilder()
+ .setTopologyId(new TopologyId(topologyId)).setNode(nodes).build();
+ } else {
+ topology = null;
+ }
+ return new GetStatsOutputBuilder().setTopology(topology != null ? Collections.singletonList(topology) : null)
+ .build();
+ }
+
+ @After
+ public void tearDown() {
+ rpcService.close();
+ }
+}