BUG-48: basic exporter implementation 52/2152/2
authorRobert Varga <rovarga@cisco.com>
Thu, 24 Oct 2013 04:40:44 +0000 (06:40 +0200)
committerRobert Varga <rovarga@cisco.com>
Fri, 25 Oct 2013 12:47:48 +0000 (14:47 +0200)
Change-Id: Ic80b73665f800c13f8772f75bc36fbadf3f8e744
Signed-off-by: Robert Varga <rovarga@cisco.com>
12 files changed:
topology/pcep-api/.project [new file with mode: 0644]
topology/pcep-api/pom.xml [new file with mode: 0644]
topology/pcep-api/src/main/yang/inventory-pcep.yang [new file with mode: 0644]
topology/pcep-api/src/main/yang/network-topology-pcep.yang [new file with mode: 0644]
topology/pom.xml
topology/provider-pcep/.project [new file with mode: 0644]
topology/provider-pcep/pom.xml [new file with mode: 0644]
topology/provider-pcep/src/main/java/org/opendaylight/bgpcep/topology/provider/pcep/BundleActivator.java [new file with mode: 0644]
topology/provider-pcep/src/main/java/org/opendaylight/bgpcep/topology/provider/pcep/ServerSessionManager.java [new file with mode: 0644]
topology/provider-pcep/src/main/java/org/opendaylight/bgpcep/topology/provider/pcep/TopologyExporter.java [new file with mode: 0644]
topology/tunnel-pcep/pom.xml
topology/tunnel-pcep/src/main/yang/topology-tunnel-pcep.yang

