Add Neutron host-id to RLOC mapping 92/50392/17
authorShakib Ahmed <sheikahm@cisco.com>
Tue, 10 Jan 2017 22:17:54 +0000 (14:17 -0800)
committerLorand Jakab <lojakab@cisco.com>
Fri, 17 Mar 2017 08:21:01 +0000 (10:21 +0200)
Neutron port create call provides us informations like port uuid, host-
id, sometimes fixed-ips but we don't know the interface VPP is going to
use for sending traffic from one host to another. That interface is
going to be the locator for the mapping record we will be putting in
the map-cache. For that, we need to know the locator interface of a
host. Just to clarify, for OpenStack environment is going to be the
tenant network interface.

This patch adds the functionality of listening to VbridgeTopology for
topology updates in Virtual Bridge Domain and pre-populate host to
locator information base.

Change-Id: Ic4c0844ccfcb972e46122df875b628c789f8c837
Signed-off-by: Shakib Ahmed <sheikahm@cisco.com>
17 files changed:
features/features-lispflowmapping/pom.xml
features/features-lispflowmapping/src/main/features/features.xml
features/odl-lispflowmapping-neutron/pom.xml
mappingservice/neutron/pom.xml
mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/GroupBasedPolicyNeutronIntentHandlerBean.java [new file with mode: 0644]
mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/IntentHandlerAsyncExecutorProvider.java [new file with mode: 0644]
mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/exception/RlocNotFoundOnVppNode.java [new file with mode: 0644]
mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/listener/VbridgeTopologyListener.java [new file with mode: 0644]
mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/listener/VppEndpointListener.java [new file with mode: 0644]
mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/listener/service/VbridgeTopologyListenerService.java [new file with mode: 0644]
mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/InfoUtil.java [new file with mode: 0644]
mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/LispNeutronUtil.java [new file with mode: 0644]
mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/VppNetconfConnectionProbe.java [new file with mode: 0644]
mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/VppNetconfTrasaction.java [new file with mode: 0644]
mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/VppNodeReader.java [new file with mode: 0644]
mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/mappingmanager/HostIdToRlocMapper.java [new file with mode: 0644]
mappingservice/neutron/src/main/resources/org/opendaylight/blueprint/neutron.xml

index 719f7303ca5702e8767bb476194bd0b0f0636425..02d06c4229cc2f6e2f9292a1eb3e8f38561f9e26 100644 (file)
@@ -28,8 +28,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <dluxapps.version>0.5.0-SNAPSHOT</dluxapps.version>
     <mdsal.version>1.5.0-SNAPSHOT</mdsal.version>
     <mdsal.model.version>0.10.0-SNAPSHOT</mdsal.model.version>
+    <netconf.version>1.2.0-SNAPSHOT</netconf.version>
     <neutron.version>0.8.0-SNAPSHOT</neutron.version>
     <restconf.version>1.5.0-SNAPSHOT</restconf.version>
+    <vbd.version>1.1.0-SNAPSHOT</vbd.version>
   </properties>
 
   <dependencyManagement>
@@ -42,6 +44,13 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         <type>pom</type>
         <scope>import</scope>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.honeycomb.vbd</groupId>