diff --git a/topology/pcep-api/.project b/topology/pcep-api/.project
new file mode 100644 (file)
index 0000000..bfc89df
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>topology-pcep-api</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.m2e.core.maven2Builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.m2e.core.maven2Nature</nature>
+       </natures>
+</projectDescription>
diff --git a/topology/pcep-api/pom.xml b/topology/pcep-api/pom.xml
new file mode 100644 (file)
index 0000000..9eceb85
--- /dev/null
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<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.bgpcep</groupId>
+               <artifactId>topology-parent</artifactId>
+               <version>0.3.0-SNAPSHOT</version>
+       </parent>
+
+       <modelVersion>4.0.0</modelVersion>
+       <artifactId>topology-pcep-api</artifactId>
+       <description>Topology PCEP API</description>
+       <packaging>bundle</packaging>
+       <name>${project.artifactId}</name>
+       <prerequisites>
+               <maven>3.0.4</maven>
+       </prerequisites>
+
+       <dependencies>
+               <dependency>
+                       <groupId>${project.groupId}</groupId>
+                       <artifactId>pcep-api</artifactId>
+            <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>${project.groupId}</groupId>
+                       <artifactId>topology-api</artifactId>
+            <version>${project.version}</version>
+               </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-binding</artifactId>
+            <version>${yang.binding.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-common</artifactId>
+            <version>${yangtools.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.controller.model</groupId>
+            <artifactId>model-inventory</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+       </dependencies>
+
+       <build>
+        <plugins>
+           <plugin>
+               <groupId>org.opendaylight.yangtools</groupId>
+               <artifactId>yang-maven-plugin</artifactId>
+               <version>${yangtools.version}</version>
+               <executions>
+                   <execution>
+                       <goals>
+                           <goal>generate-sources</goal>
+                       </goals>
+                       <configuration>
+                           <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+                           <codeGenerators>
+                               <generator>
+                                   <codeGeneratorClass>
+                                       org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+                                   </codeGeneratorClass>
+                                   <outputBaseDir>
+                                       target/generated-sources/sal
+                                   </outputBaseDir>
+                               </generator>
+                           </codeGenerators>
+                           <inspectDependencies>true</inspectDependencies>
+                       </configuration>
+                   </execution>
+               </executions>
+               <dependencies>
+                   <dependency>
+                       <groupId>org.opendaylight.yangtools</groupId>
+                       <artifactId>maven-sal-api-gen-plugin</artifactId>
+                       <version>${yang.binding.version}</version>
+                       <type>jar</type>
+                   </dependency>
+               </dependencies>
+           </plugin>
+           <plugin>
+               <groupId>org.apache.felix</groupId>
+               <artifactId>maven-bundle-plugin</artifactId>
+               <version>${maven.bundle.version}</version>
+               <extensions>true</extensions>
+               <configuration>
+                   <instructions>
+                       <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                       <Export-Package>
+                           org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.pcep.rev131024,
+                           org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024,
+                       </Export-Package>
+                   </instructions>
+               </configuration>
+           </plugin>
+               </plugins>
+       </build>
+
+       <distributionManagement>
+               <site>
+                       <id>${project.artifactId}</id>
+                       <name>TOPOLOGY-PCEP-API Module site</name>
+                       <url>${basedir}/target/site/${project.artifactId}</url>
+               </site>
+       </distributionManagement>
+
+</project>
diff --git a/topology/pcep-api/src/main/yang/inventory-pcep.yang b/topology/pcep-api/src/main/yang/inventory-pcep.yang
new file mode 100644 (file)
index 0000000..36150e6
--- /dev/null
@@ -0,0 +1,61 @@
+module inventory-pcep {
+       // vi: set et smarttab sw=4 tabstop=4:
+       yang-version 1;
+       namespace "urn:opendaylight:inventory:pcep";
+       prefix "inv-pcep";
+
+       import network-topology { prefix nt; revision-date 2013-10-21; }
+       import opendaylight-inventory { prefix inv; revision-date 2013-08-19; }
+       import pcep-types { prefix pcep; revision-date 2013-10-05; }
+
+       organization "Cisco Systems, Inc.";
+       contact "Robert Varga <rovarga@cisco.com>";
+
+       description
+               "This module contains the PCEP extensions to base inventory
+               model.
+
+               Copyright (c)2013 Cisco Systems, Inc. All rights reserved.";
+
+       revision "2013-10-24" {
+               description
+                       "Initial revision.";
+               reference "";
+       }
+
+       typedef pcc-sync-state {
+               type enumeration {
+                       enum initial-resync {
+                               description
+                                       "Initial state resynchronization is being performed.";
+                       }
+                       enum synchronized {
+                               description
+                                       "State synchronization has been achieved.";
+                       }
+               }
+       }
+
+       augment "/inv:nodes/inv:node" {
+               container path-computation-client {
+                       description
+                "PCC-related run-time information. This container is only
+                present when the node is connected through PCEP in a PCC
+                role.";
+
+                       container stateful-tlv {
+                               uses pcep:stateful-capability-tlv;
+                       }
+
+                       leaf state-sync {
+                               when "../stateful-tlv";
+                               type pcc-sync-state;
+                       }
+
+            leaf topology-node {
+                type nt:node-ref;
+            }
+               }
+       }
+}
+
diff --git a/topology/pcep-api/src/main/yang/network-topology-pcep.yang b/topology/pcep-api/src/main/yang/network-topology-pcep.yang
new file mode 100644 (file)
index 0000000..f870c72
--- /dev/null
@@ -0,0 +1,47 @@
+module network-topology-pcep {
+       // vi: set et smarttab sw=4 tabstop=4:
+       yang-version 1;
+       namespace "urn:opendaylight:params:xml:ns:yang:topology:pcep";
+       prefix "pn";
+
+       import network-topology { prefix nt; revision-date 2013-10-21; }
+       import pcep-types { prefix pcep; revision-date 2013-10-05; }
+
+       organization "Cisco Systems, Inc.";
+       contact "Robert Varga <rovarga@cisco.com>";
+
+       description
+               "This module contains the PCEP extensions to base topology model. It
+        exposes the LSPs for which a particular node is the head end.
+
+               Copyright (c)2013 Cisco Systems, Inc. All rights reserved.";
+
+       revision "2013-10-24" {
+               description
+                       "Initial revision.";
+               reference "";
+       }
+
+       grouping pcep-client-attributes {
+        description "Data present in a node which is a PCEP client (PCC).";
+
+        container pcc {
+            config false;
+
+            list lsps {
+                leaf name {
+                    type pcep:symbolic-path-name;
+                }
+                key name;
+
+                // FIXME: hide protocol-specific?
+                uses pcep:lsp-object;
+            }
+        }
+       }
+
+       augment "/nt:network-topology/nt:topology/nt:node" {
+               uses pcep-client-attributes;
+       }
+}
+
index c799783492ebf3d90b612016fe394eaa4b2b208c..625cbe2a3948e4a73d52de0e07488ada149e472a 100644 (file)
@@ -18,7 +18,9 @@
        
        <modules>
         <module>api</module>
+        <module>pcep-api</module>
         <module>provider-bgp</module>
+        <module>provider-pcep</module>
                <module>tunnel-api</module>
         <module>tunnel-pcep</module>
         <module>segment-routing</module>
diff --git a/topology/provider-pcep/.project b/topology/provider-pcep/.project
new file mode 100644 (file)
index 0000000..3670b5e
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>topology-provider-pcep</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.m2e.core.maven2Builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.m2e.core.maven2Nature</nature>
+       </natures>
+</projectDescription>
diff --git a/topology/provider-pcep/pom.xml b/topology/provider-pcep/pom.xml
new file mode 100644 (file)
index 0000000..4c414c6
--- /dev/null
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<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.bgpcep</groupId>
+               <artifactId>topology-parent</artifactId>
+               <version>0.3.0-SNAPSHOT</version>
+       </parent>
+
+       <modelVersion>4.0.0</modelVersion>
+       <artifactId>topology-provider-pcep</artifactId>
+       <description>PCEP Topology Provider</description>
+       <packaging>bundle</packaging>
+       <name>${project.artifactId}</name>
+       <prerequisites>
+               <maven>3.0.4</maven>
+       </prerequisites>
+
+       <dependencies>
+               <dependency>
+                       <groupId>${project.groupId}</groupId>
+                       <artifactId>pcep-api</artifactId>
+            <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>${project.groupId}</groupId>
+                       <artifactId>topology-api</artifactId>
+            <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>${project.groupId}</groupId>
+                       <artifactId>topology-pcep-api</artifactId>
+            <version>${project.version}</version>
+               </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>slf4j-api</artifactId>
+                       <version>${slf4j.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>${project.groupId}</groupId>
+                       <artifactId>mockito-configuration</artifactId>
+            <version>${project.version}</version>
+                       <scope>test</scope>
+        </dependency>
+
+        <!-- FIXME: integrate with config to get rid of this -->
+               <dependency>
+                       <groupId>${project.groupId}</groupId>
+                       <artifactId>pcep-impl</artifactId>
+            <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>${project.groupId}</groupId>
+                       <artifactId>pcep-spi</artifactId>
+            <version>${project.version}</version>
+               </dependency>
+       </dependencies>
+
+       <build>
+        <plugins>
+           <plugin>
+               <groupId>org.apache.felix</groupId>
+               <artifactId>maven-bundle-plugin</artifactId>
+               <version>${maven.bundle.version}</version>
+               <extensions>true</extensions>
+               <configuration>
+                   <instructions>
+                       <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                       <Private-Package>
+                           org.opendaylight.bgpcep.topology.provider.pcep
+                       </Private-Package>
+                       <Bundle-Activator>org.opendaylight.bgpcep.topology.provider.pcep.BundleActivator</Bundle-Activator>
+                   </instructions>
+               </configuration>
+           </plugin>
+               </plugins>
+       </build>
+
+       <distributionManagement>
+               <site>
+                       <id>${project.artifactId}</id>
+                       <name>TOPOLOGY-PROVIDER-PCEP Module site</name>
+                       <url>${basedir}/target/site/${project.artifactId}</url>
+               </site>
+       </distributionManagement>
+
+</project>
diff --git a/topology/provider-pcep/src/main/java/org/opendaylight/bgpcep/topology/provider/pcep/BundleActivator.java b/topology/provider-pcep/src/main/java/org/opendaylight/bgpcep/topology/provider/pcep/BundleActivator.java
new file mode 100644 (file)
index 0000000..7357484
--- /dev/null
@@ -0,0 +1,49 @@
+package org.opendaylight.bgpcep.topology.provider.pcep;
+
+import io.netty.channel.ChannelFuture;
+import io.netty.util.HashedWheelTimer;
+
+import java.net.InetSocketAddress;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.protocol.pcep.PCEPDispatcher;
+import org.opendaylight.protocol.pcep.PCEPSessionProposalFactory;
+import org.opendaylight.protocol.pcep.impl.DefaultPCEPSessionNegotiatorFactory;
+import org.opendaylight.protocol.pcep.impl.PCEPDispatcherImpl;
+import org.opendaylight.protocol.pcep.impl.PCEPSessionProposalFactoryImpl;
+import org.opendaylight.protocol.pcep.spi.pojo.PCEPExtensionProviderContextImpl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.OpenObject;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public final class BundleActivator extends AbstractBindingAwareProvider {
+       private static final Logger LOG = LoggerFactory.getLogger(BundleActivator.class);
+
+       @Override
+       public void onSessionInitiated(final ProviderContext session) {
+               final DataProviderService dps = Preconditions.checkNotNull(session.getSALService(DataProviderService.class));
+
+               // FIXME: integration with config subsystem should allow this to be injected as a service
+               final InetSocketAddress address = new InetSocketAddress("0.0.0.0", 4189);
+               final PCEPSessionProposalFactory spf = new PCEPSessionProposalFactoryImpl(30, 10, true, true, true, true, 0);
+               final OpenObject prefs = spf.getSessionProposal(address, 0);
+               final PCEPDispatcher dispatcher = new PCEPDispatcherImpl(PCEPExtensionProviderContextImpl.getSingletonInstance().getMessageHandlerRegistry(),
+                               new DefaultPCEPSessionNegotiatorFactory(new HashedWheelTimer(), prefs, 5));
+               final InstanceIdentifier<Topology> topology = InstanceIdentifier.builder().node(Topology.class).toInstance();
+
+               final TopologyExporter exp = new TopologyExporter(dispatcher, dps, topology);
+               final ChannelFuture s = exp.startServer(address);
+               try {
+                       s.get();
+               } catch (InterruptedException | ExecutionException e) {
+                       LOG.error("Failed to instantiate server", e);
+               }
+       }
+}
diff --git a/topology/provider-pcep/src/main/java/org/opendaylight/bgpcep/topology/provider/pcep/ServerSessionManager.java b/topology/provider-pcep/src/main/java/org/opendaylight/bgpcep/topology/provider/pcep/ServerSessionManager.java
new file mode 100644 (file)
index 0000000..66b567a
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, 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.topology.provider.pcep;
+
+import java.net.InetAddress;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.protocol.framework.SessionListenerFactory;
+import org.opendaylight.protocol.pcep.PCEPSession;
+import org.opendaylight.protocol.pcep.PCEPSessionListener;
+import org.opendaylight.protocol.pcep.PCEPTerminationReason;
+import org.opendaylight.protocol.pcep.TerminationReason;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.pcep.rev131024.PccSyncState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.pcep.rev131024.nodes.node.PathComputationClientBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.pcep.rev131024.nodes.node.path.computation.client.StatefulTlvBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Pcerr;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.PcerrBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Message;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.PcrptMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.PlspId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lsp.object.tlvs.SymbolicPathName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.Tlvs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.tlvs.Stateful;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcerr.message.PcerrMessageBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrpt.message.pcrpt.message.Reports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrpt.message.pcrpt.message.reports.Lsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.PccBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.pcc.Lsps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.pcc.LspsKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+/**
+ *
+ */
+final class ServerSessionManager implements SessionListenerFactory<PCEPSessionListener> {
+       private static String createNodeId(final InetAddress addr) {
+               return "pcc://" + addr.getHostAddress();
+       }
+
+       private final class SessionListener implements PCEPSessionListener {
+               private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node inventoryNode(final DataModificationTransaction trans, final InetAddress address) {
+                       final String pccId = createNodeId(address);
+
+                       // FIXME: after 0.6 yangtools, this cast should not be needed
+                       final Nodes nodes = (Nodes)trans.readOperationalData(inventory);
+
+                       for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node n : nodes.getNode()) {
+                               LOG.debug("Matching inventory node {} to peer {}", n, address);
+                               if (n.getId().getValue().equals(pccId)) {
+                                       return n;
+                               }
+
+                               // FIXME: locate the node by its management IP address
+                       }
+
+                       /*
+                        * We failed to find a matching node. Let's create a dynamic one
+                        * to have a backer. Note that this node will be created in the
+                        * Runtime data space.
+                        */
+                       LOG.debug("Failed to find inventory node for peer {}, creating a new one at {}", address, pccId);
+
+                       final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId id =
+                                       new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId(pccId);
+                       final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nk =
+                                       new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey(id);
+                       final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nii =
+                                       InstanceIdentifier.builder(inventory).node(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, nk).toInstance();
+                       final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node ret =
+                                       new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder().setId(id).setKey(nk).build();
+
+                       trans.putRuntimeData(nii, ret);
+                       ownsInventory = true;
+                       inventoryNodeId = nii;
+                       return ret;
+               }
+
+               final org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node topologyNode(
+                               final DataModificationTransaction trans,
+                               final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node invNode) {
+                       // FIXME: after 0.6 yangtools, this cast should not be needed
+                       final Topology topo = (Topology)trans.readOperationalData(topology);
+
+                       for (final org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node n : topo.getNode()) {
+                               LOG.debug("Matching topology node {} to inventory node {}", n, invNode);
+                               if (n.getNodeId().getValue().equals(invNode.getId().getValue())) {
+                                       return n;
+                               }
+                       }
+
+                       /*
+                        * We failed to find a matching node. Let's create a dynamic one
+                        * and note that we are the owner (so we clean it up afterwards).
+                        */
+                       final org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId id =
+                                       new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId(invNode.getId().getValue());
+                       final org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey nk =
+                                       new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey(id);
+                       final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node> nti =
+                                       InstanceIdentifier.builder(topology).node(
+                                                       org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node.class, nk).toInstance();
+
+                       final org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node ret =
+                                       new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder().
+                                       setKey(nk).setNodeId(id).build();
+
+                       trans.putRuntimeData(nti, ret);
+                       ownsTopology = true;
+                       topologyNodeId = nti;
+                       return ret;
+               }
+
+               @Override
+               public void onSessionUp(final PCEPSession session) {
+                       /*
+                        * The session went up. Look up the router in Inventory model,
+                        * create it if it is not there (marking that fact for later
+                        * deletion), and mark it as synchronizing. Also create it in
+                        * the topology model, with empty LSP list.
+                        */
+                       final InetAddress peerAddress = session.getRemoteAddress();
+                       final DataModificationTransaction trans = dataProvider.beginTransaction();
+
+                       final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node invNode = inventoryNode(trans, peerAddress);
+                       LOG.debug("Peer {} resolved to inventory node {}", peerAddress, invNode);
+
+                       final org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node topoNode = topologyNode(trans, invNode);
+                       LOG.debug("Peer {} resolved to topology node {}", peerAddress, topoNode);
+
+                       // Our augmentation in the topology node
+                       final PccBuilder pb = new PccBuilder();
+
+                       final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.Node1 topoAugment =
+                                       new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.Node1Builder().setPcc(pb.build()).build();
+                       topologyAugmentId = InstanceIdentifier.builder(topologyNodeId).node(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.Node1.class).toInstance();
+                       trans.putRuntimeData(topologyAugmentId, topoAugment);
+
+                       // Our augmentation in the inventory node
+                       pccBuilder = new PathComputationClientBuilder();
+
+                       final Tlvs tlvs = session.getRemoteTlvs();
+                       final Stateful stateful = tlvs.getStateful();
+                       if (stateful != null) {
+                               // FIXME: rework once groupings can be used in builders
+                               pccBuilder.setStatefulTlv(new StatefulTlvBuilder().setFlags(tlvs.getStateful().getFlags()).build());
+                               pccBuilder.setStateSync(PccSyncState.InitialResync);
+                       }
+
+                       pccBuilder.setTopologyNode(topoNode.getNodeId());
+
+                       inventoryAugmentBuilder = new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.pcep.rev131024.Node1Builder()
+                       .setPathComputationClient(pccBuilder.build());
+                       inventoryAugmentId = InstanceIdentifier.builder(inventoryNodeId).node(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.pcep.rev131024.Node1.class).toInstance();
+                       trans.putRuntimeData(inventoryAugmentId, inventoryAugmentBuilder.build());
+
+                       // All set, commit the modifications
+                       final Future<RpcResult<TransactionStatus>> s = trans.commit();
+
+                       /*
+                        * FIXME: once this Future is listenable, attach to it so we can
+                        *        do cleanup if the commit fails. For now we force a commit.
+                        */
+                       try {
+                               s.get();
+                       } catch (InterruptedException | ExecutionException e) {
+                               LOG.error("Failed to update internal state for session {}, terminating it", session, e);
+                               session.close(TerminationReason.Unknown);
+                       }
+
+                       LOG.info("Session with {} attached to inventory node {} and topology node {}", session.getRemoteAddress(), invNode.getId(), topoNode.getNodeId());
+               }
+
+               private void tearDown(final PCEPSession session) {
+                       final DataModificationTransaction trans = dataProvider.beginTransaction();
+
+                       /*
+                        * The session went down. Undo all the Inventory and Topology
+                        * changes we have done.
+                        */
+                       trans.removeRuntimeData(inventoryAugmentId);
+                       if (ownsInventory) {
+                               trans.removeRuntimeData(inventoryNodeId);
+                       }
+                       trans.removeRuntimeData(topologyAugmentId);
+                       if (ownsTopology) {
+                               trans.removeRuntimeData(topologyNodeId);
+                       }
+
+                       /*
+                        * FIXME: once this Future is listenable, attach to it so we can
+                        *        do cleanup if the commit fails. For now we force a commit.
+                        */
+                       final Future<RpcResult<TransactionStatus>> s = trans.commit();
+                       try {
+                               s.get();
+                       } catch (InterruptedException | ExecutionException e) {
+                               LOG.error("Failed to cleanup internal state for session {}", session, e);
+                       }
+               }
+
+               @Override
+               public void onSessionDown(final PCEPSession session, final Exception e) {
+                       LOG.warn("Session {} went down unexpectedly", e);
+                       tearDown(session);
+               }
+
+               @Override
+               public void onSessionTerminated(final PCEPSession session, final PCEPTerminationReason reason) {
+                       LOG.info("Session {} terminated by peer with reason {}", session, reason);
+                       tearDown(session);
+               }
+
+               private InstanceIdentifier<Lsps> lspIdentifier(final SymbolicPathName name) {
+                       return InstanceIdentifier.builder(topologyAugmentId).
+                                       node(Lsps.class, new LspsKey(name.getPathName())).toInstance();
+               }
+
+               @Override
+               public void onMessage(final PCEPSession session, final Message message) {
+                       if (!(message instanceof PcrptMessage)) {
+                               LOG.info("Unhandled message {} on session {}", message, session);
+                               session.sendMessage(unhandledMessageError);
+                       }
+
+                       final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrpt.message.PcrptMessage rpt =
+                                       ((PcrptMessage)message).getPcrptMessage();
+
+                       final DataModificationTransaction trans = dataProvider.beginTransaction();
+
+                       for (final Reports r : rpt.getReports()) {
+                               final Lsp lsp = r.getLsp();
+
+                               if (lsp.isSync() && !synced) {
+                                       // Update synchronization flag
+                                       synced = true;
+                                       inventoryAugmentBuilder.setPathComputationClient(pccBuilder.setStateSync(PccSyncState.Synchronized).build());
+                                       trans.putRuntimeData(inventoryAugmentId, inventoryAugmentBuilder.build());
+                                       LOG.debug("Session {} achieved synchronized state", session);
+                               }
+
+                               final PlspId id = lsp.getPlspId();
+                               if (lsp.isRemove()) {
+                                       final SymbolicPathName name = lsps.remove(id);
+                                       if (name != null) {
+                                               trans.removeRuntimeData(lspIdentifier(name));
+                                       }
+
+                                       LOG.debug("LSP {} removed", lsp);
+                               } else {
+                                       if (!lsps.containsKey(id)) {
+                                               LOG.debug("PLSPID {} not known yet, looking for a symbolic name", id);
+
+                                               final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lsp.object.Tlvs tlvs =
+                                                               r.getLsp().getTlvs();
+                                               final SymbolicPathName name = tlvs.getSymbolicPathName();
+                                               if (name == null) {
+                                                       LOG.error("PLSPID {} seen for the first time, not reporting the LSP");
+                                                       // TODO: what should we do here?
+                                                       continue;
+                                               }
+                                       }
+
+                                       final SymbolicPathName name = lsps.get(id);
+                                       trans.putRuntimeData(lspIdentifier(name), lsp);
+
+                                       LOG.debug("LSP {} updated");
+                               }
+                       }
+
+                       /*
+                        * FIXME: once this Future is listenable, attach to it so we can
+                        *        do cleanup if the commit fails. For now we force a commit.
+                        */
+                       final Future<RpcResult<TransactionStatus>> s = trans.commit();
+                       try {
+                               s.get();
+                       } catch (InterruptedException | ExecutionException e) {
+                               LOG.error("Failed to update internal state for session {}, closing it", session, e);
+                               session.close(TerminationReason.Unknown);
+                       }
+               }
+       }
+
+       private static final Logger LOG = LoggerFactory.getLogger(ServerSessionManager.class);
+       private static final Pcerr unhandledMessageError = new PcerrBuilder().setPcerrMessage(
+                       new PcerrMessageBuilder().setErrorType(null).build()).build();
+       private final Map<PlspId, SymbolicPathName> lsps = new HashMap<>();
+       private final InstanceIdentifier<Nodes> inventory;
+       private final InstanceIdentifier<Topology> topology;
+       private final DataProviderService dataProvider;
+
+       private boolean ownsInventory = false;
+       private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> inventoryNodeId;
+       private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.pcep.rev131024.Node1> inventoryAugmentId;
+       private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.pcep.rev131024.Node1Builder inventoryAugmentBuilder;
+       private PathComputationClientBuilder pccBuilder;
+       private boolean synced = false;
+
+       private boolean ownsTopology = false;
+       private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node> topologyNodeId;
+       private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.Node1> topologyAugmentId;
+
+       public ServerSessionManager(final DataProviderService dataProvider,
+                       final InstanceIdentifier<Nodes> inventory, final InstanceIdentifier<Topology> topology) {
+               this.dataProvider = Preconditions.checkNotNull(dataProvider);
+               this.inventory = Preconditions.checkNotNull(inventory);
+               this.topology = Preconditions.checkNotNull(topology);
+       }
+
+       @Override
+       public PCEPSessionListener getSessionListener() {
+               return new SessionListener();
+       }
+}
diff --git a/topology/provider-pcep/src/main/java/org/opendaylight/bgpcep/topology/provider/pcep/TopologyExporter.java b/topology/provider-pcep/src/main/java/org/opendaylight/bgpcep/topology/provider/pcep/TopologyExporter.java
new file mode 100644 (file)
index 0000000..d03c126
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, 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.topology.provider.pcep;
+
+import io.netty.channel.ChannelFuture;
+
+import java.net.InetSocketAddress;
+
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.protocol.pcep.PCEPDispatcher;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Preconditions;
+
+public final class TopologyExporter {
+       private static final InstanceIdentifier<Nodes> inventory = new InstanceIdentifier<Nodes>(Nodes.class);
+       private final PCEPDispatcher dispatcher;
+       private final DataProviderService dataProvider;
+       private final InstanceIdentifier<Topology> topology;
+
+       public TopologyExporter(final PCEPDispatcher dispatcher,
+                       final DataProviderService dataService,
+                       final InstanceIdentifier<Topology> topology) {
+               this.dispatcher = Preconditions.checkNotNull(dispatcher);
+               this.dataProvider = Preconditions.checkNotNull(dataService);
+               this.topology = Preconditions.checkNotNull(topology);
+       }
+
+       public ChannelFuture startServer(final InetSocketAddress address) {
+               return dispatcher.createServer(address, new ServerSessionManager(dataProvider, inventory, topology));
+       }
+}
index e9928580d56d1bba6da91aef2a1acf456b45ccfe..affb2e8e0c96d0b7a747dee850f14fc866c24a31 100644 (file)
                        <artifactId>topology-tunnel-api</artifactId>
             <version>${project.version}</version>
                </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-binding</artifactId>
             <artifactId>yang-common</artifactId>
             <version>${yangtools.version}</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.controller.model</groupId>
+            <artifactId>model-inventory</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
        </dependencies>
 
        <build>
@@ -88,6 +99,9 @@
                        <Export-Package>
                            org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.pcep.rev130820,
                        </Export-Package>
+                       <Private-Package>
+                           org.opendaylight.protocol.tunnel.pcep,
+                       </Private-Package>
                    </instructions>
                </configuration>
            </plugin>
index 8176c0d0ec043f74366b1c8d1d83ec01e7f32924..1f14bdc8e8e3f99d9a172179001af91fea4512b4 100644 (file)
@@ -1,4 +1,5 @@
 module topology-tunnel-pcep {
+       // vi: set et smarttab sw=4 tabstop=4:
        yang-version 1;
        namespace "urn:opendaylight:params:xml:ns:yang:topology:tunnel:pcep";
        prefix "pceptun";
@@ -14,8 +15,8 @@ module topology-tunnel-pcep {
        contact "Robert Varga <rovarga@cisco.com>";
 
        description
-               "This module contains the Segment Routing extensions to
-               base tunnel topology model.
+               "This module contains the PCEP extensions to base tunnel
+               topology model.
 
                Copyright (c)2013 Cisco Systems, Inc. All rights reserved.";