+        <artifactId>vbd-artifacts</artifactId>
+        <version>${vbd.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 
@@ -69,6 +78,14 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>features-netconf-connector</artifactId>
+      <version>${netconf.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.dlux</groupId>
       <artifactId>features-dlux</artifactId>
@@ -142,6 +159,12 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <classifier>features</classifier>
       <type>xml</type>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.honeycomb.vbd</groupId>
+      <artifactId>vbd-features</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
   </dependencies>
 
   <!--
index 24660467d996a8820ae55dd79a29ef645a765c84..78c15bdf233264c4f3a0f18d7bb6f2facc309b3a 100644 (file)
@@ -19,6 +19,9 @@
     <repository>mvn:org.opendaylight.controller/features-mdsal/{{VERSION}}/xml/features</repository>
     <!-- Needed for odl-restconf -->
     <repository>mvn:org.opendaylight.netconf/features-restconf/{{VERSION}}/xml/features</repository>
+    <!-- Needed by neutron intent handler -->
+    <repository>mvn:org.opendaylight.honeycomb.vbd/vbd-features/{{VERSION}}/xml/features</repository>
+    <repository>mvn:org.opendaylight.netconf/features-netconf-connector/{{VERSION}}/xml/features</repository>
 
     <feature name="odl-lispflowmapping-msmr" description="OpenDaylight :: LISP Flow Mapping :: Map-Server/Map-Resolver" version='${project.version}'>
         <feature version="${project.version}">odl-lispflowmapping-mappingservice</feature>
@@ -61,6 +64,8 @@
     <feature name="odl-lispflowmapping-neutron" description="OpenDaylight :: LISP Flow Mapping :: Neutron Integration" version='${project.version}'>
         <feature version="${neutron.version}">odl-neutron-service</feature>
         <feature version="${project.version}">odl-lispflowmapping-mappingservice</feature>
+        <feature version="${vbd.version}">odl-vbd</feature>
+        <feature version='${netconf.version}'>odl-netconf-clustered-topology</feature>
         <bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.neutron/{{VERSION}}</bundle>
     </feature>
 
index 9dd0884a397b69039fa2ad819de39989e1328b69..85940d19bf763f05b70d14bcff644cf0a8f5c494 100644 (file)
@@ -32,6 +32,27 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <type>xml</type>
       <classifier>features</classifier>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.honeycomb.vbd</groupId>
+      <artifactId>odl-vbd</artifactId>
+      <version>1.1.0-SNAPSHOT</version>
+      <type>xml</type>
+      <classifier>features</classifier>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>odl-netconf-tcp</artifactId>
+      <version>1.2.0-SNAPSHOT</version>
+      <type>xml</type>
+      <classifier>features</classifier>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>odl-netconf-clustered-topology</artifactId>
+      <version>1.2.0-SNAPSHOT</version>
+      <type>xml</type>
+      <classifier>features</classifier>
+    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>odl-lispflowmapping-mappingservice</artifactId>
index 7d65768dc04fd7ad0f7846667729ac93e5a6f3d7..87f3c353eba5da981468b8ba1f1d6118ebe7b46d 100644 (file)
        build failure. Please do not modify this unless you have a good reason. -->
   <name>ODL :: lispflowmapping :: ${project.artifactId}</name>
 
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.opendaylight.netconf</groupId>
+        <artifactId>netconf-artifacts</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>mdsal-artifacts</artifactId>
+        <version>1.5.0-SNAPSHOT</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
   <dependencies>
     <dependency>
       <groupId>org.opendaylight.lispflowmapping</groupId>
       <groupId>org.opendaylight.lispflowmapping</groupId>
       <artifactId>common.unittest.tools</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>yang-ext</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.honeycomb.vbd</groupId>
+      <artifactId>vbd-api</artifactId>
+      <version>1.1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>sal-netconf-connector</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal</groupId>
+      <artifactId>mdsal-singleton-common-api</artifactId>
+      <version>2.2.0-SNAPSHOT</version>
+    </dependency>
   </dependencies>
 
   <!--
diff --git a/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/GroupBasedPolicyNeutronIntentHandlerBean.java b/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/GroupBasedPolicyNeutronIntentHandlerBean.java
new file mode 100644 (file)
index 0000000..8c7ef96
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  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.lispflowmapping.neutron.intenthandler;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.MountPointService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.lispflowmapping.neutron.intenthandler.listener.service.VbridgeTopologyListenerService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by Shakib Ahmed on 1/19/17.
+ */
+
+/*
+ * This is the bean instantiated when lisp neutron service is installed. This bean
+ * registers and maintain listeners for getting updates of Neutron Topology
+ * maintained by groupbasedpolicy and honeycomb vbd.
+ */
+public class GroupBasedPolicyNeutronIntentHandlerBean implements AutoCloseable, BindingAwareProvider {
+    private static final Logger LOG = LoggerFactory.getLogger(GroupBasedPolicyNeutronIntentHandlerBean.class);
+
+    private DataBroker dataBroker;
+    private MountPointService mountService;
+
+    private VbridgeTopologyListenerService vbridgeTopologyListenerService;
+
+    private IntentHandlerAsyncExecutorProvider intentHandlerAsyncExecutorProvider =
+            IntentHandlerAsyncExecutorProvider.getInstace();
+
+    public GroupBasedPolicyNeutronIntentHandlerBean(final BindingAwareBroker bindingAwareBroker) {
+        bindingAwareBroker.registerProvider(this);
+    }
+
+
+    @Override
+    public void close() throws Exception {
+        LOG.info("Clustering provider closed for {}", this.getClass().getSimpleName());
+        intentHandlerAsyncExecutorProvider.close();
+    }
+
+    @Override
+    public void onSessionInitiated(BindingAwareBroker.ProviderContext session) {
+        LOG.info("LFM neutron handler service registered", this.getClass().getSimpleName());
+        dataBroker = session.getSALService(DataBroker.class);
+        mountService = session.getSALService(MountPointService.class);
+        vbridgeTopologyListenerService = VbridgeTopologyListenerService.initialize(dataBroker, mountService);
+    }
+}
diff --git a/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/IntentHandlerAsyncExecutorProvider.java b/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/IntentHandlerAsyncExecutorProvider.java
new file mode 100644 (file)
index 0000000..7e0a94b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  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.lispflowmapping.neutron.intenthandler;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import java.util.concurrent.Executors;
+
+/**
+ * Created by Shakib Ahmed on 1/24/17.
+ */
+public class IntentHandlerAsyncExecutorProvider {
+    private static ListeningExecutorService listeningExecutorService;
+
+    private static final int EXTRA_THREADS_TO_HANDLE_VPP_LISTENER = 1;
+
+    private static IntentHandlerAsyncExecutorProvider intentHandlerAsyncExecutorProvider;
+
+    private IntentHandlerAsyncExecutorProvider() {
+        listeningExecutorService = MoreExecutors
+                .listeningDecorator(Executors.newFixedThreadPool(EXTRA_THREADS_TO_HANDLE_VPP_LISTENER));
+    }
+
+    public static synchronized IntentHandlerAsyncExecutorProvider getInstace() {
+        if (intentHandlerAsyncExecutorProvider == null) {
+            intentHandlerAsyncExecutorProvider = new IntentHandlerAsyncExecutorProvider();
+        }
+        return intentHandlerAsyncExecutorProvider;
+    }
+
+    public synchronized ListeningExecutorService getExecutor() {
+        return listeningExecutorService;
+    }
+
+    public void close() {
+        listeningExecutorService.shutdown();
+    }
+}
\ No newline at end of file
diff --git a/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/exception/RlocNotFoundOnVppNode.java b/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/exception/RlocNotFoundOnVppNode.java
new file mode 100644 (file)
index 0000000..d053da1
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  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.lispflowmapping.neutron.intenthandler.exception;
+
+/**
+ * Created by Shakib Ahmed on 1/12/17.
+ */
+public class RlocNotFoundOnVppNode extends RuntimeException {
+    public RlocNotFoundOnVppNode(String hostId) {
+        super("No available interface found on node " + hostId);
+    }
+}
diff --git a/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/listener/VbridgeTopologyListener.java b/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/listener/VbridgeTopologyListener.java
new file mode 100644 (file)
index 0000000..33cdc47
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  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.lispflowmapping.neutron.intenthandler.listener;
+
+import com.google.common.base.Preconditions;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.MountPointService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.topology.types.VbridgeTopology;
+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.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by Shakib Ahmed on 1/19/17.
+ */
+public class VbridgeTopologyListener implements ClusteredDataTreeChangeListener<VbridgeTopology>, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(VbridgeTopologyListener.class);
+
+    private DataBroker dataBroker;
+    private MountPointService mountPointService;
+
+    @GuardedBy("this")
+    private final Map<TopologyKey, VppEndpointListener> domains = new ConcurrentHashMap<>();
+
+    public VbridgeTopologyListener(final DataBroker dataBroker,
+                                   final MountPointService mountPointService) {
+        this.dataBroker = Preconditions.checkNotNull(dataBroker);
+        this.mountPointService = Preconditions.checkNotNull(mountPointService);
+    }
+
+    @Override
+    public synchronized void onDataTreeChanged(@Nonnull Collection<DataTreeModification<VbridgeTopology>> changes) {
+        for (DataTreeModification<VbridgeTopology> topologyData : changes) {
+            final KeyedInstanceIdentifier<Topology, TopologyKey> topologyInstanceIdentifier =
+                    (KeyedInstanceIdentifier<Topology, TopologyKey>) topologyData
+                                                                        .getRootPath()
+                                                                        .getRootIdentifier()
+                                                                        .firstIdentifierOf(Topology.class);
+
+            Preconditions.checkArgument(!topologyInstanceIdentifier
+                    .isWildcarded(), "Wildcard topology %s is not supported",
+                    topologyInstanceIdentifier);
+
+            final DataObjectModification<VbridgeTopology> modification =  topologyData.getRootNode();
+
+            switch (modification.getModificationType()) {
+                case DELETE:
+                    handleVbridgeTopologyDelete(topologyInstanceIdentifier);
+                    break;
+                case WRITE:
+                    handleVbridgeTopologyWrite(topologyInstanceIdentifier);
+                    break;
+                default:
+                    LOG.warn("Ignoring unhandled modification type {}", modification.getModificationType());
+                    break;
+
+            }
+        }
+    }
+
+    private void handleVbridgeTopologyDelete(KeyedInstanceIdentifier<Topology, TopologyKey> topology) {
+        VppEndpointListener endpointListener = domains.get(topology.getKey());
+        endpointListener.close();
+        domains.remove(topology.getKey());
+    }
+
+    private void handleVbridgeTopologyWrite(KeyedInstanceIdentifier<Topology, TopologyKey> topology) {
+        if (domains.containsKey(topology.getKey())) {
+            domains.get(topology.getKey()).close();
+            domains.remove(topology.getKey());
+        }
+        domains.put(topology.getKey(), new VppEndpointListener(dataBroker, mountPointService, topology));
+    }
+
+    @Override
+    public void close() {
+        domains.forEach((topologyKey, vppEndpointListener) -> {
+            vppEndpointListener.close();
+        });
+    }
+}
diff --git a/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/listener/VppEndpointListener.java b/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/listener/VppEndpointListener.java
new file mode 100644 (file)
index 0000000..2692199
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  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.lispflowmapping.neutron.intenthandler.listener;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+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.ListeningExecutorService;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.MountPointService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
+import org.opendaylight.lispflowmapping.neutron.intenthandler.IntentHandlerAsyncExecutorProvider;
+import org.opendaylight.lispflowmapping.neutron.intenthandler.util.VppNetconfConnectionProbe;
+import org.opendaylight.lispflowmapping.neutron.intenthandler.util.VppNodeReader;
+import org.opendaylight.lispflowmapping.neutron.mappingmanager.HostIdToRlocMapper;
+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.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.node.attributes.SupportingNode;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by Shakib Ahmed on 1/11/17.
+ */
+public class VppEndpointListener implements AutoCloseable, ClusteredDataTreeChangeListener<Topology> {
+    private static final Logger LOG = LoggerFactory.getLogger(VppEndpointListener.class);
+
+    private final DataBroker dataBroker;
+    private final MountPointService mountService;
+    private final ListenerRegistration<?> reg;
+
+    private final VppNodeReader vppNodeReader;
+    private final HostIdToRlocMapper hostIdToRlocMapper;
+
+    private final Multimap<NodeId, KeyedInstanceIdentifier<Node, NodeKey>> nodeIdToKeyedInstanceIdentifierMap =
+            ArrayListMultimap.create();
+
+    private final ListeningExecutorService executorService;
+
+    public VppEndpointListener(final DataBroker dataBroker,
+                               final MountPointService mountPointService,
+                               KeyedInstanceIdentifier<Topology, TopologyKey> topologyII) {
+
+        this.dataBroker = dataBroker;
+        this.mountService = mountPointService;
+
+        vppNodeReader = new VppNodeReader(this.dataBroker, this.mountService);
+
+        hostIdToRlocMapper = HostIdToRlocMapper.getInstance();
+
+        reg = dataBroker.registerDataTreeChangeListener(
+                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, topologyII), this);
+
+        executorService = IntentHandlerAsyncExecutorProvider.getInstace().getExecutor();
+    }
+
+    @Override
+    public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<Topology>> changes) {
+        for (DataTreeModification<Topology> change : changes) {
+            final DataObjectModification<Topology> modification = change.getRootNode();
+            ListenableFuture<Void> modificationTaskHandler;
+            switch (modification.getModificationType()) {
+                case WRITE:
+                    modificationTaskHandler = handleChange(modification);
+                    break;
+                case SUBTREE_MODIFIED:
+                    modificationTaskHandler = handleChange(modification);
+                    break;
+                case DELETE:
+                    modificationTaskHandler = handleDeleteOnTopology();
+                    break;
+                default:
+                    LOG.warn("Ignored topology modification {}", modification);
+                    modificationTaskHandler = Futures.immediateFuture(null);
+                    break;
+            }
+            Futures.addCallback(modificationTaskHandler, new FutureCallback<Void>() {
+                @Override
+                public void onSuccess(@Nullable Void vd) {
+                    LOG.debug("VppEndpoint modification handled successfully!");
+                }
+
+                @Override
+                public void onFailure(Throwable throwable) {
+                    LOG.debug("Failed to handle VppEndpoint modifications!");
+                }
+            });
+        }
+    }
+
+    private ListenableFuture<Void> handleChange(DataObjectModification modification) {
+        Collection<DataObjectModification<? extends DataObject>> modifiedChildren = modification.getModifiedChildren();
+        List<ListenableFuture<KeyedInstanceIdentifier<Node, NodeKey>>> processingTasks = new ArrayList<>();
+        for (DataObjectModification modifiedNode : modifiedChildren) {
+            final Node newOrModifiedNode = (Node) modifiedNode.getDataAfter();
+            ListenableFuture<KeyedInstanceIdentifier<Node, NodeKey>> processingTask = processNode(newOrModifiedNode);
+            Futures.addCallback(processingTask, new FutureCallback<KeyedInstanceIdentifier<Node, NodeKey>>() {
+                @Override
+                public void onSuccess(@Nullable KeyedInstanceIdentifier<Node, NodeKey> kiiToNode) {
+                    hostIdToRlocMapper.addMapping(newOrModifiedNode.getNodeId().getValue(),
+                            LispAddressUtil.toRloc(vppNodeReader.rlocIpOfNode(kiiToNode)));
+                }
+
+                @Override
+                public void onFailure(Throwable throwable) {
+                    LOG.debug("Couldn't process {}", newOrModifiedNode.getNodeId().getValue());
+                }
+            });
+            processingTasks.add(processNode(newOrModifiedNode));
+        }
+        return Futures.immediateFuture(null);
+    }
+
+    private ListenableFuture<KeyedInstanceIdentifier<Node, NodeKey>> processNode(final Node newOrModifiedNode) {
+        ListenableFuture<Void> probeVppNodeForConnection = executorService
+                .submit(() -> {
+                    processNodeOnConnection(newOrModifiedNode);
+                    return null;
+                });
+
+        return Futures.transform(probeVppNodeForConnection,
+                new Function<Void, KeyedInstanceIdentifier<Node, NodeKey>>() {
+                    @Nullable
+                    @Override
+                    public KeyedInstanceIdentifier<Node, NodeKey> apply(@Nullable Void vd) {
+                        return nodeIdToKeyedInstanceIdentifierMap.get(newOrModifiedNode.getNodeId()).iterator().next();
+                    }
+                });
+    }
+
+    private void processNodeOnConnection(final Node newOrModifiedNode) {
+        for (SupportingNode supportingNode : newOrModifiedNode.getSupportingNode()) {
+            final NodeId nodeMount = supportingNode.getNodeRef();
+            final VppNetconfConnectionProbe probe = new VppNetconfConnectionProbe(supportingNode.getNodeRef(),
+                    dataBroker);
+
+            try {
+                // Verify netconf connection
+                boolean connectionReady = probe.startProbing();
+                if (connectionReady) {
+                    LOG.debug("Node {} is connected, creating ...", supportingNode.getNodeRef());
+                    final TopologyId topologyMount = supportingNode.getTopologyRef();
+                    final KeyedInstanceIdentifier<Node, NodeKey> iiToVpp =
+                            InstanceIdentifier.create(NetworkTopology.class)
+                            .child(Topology.class, new TopologyKey(topologyMount))
+                            .child(Node.class, new NodeKey(nodeMount));
+                    nodeIdToKeyedInstanceIdentifierMap.put(newOrModifiedNode.getNodeId(), iiToVpp);
+                } else {
+                    LOG.debug("Failed while connecting to node {}", supportingNode.getNodeRef());
+                }
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.warn("Exception while processing node {} ... ", supportingNode.getNodeRef(), e);
+            } catch (TimeoutException e) {
+                LOG.warn("Node {} was not connected within {} seconds. "
+                                + "Check node configuration and connectivity to proceed",
+                        supportingNode.getNodeRef(), VppNetconfConnectionProbe.NODE_CONNECTION_TIMER);
+            }
+        }
+    }
+
+    private ListenableFuture<Void> handleDeleteOnTopology() {
+        //TODO
+        return Futures.immediateFuture(null);
+    }
+
+    @Override
+    public void close() {
+        reg.close();
+    }
+}
diff --git a/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/listener/service/VbridgeTopologyListenerService.java b/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/listener/service/VbridgeTopologyListenerService.java
new file mode 100644 (file)
index 0000000..1c7f090
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  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.lispflowmapping.neutron.intenthandler.listener.service;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.MountPointService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.lispflowmapping.neutron.intenthandler.listener.VbridgeTopologyListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyTypesVbridgeAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.topology.types.VbridgeTopology;
+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.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by Shakib Ahmed on 1/19/17.
+ */
+public class VbridgeTopologyListenerService implements AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(VbridgeTopologyListenerService.class);
+
+    private final ListenerRegistration<VbridgeTopologyListener> listenerRegistration;
+
+    private boolean closed;
+
+    private static final DataTreeIdentifier<VbridgeTopology> TREE_LISTENER_IDENTIFIER =
+            new DataTreeIdentifier<>(
+                    LogicalDatastoreType.OPERATIONAL,
+                    InstanceIdentifier.builder(NetworkTopology.class)
+                            .child(Topology.class)
+                            .child(TopologyTypes.class)
+                            .augmentation(TopologyTypesVbridgeAugment.class)
+                            .child(VbridgeTopology.class).build());
+
+    public VbridgeTopologyListenerService(final ListenerRegistration<VbridgeTopologyListener> reg) {
+        this.listenerRegistration = reg;
+        this.closed = false;
+    }
+
+    public static VbridgeTopologyListenerService initialize(@Nonnull final DataBroker dataBroker,
+                                                            @Nonnull final MountPointService mountPointService) {
+        final ListenerRegistration<VbridgeTopologyListener> reg =
+                dataBroker.registerDataTreeChangeListener(TREE_LISTENER_IDENTIFIER,
+                        new VbridgeTopologyListener(dataBroker, mountPointService));
+
+        return new VbridgeTopologyListenerService(reg);
+    }
+
+
+    @Override
+    public void close() {
+        if (!closed) {
+
+            final VbridgeTopologyListener listener = listenerRegistration.getInstance();
+
+            listenerRegistration.close();
+            listener.close();
+
+            closed = true;
+        }
+    }
+}
diff --git a/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/InfoUtil.java b/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/InfoUtil.java
new file mode 100644 (file)
index 0000000..b48f512
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  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.lispflowmapping.neutron.intenthandler.util;
+
+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.yang.binding.KeyedInstanceIdentifier;
+
+/**
+ * Created by Shakib Ahmed on 1/23/17.
+ */
+public class InfoUtil {
+
+    private InfoUtil() {
+
+    }
+
+    public static String topology(final KeyedInstanceIdentifier<Topology, TopologyKey> topoIID) {
+        return topoIID.getKey().getTopologyId().getValue();
+    }
+
+    public static String topology(final Topology topology) {
+        return topology.getKey().getTopologyId().getValue();
+    }
+
+    public static String node(final KeyedInstanceIdentifier<Node, NodeKey> nodeIID) {
+        return nodeIID.getKey().getNodeId().getValue();
+    }
+}
diff --git a/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/LispNeutronUtil.java b/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/LispNeutronUtil.java
new file mode 100644 (file)
index 0000000..820d76a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  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.lispflowmapping.neutron.intenthandler.util;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.MountPoint;
+import org.opendaylight.controller.md.sal.binding.api.MountPointService;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by Shakib Ahmed on 1/12/17.
+ */
+public class LispNeutronUtil {
+    protected static final Logger LOG = LoggerFactory.getLogger(LispNeutronUtil.class);
+
+    private LispNeutronUtil(){}
+
+    public static DataBroker resolveDataBrokerForMountPoint(InstanceIdentifier<Node> iiToMountPoint,
+                                                            MountPointService mountService) {
+        final Optional<MountPoint> vppMountPointOpt = mountService.getMountPoint(iiToMountPoint);
+        if (vppMountPointOpt.isPresent()) {
+            final MountPoint vppMountPoint = vppMountPointOpt.get();
+            final Optional<DataBroker> dataBrokerOpt = vppMountPoint.getService(DataBroker.class);
+            if (dataBrokerOpt.isPresent()) {
+                return dataBrokerOpt.get();
+            }
+        }
+        return null;
+    }
+}
diff --git a/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/VppNetconfConnectionProbe.java b/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/VppNetconfConnectionProbe.java
new file mode 100644 (file)
index 0000000..ff0dfb4
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  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.lispflowmapping.neutron.intenthandler.util;
+
+/**
+ * Created by Shakib Ahmed on 1/23/17.
+ */
+
+import static org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus.Connected;
+import static org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus.Connecting;
+
+
+import com.google.common.util.concurrent.SettableFuture;
+
+import java.util.Collection;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Purpose: verify whether provided netconf node is already connected or wait if not.
+ *
+ * <p>
+ *     VppNetconfConnectionProbe registers istener which catches node-related changes from topology-netconf.
+ * A {@link SettableFuture} is set {@link Boolean#TRUE}, if the node is connected within {@link
+ * VppNetconfConnectionProbe#NODE_CONNECTION_TIMER} seconds. Else, proper exception is throws.
+ * </p>
+ *
+ */
+public class VppNetconfConnectionProbe implements ClusteredDataTreeChangeListener<Node> {
+    private static final Logger LOG = LoggerFactory.getLogger(VppNodeReader.class);
+
+    public static final int NODE_CONNECTION_TIMER = 60;
+    private final DataBroker dataBroker;
+    private ListenerRegistration<VppNetconfConnectionProbe> registeredListener;
+    private SettableFuture<Boolean> connectionStatusFuture = SettableFuture.create();
+
+    private static final String TOPOLOGY_IDENTIFIER = "topology-netconf";
+
+    private final DataTreeIdentifier<Node> path;
+
+    public VppNetconfConnectionProbe(final NodeId nodeId, final DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+        final InstanceIdentifier<Node> nodeIid = InstanceIdentifier.builder(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_IDENTIFIER)))
+                .child(Node.class, new NodeKey(nodeId))
+                .build();
+
+        path = new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, nodeIid);
+    }
+
+    public boolean startProbing() throws ExecutionException, InterruptedException, TimeoutException {
+        registeredListener = dataBroker.registerDataTreeChangeListener(path, this);
+        return connectionStatusFuture.get(NODE_CONNECTION_TIMER, TimeUnit.SECONDS);
+    }
+
+    @Override
+    public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<Node>> changes) {
+        changes.forEach(modification -> {
+            final DataObjectModification<Node> rootNode = modification.getRootNode();
+            final Node node = rootNode.getDataAfter();
+            final NetconfNode netconfNode = getNodeAugmentation(node);
+            if (node == null || node.getNodeId() == null) {
+                return;
+            }
+            if (netconfNode == null || netconfNode.getConnectionStatus() == null) {
+                connectionStatusFuture.set(false);
+                unregister();
+            } else {
+                final NetconfNodeConnectionStatus.ConnectionStatus status = netconfNode.getConnectionStatus();
+                if (status.equals(Connected)) {
+                    connectionStatusFuture.set(true);
+                    unregister();
+                } else if (!status.equals(Connecting)) {
+                    connectionStatusFuture.set(false);
+                    unregister();
+                }
+            }
+        });
+    }
+
+    private NetconfNode getNodeAugmentation(Node node) {
+        NetconfNode netconfNode = node.getAugmentation(NetconfNode.class);
+        if (netconfNode == null) {
+            return null;
+        }
+        return netconfNode;
+    }
+
+    private void unregister() {
+        if (registeredListener != null) {
+            registeredListener.close();
+        }
+    }
+}
diff --git a/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/VppNetconfTrasaction.java b/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/VppNetconfTrasaction.java
new file mode 100644 (file)
index 0000000..9a3debb
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  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.lispflowmapping.neutron.intenthandler.util;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by Shakib Ahmed on 1/12/17.
+ */
+public class VppNetconfTrasaction {
+    private static final Logger LOG = LoggerFactory.getLogger(VppNetconfTrasaction.class);
+
+    public static final byte RETRY_COUNT = 5;
+
+    public static synchronized <T extends DataObject> Optional<T> read(DataBroker dataBroker,
+                                                                       LogicalDatastoreType datastoreType,
+                                                                       InstanceIdentifier<T> instanceIdentifier) {
+        LOG.trace("Started Netconf transaction on VPP Node");
+        Preconditions.checkNotNull(dataBroker);
+
+        Optional<T> returnData;
+
+        int retryCounter = RETRY_COUNT;
+
+        while (retryCounter > 0) {
+            ReadOnlyTransaction readTransaction = dataBroker.newReadOnlyTransaction();
+            try {
+                returnData = readTransaction(instanceIdentifier, datastoreType, readTransaction);
+                LOG.trace("Netconf READ transaction SUCCESSFUL. Data present: {}", returnData.isPresent());
+                readTransaction.close();
+                return returnData;
+            } catch (IllegalStateException e) {
+
+                LOG.warn("Assuming that netconf read-transaction failed, retrying. Retry Count: " + retryCounter,
+                            e.getMessage());
+                readTransaction.close();
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.warn("Exception while reading data. Retry Aborted.", e.getMessage());
+                readTransaction.close();
+                break;
+            }
+            retryCounter--;
+        }
+        return Optional.absent();
+    }
+
+    private static <T extends DataObject> Optional<T> readTransaction(InstanceIdentifier<T> instanceIdentifier,
+                                                                      LogicalDatastoreType datastoreType,
+                                                                      ReadOnlyTransaction readTransaction)
+            throws IllegalStateException, InterruptedException, ExecutionException {
+
+        CheckedFuture<Optional<T>, ReadFailedException> futureData =
+                readTransaction.read(datastoreType, instanceIdentifier);
+
+        return futureData.get();
+    }
+}
diff --git a/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/VppNodeReader.java b/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/intenthandler/util/VppNodeReader.java
new file mode 100644 (file)
index 0000000..7be09c7
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  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.lispflowmapping.neutron.intenthandler.util;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.MountPointService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.lispflowmapping.neutron.intenthandler.exception.RlocNotFoundOnVppNode;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.Loopback;
+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.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Created by Shakib Ahmed on 1/12/17.
+ */
+public class VppNodeReader {
+    private static final Logger LOG = LoggerFactory.getLogger(VppNodeReader.class);
+
+    private final DataBroker dataBroker;
+    private final MountPointService mountService;
+
+    public VppNodeReader(DataBroker dataBroker, MountPointService mountService) {
+        this.dataBroker = dataBroker;
+        this.mountService = mountService;
+    }
+
+    public Ipv4Address rlocIpOfNode(KeyedInstanceIdentifier<Node, NodeKey> instanceIdentifierToVppNode) {
+        try {
+            Optional<Ipv4Address> ipv4AddressOptional =
+                    readFirstAvailableIpOfVppNode(instanceIdentifierToVppNode).get();
+            if (!ipv4AddressOptional.isPresent()) {
+                throw new RlocNotFoundOnVppNode(InfoUtil.node(instanceIdentifierToVppNode));
+            }
+
+            return ipv4AddressOptional.get();
+        } catch (final InterruptedException | ExecutionException ex) {
+            LOG.warn("Got exception while reading IP addresses from nodes {}",
+                    InfoUtil.node(instanceIdentifierToVppNode));
+            throw new RlocNotFoundOnVppNode(InfoUtil.node(instanceIdentifierToVppNode));
+        }
+    }
+
+    private ListenableFuture<Optional<Ipv4Address>>
+        readFirstAvailableIpOfVppNode(final KeyedInstanceIdentifier<Node, NodeKey> instanceIdentifierToVppNode) {
+
+        final SettableFuture<Optional<Ipv4Address>> resultFuture = SettableFuture.create();
+
+        final DataBroker vppDataBroker = LispNeutronUtil.resolveDataBrokerForMountPoint(instanceIdentifierToVppNode,
+                mountService);
+        if (vppDataBroker != null) {
+            final Optional<InterfacesState> interfacesOnVppNodeOptional = VppNetconfTrasaction.read(vppDataBroker,
+                    LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(InterfacesState.class));
+            if (interfacesOnVppNodeOptional.isPresent()) {
+
+                for (Interface intf : interfacesOnVppNodeOptional.get().getInterface()) {
+
+                    if (intf.getType().equals(Loopback.class)) {
+                        continue;
+                    }
+
+                    final Optional<Ipv4Address> ipv4AddressOptional = readIpAddressFromInterface(intf,
+                            instanceIdentifierToVppNode);
+
+                    if (ipv4AddressOptional.isPresent()) {
+                        resultFuture.set(ipv4AddressOptional);
+                        break;
+                    }
+                }
+
+            }
+
+            resultFuture.set(Optional.absent());
+        } else {
+            LOG.debug("Data broker for vpp {} is missing.", instanceIdentifierToVppNode);
+        }
+        return resultFuture;
+    }
+
+    private Optional<Ipv4Address> readIpAddressFromInterface(Interface intf,
+                                                                   KeyedInstanceIdentifier iiToVpp) {
+        Interface2 augIntf = intf.getAugmentation(Interface2.class);
+
+        if (augIntf == null) {
+            LOG.debug("Cannot get Interface2 augmentation for intf {}");
+            return Optional.absent();
+        }
+
+        Ipv4 ipv4 = augIntf.getIpv4();
+
+        if (ipv4 == null) {
+            LOG.debug("Ipv4 address for interface {} on node {} is null!", augIntf, InfoUtil.node(iiToVpp));
+            return Optional.absent();
+        }
+
+        final List<Address> addresses = ipv4.getAddress();
+        if (addresses == null || addresses.isEmpty()) {
+            LOG.debug("Ipv4 addresses list is empty for interface {} on node {}", augIntf, InfoUtil.node(iiToVpp));
+            return Optional.absent();
+        }
+
+        final Ipv4AddressNoZone ip = addresses.iterator().next().getIp();
+        if (ip == null) {
+            LOG.debug("Ipv4AddressNoZone is null for node {}", InfoUtil.node(iiToVpp));
+            return Optional.absent();
+        }
+
+        LOG.debug("Got ip address {} from interface {} on node {}", ip.getValue(), intf.getName(),
+                InfoUtil.node(iiToVpp));
+        return Optional.of(ip);
+    }
+
+}
diff --git a/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/mappingmanager/HostIdToRlocMapper.java b/mappingservice/neutron/src/main/java/org/opendaylight/lispflowmapping/neutron/mappingmanager/HostIdToRlocMapper.java
new file mode 100644 (file)
index 0000000..f99567e
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc.  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.lispflowmapping.neutron.mappingmanager;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.rloc.container.Rloc;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by Shakib Ahmed on 1/12/17.
+ */
+public class HostIdToRlocMapper {
+    private static final Logger LOG = LoggerFactory.getLogger(HostIdToRlocMapper.class);
+
+    private ConcurrentHashMap<String, List<Rloc>> mapper;
+    private static HostIdToRlocMapper instance;
+
+    private HostIdToRlocMapper() {
+        mapper = new ConcurrentHashMap();
+    }
+
+    public static synchronized HostIdToRlocMapper getInstance() {
+        if (instance == null) {
+            instance = new HostIdToRlocMapper();
+        }
+        return instance;
+    }
+
+    public synchronized void addMapping(String hostId, Rloc hostRloc) {
+        List<Rloc> hostIdSpeceficRlocs = mapper.get(hostId);
+
+        if (hostIdSpeceficRlocs == null) {
+            hostIdSpeceficRlocs = new ArrayList<>();
+        }
+
+        hostIdSpeceficRlocs.add(hostRloc);
+        mapper.put(hostId, hostIdSpeceficRlocs);
+        LOG.debug("Adding " + hostRloc.getAddress() + " as Rloc of " + hostId);
+    }
+
+    public List<Rloc> getRlocs(String hostId) {
+        return mapper.get(hostId);
+    }
+
+    public synchronized void deleteMapping(String hostId) {
+        //for now, delete all rlocs
+        mapper.remove(hostId);
+    }
+}
\ No newline at end of file
index 3fd34b2cbc2b0ac70db0948ae1a52d4c2b550aac..99ea762a8e02e93d2b92349ccdf7989cd3290375 100644 (file)
     <argument ref="mappingService" />
     <argument ref="bindingAwareBroker"/>
   </bean>
+  <bean id="lispNeutronIntent"
+        class="org.opendaylight.lispflowmapping.neutron.intenthandler.GroupBasedPolicyNeutronIntentHandlerBean"
+        destroy-method="close">
+    <argument ref="bindingAwareBroker"/>
+  </bean>
+
   <service ref="lispNeutronPlugin"
     interface="org.opendaylight.lispflowmapping.neutron.ILispNeutronService"
     odl:type="default" />