Merge "Bug 5046 : ELAN integration into NeutronVPN for ELAN instance/interfaces"
authorVivek Srivastava <vivek.v.srivastava@ericsson.com>
Mon, 25 Jan 2016 09:56:28 +0000 (09:56 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 25 Jan 2016 09:56:28 +0000 (09:56 +0000)
29 files changed:
commons/binding-parent/pom.xml
commons/config-parent/pom.xml
distribution/karaf/pom.xml
features/pom.xml
features/src/main/features/features.xml
fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/NexthopManager.java
neutronvpn/neutronvpn-api/pom.xml
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnManager.java
pom.xml
vpnintent/api/pom.xml [new file with mode: 0644]
vpnintent/api/src/main/yang/vpnintent.yang [new file with mode: 0644]
vpnintent/impl/pom.xml [new file with mode: 0644]
vpnintent/impl/src/main/config/default-config.xml [new file with mode: 0644]
vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/IntentServiceManager.java [new file with mode: 0644]
vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MappingServiceManager.java [new file with mode: 0644]
vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MplsLabelManagerService.java [new file with mode: 0644]
vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/VpnintentProvider.java [new file with mode: 0644]
vpnintent/impl/src/main/java/org/opendaylight/vpnservice/utils/IidFactory.java [new file with mode: 0644]
vpnintent/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnintent/impl/rev141210/VpnintentImplModule.java [new file with mode: 0644]
vpnintent/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnintent/impl/rev141210/VpnintentImplModuleFactory.java [new file with mode: 0644]
vpnintent/impl/src/main/yang/vpnintent-impl.yang [new file with mode: 0644]
vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/IntentServiceManagerTest.java [new file with mode: 0644]
vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/MappingServiceManagerTests.java [new file with mode: 0644]
vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/VpnintentProviderTest.java [new file with mode: 0644]
vpnintent/pom.xml [new file with mode: 0644]
vpnintent/resources/vpnintent.postman_collection [new file with mode: 0644]
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/InterfaceStateChangeListener.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/utilities/InterfaceUtils.java

index 6ed9de4bce1987ad130ed37b347809711f059684..1ba8e773697bb65e799a37ae7fd8e6eae9cf857c 100644 (file)
@@ -27,7 +27,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <ietf.interfaces.version>2014.05.08.9-SNAPSHOT</ietf.interfaces.version>
     <iana.if.type.version>2014.05.08.9-SNAPSHOT</iana.if.type.version>
     <yang.ext.version>2013.09.07.9-SNAPSHOT</yang.ext.version>
-    <yangtools.version>0.9.0-SNAPSHOT</yangtools.version>
+    <yangtools.version>1.0.0-SNAPSHOT</yangtools.version>
     <mdsal.version>2.1.0-SNAPSHOT</mdsal.version>
     <controller.mdsal.version>1.4.0-SNAPSHOT</controller.mdsal.version>
     <vpns.mdsalutil.version>0.3.0-SNAPSHOT</vpns.mdsalutil.version>
index 7f7abaee1cbefc4cae236fa5667d968c968106d9..dae5ca5efea9dabf37b17f4b94474395316028ab 100644 (file)
@@ -24,7 +24,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <properties>
     <!-- ODL -->
     <vpnservices.version>0.3.0-SNAPSHOT</vpnservices.version>
-    <yangtools.version>0.9.0-SNAPSHOT</yangtools.version>
+    <yangtools.version>1.0.0-SNAPSHOT</yangtools.version>
+    <mdsal.model.version>0.9.0-SNAPSHOT</mdsal.model.version>
     <controller.mdsal.version>1.4.0-SNAPSHOT</controller.mdsal.version>
     <vpns.mdsalutil.version>0.3.0-SNAPSHOT</vpns.mdsalutil.version>
     <model.bgp.version>2013.07.15.9-SNAPSHOT</model.bgp.version>
@@ -47,7 +48,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <dependency>
         <groupId>org.opendaylight.mdsal.model</groupId>
         <artifactId>mdsal-model-artifacts</artifactId>
-        <version>0.9.0-SNAPSHOT</version>
+        <version>${mdsal.model.version}</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>
index 3fdedb91c89add5a09e6368134ee012eaa840a1b..c6f059b9e1abee90346f626960b9fe6d4d8d6459 100644 (file)
@@ -22,7 +22,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <maven>3.1.1</maven>
   </prerequisites>
   <properties>
-    <karaf.localFeature>odl-vpnservice-core</karaf.localFeature>
+    <!-- <karaf.localFeature>odl-vpnservice-core</karaf.localFeature> -->
   </properties>
   <dependencyManagement>
     <dependencies>
index 536106a1b8726079a0b44dabf80caade5a70b8ec..2508f3ce053097137e5c51e81248524fed0a165a 100644 (file)
@@ -24,12 +24,13 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <mdsal.version>1.4.0-SNAPSHOT</mdsal.version>
     <openflowplugin.version>0.3.0-SNAPSHOT</openflowplugin.version>
     <restconf.version>1.4.0-SNAPSHOT</restconf.version>
-    <yangtools.version>0.9.0-SNAPSHOT</yangtools.version>
+    <yangtools.version>1.0.0-SNAPSHOT</yangtools.version>
     <mdsal.model.version>0.9.0-SNAPSHOT</mdsal.model.version>
     <vpnservices.version>0.3.0-SNAPSHOT</vpnservices.version>
     <ovsdb.version>1.3.0-SNAPSHOT</ovsdb.version>
     <liblldp.version>0.11.0-SNAPSHOT</liblldp.version>
     <neutron.version>0.7.0-SNAPSHOT</neutron.version>
+    <nic.version>1.2.0-SNAPSHOT</nic.version>
     <arputil.version>${vpnservices.version}</arputil.version>
     <mdsalutil.version>${vpnservices.version}</mdsalutil.version>
     <vpnmanager.version>${vpnservices.version}</vpnmanager.version>
@@ -86,6 +87,14 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.nic</groupId>
+      <artifactId>features-nic</artifactId>
+      <classifier>features</classifier>
+      <version>${nic.version}</version>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.ovsdb</groupId>
       <artifactId>features-ovsdb</artifactId>
@@ -377,5 +386,22 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <artifactId>commons-net</artifactId>
       <version>${commons.net.version}</version>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>vpnintent-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>vpnintent-impl</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>vpnintent-impl</artifactId>
+      <version>${vpnservices.version}</version>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
   </dependencies>
 </project>
index cfebda449e8e4bebd8209dd75cb5446e62e9f1d0..74e321ffd8f92540c329e250c238c9098e060c02 100644 (file)
@@ -18,6 +18,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <repository>mvn:org.opendaylight.netconf/features-restconf/${restconf.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.ovsdb/features-ovsdb/${ovsdb.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.neutron/features-neutron/${neutron.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.nic/features-nic/{{VERSION}}/xml/features</repository>
   <feature name='odl-vpnservice-api' version='${project.version}' description='OpenDaylight :: vpnservice :: api '>
     <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
     <feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
@@ -66,6 +67,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <bundle>mvn:org.opendaylight.vpnservice/elanmanager-impl/${elanmgr.version}</bundle>
 
     <!--<bundle>mvn:org.opendaylight.vpnservice.third-party/org.apache.thriftlib/1.1.0-SNAPSHOT</bundle>-->
+    <!--<bundle>mvn:org.opendaylight.vpnservice.third-party/org.apache.thriftlib/1.0.1-SNAPSHOT</bundle>-->
     <bundle>wrap:mvn:org.apache.thrift/libthrift/0.9.1$overwrite=merge&amp;Bundle-Version=0.9.1&amp;Export-Package=*;-noimport:=true;version="0.9.1"</bundle>
     <!--<bundle>wrap:mvn:javax.servlet/servlet-api/2.5</bundle>-->
     <configfile finalname="lockmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/lockmanager-impl/${lockmanager.version}/xml/config</configfile>
@@ -101,4 +103,13 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <feature name='odl-vpnservice-openstack' version='${project.version}' description='OpenDaylight :: vpnservice :: impl :: REST '>
     <feature version="${project.version}">odl-vpnservice-impl</feature>
   </feature>
+  <feature name='odl-vpnservice-intent' version='${project.version}' description='OpenDaylight :: vpnservice :: intent'>
+    <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
+    <feature version='${nic.version}'>odl-nic-core-service-mdsal</feature>
+    <feature version='${nic.version}'>odl-nic-core</feature>
+    <feature version='${nic.version}'>odl-nic-listeners</feature>
+    <bundle>mvn:org.opendaylight.vpnservice/vpnintent-api/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/vpnintent-impl/{{VERSION}}</bundle>
+    <configfile finalname="vpnintent-impl-default-config.xml">mvn:org.opendaylight.vpnservice/vpnintent-impl/{{VERSION}}/xml/config</configfile>
+  </feature>
   </features>
index 28ea399d791b04715aa31ebd80f0e998d941e36f..a3cd7c4eea9af109c9fde30e87a205b3441bbad3 100644 (file)
@@ -362,11 +362,13 @@ public class NexthopManager implements AutoCloseable {
                   localDpnId, remoteDpnId, vpnId, prefixIp, nextHopIp);
 
         LOG.trace("getRemoteNextHopPointer: Calling ITM with localDpnId {} ", localDpnId);
-        try{
-            // here use the config for tunnel type param
-            tunnelIfName = getTunnelInterfaceName(remoteDpnId, IpAddressBuilder.getDefaultInstance(nextHopIp));
-        }catch(Exception ex){
-            LOG.error("Error while retrieving nexthop pointer for DC Gateway : ", ex.getMessage());
+        if (nextHopIp != null && !nextHopIp.isEmpty()) {
+            try{
+                // here use the config for tunnel type param
+                tunnelIfName = getTunnelInterfaceName(remoteDpnId, IpAddressBuilder.getDefaultInstance(nextHopIp));
+            }catch(Exception ex){
+            LOG.error("Error while retrieving nexthop pointer for nexthop {} : ", nextHopIp, ex.getMessage());
+            }
         }
         return tunnelIfName;
     }
index 6ecdd0330fd9f6e8aa8d962c6eff37eb0bb99680..c4afd3488bcd1819fa8bb2912f8e8c31a405f847 100644 (file)
@@ -25,7 +25,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         <dependency>
             <groupId>org.opendaylight.mdsal</groupId>
             <artifactId>yang-binding</artifactId>
-            <version>${yangtools.version}</version>
+            <version>${mdsal.model.version}</version>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
index 505d128a215506837909732f8dee23a0e2b488e3..e7399566f514e9b6b0ce04880bf7854c76f548d3 100644 (file)
@@ -369,10 +369,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
             return;
         }
         String portname = NeutronvpnUtils.uuidToTapPortName(port.getUuid());
-        String name = new StringBuilder(portname).append(":0").toString();
         List<Adjacency> adjList = new ArrayList<Adjacency>();
         InstanceIdentifier<VpnInterface> vpnIfIdentifier = InstanceIdentifier.builder(VpnInterfaces.class).
-                child(VpnInterface.class, new VpnInterfaceKey(name)).build();
+                child(VpnInterface.class, new VpnInterfaceKey(portname)).build();
         // find router associated to vpn
         Uuid routerId = NeutronvpnUtils.getRouterforVpn(broker, vpnId);
         Router rtr = null;
@@ -392,7 +391,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
             // create extra route adjacency
             if (rtr != null && rtr.getRoutes() != null) {
                 List<String> routeList = rtr.getRoutes();
-                List<Adjacency> erAdjList = addAdjacencyforExtraRoute(routeList, false, name);
+                List<Adjacency> erAdjList = addAdjacencyforExtraRoute(routeList, false, portname);
                 if (erAdjList != null) {
                     adjList.addAll(erAdjList);
                 }
@@ -400,18 +399,18 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
         }
         // create vpn-interface on this neutron port
         Adjacencies adjs = new AdjacenciesBuilder().setAdjacency(adjList).build();
-        VpnInterfaceBuilder vpnb = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(name)).
-                setName(name).setVpnInstanceName(vpnId.getValue()).addAugmentation(Adjacencies.class, adjs);
+        VpnInterfaceBuilder vpnb = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(portname)).
+                setName(portname).setVpnInstanceName(vpnId.getValue()).addAugmentation(Adjacencies.class, adjs);
         VpnInterface vpnIf = vpnb.build();
 
-        NeutronvpnUtils.lockVpnInterface(lockManager, name);
+        NeutronvpnUtils.lockVpnInterface(lockManager, portname);
         try {
             logger.debug("Creating vpn interface {}", vpnIf);
             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIf);
         } catch (Exception ex) {
-            logger.error("Creation of vpninterface {} failed due to {}", name, ex);
+            logger.error("Creation of vpninterface {} failed due to {}", portname, ex);
         } finally {
-            NeutronvpnUtils.unlockVpnInterface(lockManager, name);
+            NeutronvpnUtils.unlockVpnInterface(lockManager, portname);
         }
     }
 
@@ -419,18 +418,17 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
 
         if (port != null) {
             String pname = NeutronvpnUtils.uuidToTapPortName(port.getUuid());
-            String name = new StringBuilder(pname).append(":0").toString();
             InstanceIdentifier<VpnInterface> vpnIfIdentifier = InstanceIdentifier.builder(VpnInterfaces.class).
-                    child(VpnInterface.class, new VpnInterfaceKey(name)).build();
+                    child(VpnInterface.class, new VpnInterfaceKey(pname)).build();
 
-            NeutronvpnUtils.lockVpnInterface(lockManager, name);
+            NeutronvpnUtils.lockVpnInterface(lockManager, pname);
             try {
-                logger.debug("Deleting vpn interface {}", name);
+                logger.debug("Deleting vpn interface {}", pname);
                 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier);
             } catch (Exception ex) {
-                logger.error("Deletion of vpninterface {} failed due to {}", name, ex);
+                logger.error("Deletion of vpninterface {} failed due to {}", pname, ex);
             } finally {
-                NeutronvpnUtils.unlockVpnInterface(lockManager, name);
+                NeutronvpnUtils.unlockVpnInterface(lockManager, pname);
             }
         }
     }
@@ -689,30 +687,29 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
                     String destination = parts[1];
 
                     String tapPortName = NeutronvpnUtils.getNeutronPortNamefromPortFixedIp(broker, nextHop);
-                    String ifname = new StringBuilder(tapPortName).append(":0").toString();
                     logger.trace("Adding extra route with nexthop {}, destination {}, ifName {}", nextHop,
-                            destination, ifname);
+                            destination, tapPortName);
                     Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination).setNextHopIp(nextHop).setKey
                             (new AdjacencyKey(destination)).build();
                     if (rtrUp == false) {
-                        if (ifname.equals(vpnifname)) {
+                        if (tapPortName.equals(vpnifname)) {
                             adjList.add(erAdj);
                         }
                         continue;
                     }
                     InstanceIdentifier<VpnInterface> vpnIfIdentifier = InstanceIdentifier.builder(VpnInterfaces.class).
-                            child(VpnInterface.class, new VpnInterfaceKey(ifname)).build();
+                            child(VpnInterface.class, new VpnInterfaceKey(tapPortName)).build();
                     Optional<VpnInterface> optionalVpnInterface = NeutronvpnUtils.read(broker, LogicalDatastoreType
                             .CONFIGURATION, vpnIfIdentifier);
                     if (optionalVpnInterface.isPresent()) {
                         Adjacencies erAdjs = new AdjacenciesBuilder().setAdjacency(Arrays.asList(erAdj)).build();
-                        VpnInterface vpnIf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(ifname))
+                        VpnInterface vpnIf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(tapPortName))
                                 .addAugmentation(Adjacencies.class, erAdjs).build();
                         MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIf);
                         logger.trace("extra route {} added successfully", route);
                     } else {
                         logger.error("VM adjacency for interface {} not present ; cannot add extra route adjacency",
-                                ifname);
+                                tapPortName);
                     }
                 } else {
                     logger.error("Incorrect input received for extra route. {}", parts);
@@ -735,11 +732,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
                     String destination = parts[1];
 
                     String tapPortName = NeutronvpnUtils.getNeutronPortNamefromPortFixedIp(broker, nextHop);
-                    String ifname = new StringBuilder(tapPortName).append(":0").toString();
                     logger.trace("Removing extra route with nexthop {}, destination {}, ifName {}", nextHop,
-                            destination, ifname);
+                            destination, tapPortName);
                     InstanceIdentifier<Adjacency> adjacencyIdentifier = InstanceIdentifier.builder(VpnInterfaces.class).
-                            child(VpnInterface.class, new VpnInterfaceKey(ifname)).augmentation(Adjacencies.class)
+                            child(VpnInterface.class, new VpnInterfaceKey(tapPortName)).augmentation(Adjacencies.class)
                             .child(Adjacency.class, new AdjacencyKey(destination)).build();
                     MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
                     logger.trace("extra route {} deleted successfully", route);
diff --git a/pom.xml b/pom.xml
index 591652c614cb313d9f3b8aa5a043e71584839235..e29557e99b9cce51a66757b8a4c7e0bf4d871739 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -4,8 +4,7 @@ Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others.  A
 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 INTERNAL
--->
-<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">
+--><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">
   <groupId>org.opendaylight.vpnservice</groupId>
   <artifactId>vpnservice</artifactId>
   <version>0.3.0-SNAPSHOT</version>
@@ -35,6 +34,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <module>distribution/karaf</module>
     <module>features</module>
     <module>vpnservice-artifacts</module>
+    <module>vpnintent</module>
   </modules>
 
   <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
@@ -62,4 +62,4 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <url>https://wiki.opendaylight.org/view/VPNService:Main</url>
     <tag>HEAD</tag>
   </scm>
-</project>
+</project>
\ No newline at end of file
diff --git a/vpnintent/api/pom.xml b/vpnintent/api/pom.xml
new file mode 100644 (file)
index 0000000..24f8d54
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2016 Inocybe Technologies and others.  All rights reserved.
+
+This program and the accompanying materials are made available under the
+terms of the Eclipse Public License v1.0 which accompanies this distribution,
+and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.opendaylight.vpnservice</groupId>
+    <artifactId>binding-parent</artifactId>
+    <version>0.3.0-SNAPSHOT</version>
+    <relativePath>../../commons/binding-parent</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.vpnservice</groupId>
+  <artifactId>vpnintent-api</artifactId>
+  <version>${vpnservices.version}</version>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+  <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-inet-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-yang-types</artifactId>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/vpnintent/api/src/main/yang/vpnintent.yang b/vpnintent/api/src/main/yang/vpnintent.yang
new file mode 100644 (file)
index 0000000..f0884e4
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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 INTERNAL
+ */
+module vpnintent {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:vpnintent";
+    prefix "vpnintent";
+
+    import ietf-inet-types { prefix inet; revision-date 2010-09-24;}
+
+    revision "2015-01-05" {
+        description "Initial revision of VPN intent model.
+            Create VPN via Intent, keep VPN state and manage MPLS labels";
+    }
+
+    container vpns{
+        list vpn-intents {
+            key "vpn-name";
+            uses vpn-intent;
+        }
+    }
+
+    typedef failover-type {
+        type enumeration {
+            enum fast-reroute {
+                value 1;
+            }
+            enum slow-reroute {
+                value 2;
+            }
+        }
+    }
+
+    grouping vpn-intent {
+        leaf vpn-name {
+            type string;
+            description "VPN name";
+            mandatory true;
+        }
+        leaf path-protection {
+            type boolean;
+        }
+        leaf failover-type {
+            type failover-type;
+        }
+        list endpoint {
+            key "site-name";
+            uses endpoint-fields;
+            description "List to keep track site name and endpoint.";
+          }
+    }
+
+    grouping endpoint-fields {
+        leaf site-name{
+            type string;
+            description "VPN member site name.";
+        }
+
+        leaf ip-prefix {
+            type inet:ip-prefix;
+            description "VPN member IP prefix.";
+        }
+
+        leaf switch-port-id {
+            type string;
+            description "Switch and port ID that VPN member is connected to.";
+        }
+    }
+
+    grouping labels {
+        list label {
+            key "label-id";
+            leaf "label-id"{
+                type uint32 {
+                    range "0 .. 524288";
+                }
+                description "20 bit MPLS label ID";
+                mandatory true;
+            }
+            uses endpoint-fields;
+            description "Keep track of MPLS/other label endpoint relation.";
+        }
+     }
+
+    container mpls-labels {
+        uses labels;
+    }
+
+    rpc add-vpn-endpoint{
+        description
+            "Add VPN endpoint.";
+        input {
+            leaf vpn-name {
+                type string;
+                description "VPN name";
+                mandatory true;
+            }
+            uses endpoint-fields;
+        }
+    }
+
+    rpc remove-vpn-endpoint{
+        description
+            "Remove VPN endpoint.";
+        input {
+            leaf vpn-name {
+                type string;
+                description "VPN name";
+                mandatory true;
+            }
+            leaf site-name{
+                type string;
+                description "VPN member site name.";
+            }
+        }
+    }
+
+    rpc remove-vpn{
+        description
+            "Remove VPN and its endpoints.";
+        input {
+            leaf vpn-name {
+                type string;
+                description "VPN name";
+                mandatory true;
+            }
+        }
+    }
+  }
diff --git a/vpnintent/impl/pom.xml b/vpnintent/impl/pom.xml
new file mode 100644 (file)
index 0000000..0be7d94
--- /dev/null
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2016 Inocybe Technologies 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 INTERNAL
+-->
+<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.vpnservice</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.3.0-SNAPSHOT</version>
+    <relativePath>../../commons/config-parent</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>vpnintent-impl</artifactId>
+  <version>${vpnservices.version}</version>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <nic.version>1.2.0-SNAPSHOT</nic.version>
+    <powermock.version>1.5.2</powermock.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>vpnintent-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <!-- NIC dependency -->
+    <dependency>
+      <groupId>org.opendaylight.nic</groupId>
+      <artifactId>intent-api</artifactId>
+      <version>${nic.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.nic</groupId>
+      <artifactId>utils</artifactId>
+      <version>${nic.version}</version>
+    </dependency>
+
+    <!-- Testing Dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <version>${powermock.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <version>${powermock.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.nic</groupId>
+      <artifactId>intent-mapping-interface</artifactId>
+      <version>${nic.version}</version>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/vpnintent/impl/src/main/config/default-config.xml b/vpnintent/impl/src/main/config/default-config.xml
new file mode 100644 (file)
index 0000000..0b6f6a6
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+Copyright (c) 2016 Inocybe Technologies 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
+-->
+<snapshot>
+  <required-capabilities>
+      <capability>urn:opendaylight:params:xml:ns:yang:vpnintent:impl?module=vpnintent-impl&amp;revision=2014-12-10</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+  </required-capabilities>
+  <configuration>
+
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:vpnintent:impl">prefix:vpnintent-impl</type>
+          <name>vpnintent-impl-default</name>
+          <broker>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+            <name>binding-osgi-broker</name>
+          </broker>
+          <rpc-registry>
+              <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+              <name>binding-rpc-broker</name>
+          </rpc-registry>
+        </module>
+      </modules>
+    </data>
+  </configuration>
+</snapshot>
diff --git a/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/IntentServiceManager.java b/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/IntentServiceManager.java
new file mode 100644 (file)
index 0000000..dda5447
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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.vpnservice.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.nic.utils.MdsalUtils;
+import org.opendaylight.vpnservice.utils.IidFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.constraints.rev150122.FailoverType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.Intents;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.IntentsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.Actions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.ActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.Constraints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.ConstraintsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.Subjects;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.SubjectsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action.allow.AllowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action.block.BlockBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints.constraints.failover.constraint.FailoverConstraintBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints.constraints.protection.constraint.ProtectionConstraintBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.end.point.group.EndPointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.end.point.group.EndPointGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.Intent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.IntentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.IntentKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.types.rev150122.Uuid;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+
+public class IntentServiceManager {
+
+    /**
+     * This class is used to build Intents object and
+     * write it to Network Intent Composition md-sal tree
+     * in order to create/delete intents between two endpoint groups.
+     */
+
+    private static final Logger LOG = LoggerFactory.getLogger(IntentServiceManager.class);
+    private static final short FIRST_SUBJECT = 1;
+    private static final short SECOND_SUBJECT = 2;
+    public static final String ACTION_ALLOW = "ALLOW";
+    public static final String ACTION_BLOCK = "BLOCK";
+    public static final String FAST_REROUTE = "fast-reroute";
+    public static final String SLOW_REROUTE = "slow-reroute";
+    private final DataBroker dataBroker;
+    private static final InstanceIdentifier<Intents> INTENTS_IID = IidFactory.getIntentsIid();
+    private MdsalUtils mdsal;
+
+    public IntentServiceManager(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+        this.mdsal = new MdsalUtils(dataBroker);
+    }
+
+    /**
+     * Create Intents object and write to to config tree to trigger intents
+     * @param src :Source Site Name
+     * @param dst :Destination Site Name
+     * @param intentAction :Intent verb: ALLOW or BLOCK
+     * @param failOverType
+     */
+    public void addIntent(String src, String dst, String intentAction, String failOverType) {
+        Preconditions.checkNotNull(src);
+        Preconditions.checkNotNull(dst);
+        Preconditions.checkNotNull(intentAction);
+
+        List<Intent> intentList = null;
+        List<Subjects> subjects = createSubjects(dst, src);
+        List<Actions> intentActions = createActions(intentAction);
+        List<Constraints> intentConstraints = createConstraints(failOverType);
+
+        Intent intent  = new IntentBuilder().setId(new Uuid(UUID.randomUUID().toString()))
+                .setSubjects(subjects).setActions(intentActions)
+                .setConstraints(intentConstraints)
+                .build();
+
+        Intents currentIntents = mdsal.read(LogicalDatastoreType.CONFIGURATION, INTENTS_IID);
+        if (currentIntents == null) {
+            intentList = new ArrayList<>();
+        } else {
+            intentList = currentIntents.getIntent();
+        }
+        intentList.add(intent);
+        Intents intents = new IntentsBuilder().setIntent(intentList).build();
+        mdsal.put(LogicalDatastoreType.CONFIGURATION, INTENTS_IID, intents);
+        LOG.info("AddIntent: config populated: {}", intents);
+    }
+
+    /**
+     * Delete an Intent
+     * @param id :Uuid of the Intent to be deleted
+     */
+    public void removeIntent(Uuid id) {
+        Preconditions.checkNotNull(id);
+        InstanceIdentifier<Intent> iid = InstanceIdentifier.create(Intents.class).child(Intent.class, new IntentKey(id));
+        mdsal.delete(LogicalDatastoreType.CONFIGURATION, iid);
+        LOG.info("RemoveIntent succeeded");
+    }
+
+    /**
+     * Remove all associated intents by endpointGroupName
+     * @param endpointGroupName
+     */
+    public void removeIntentsByEndpoint(String endpointGroupName) {
+        Preconditions.checkNotNull(endpointGroupName);
+
+        Intents intents = mdsal.read(LogicalDatastoreType.CONFIGURATION, INTENTS_IID);
+
+        if (intents != null && intents.getIntent() != null) {
+            for (Intent intent : intents.getIntent()) {
+                if (intent.getSubjects() != null && intent.getSubjects().size() > 0) {
+                    String endpointValue = "";
+                    for (Subjects subject : intent.getSubjects()) {
+                        if (subject
+                                .getSubject() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroup) {
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroup epg = (org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroup) subject
+                                    .getSubject();
+                            endpointValue = epg.getEndPointGroup().getName();
+                        } else if (subject
+                                .getSubject() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointSelector) {
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointSelector epg = (org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointSelector) subject
+                                    .getSubject();
+                            endpointValue = epg.getEndPointSelector().getEndPointSelector();
+                        } else if (subject
+                                .getSubject() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroupSelector) {
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroupSelector epg = (org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroupSelector) subject
+                                    .getSubject();
+                            endpointValue = epg.getEndPointGroupSelector().getEndPointGroupSelector();
+                        }
+                        if (endpointValue.equalsIgnoreCase(endpointGroupName)) {
+                            removeIntent(intent.getId());
+                            LOG.info("Deleted Intent ID : {} for endpoint: {}", intent.getId(), endpointGroupName);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a list of Intent actions
+     * @param intentAction
+     * @return :a list of Actions
+     */
+    private List<Actions> createActions(String intentAction) {
+        List<Actions> actionsList = new ArrayList<Actions>();
+        short order = 1;
+        org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.Action action = null;
+        if (intentAction.equalsIgnoreCase(ACTION_ALLOW)) {
+            action = new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action
+                    .AllowBuilder().setAllow(new AllowBuilder().build()).build();
+        } else if (intentAction.equalsIgnoreCase(ACTION_BLOCK)) {
+            action = new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action
+                    .BlockBuilder().setBlock(new BlockBuilder().build()).build();
+        }
+
+        Actions intentActions = new ActionsBuilder().setOrder(order).setAction(action).build();
+        actionsList.add(intentActions);
+        return actionsList;
+    }
+
+    /**
+     * Create a list of Intent subjects
+     * @param src :Source Site Name
+     * @param dst :Destination Site Name
+     * @return :a list of Subjects
+     */
+    private List<Subjects> createSubjects(String src, String dst) {
+        List<Subjects> subjectList = new ArrayList<Subjects>();
+
+        EndPointGroup endpointGroupFrom = new EndPointGroupBuilder().setName(src).build();
+        org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroup fromEPG =
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject
+                .EndPointGroupBuilder().setEndPointGroup(endpointGroupFrom).build();
+        Subjects subjects1 = new SubjectsBuilder().setOrder(FIRST_SUBJECT).setSubject(fromEPG).build();
+
+        EndPointGroup endpointGroupTo = new EndPointGroupBuilder().setName(dst).build();
+        org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroup toEPG =
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject
+                .EndPointGroupBuilder().setEndPointGroup(endpointGroupTo).build();
+        Subjects subjects2 = new SubjectsBuilder().setOrder(SECOND_SUBJECT).setSubject(toEPG).build();
+
+        subjectList.add(subjects1);
+        subjectList.add(subjects2);
+        return subjectList;
+    }
+
+    /**
+     * Create a list of Intent constraints
+     * @param failOverType :Type of failover, fast-reroute or slow-reroute
+     * @return
+     */
+    private List<Constraints> createConstraints(String failOverType) {
+        List<Constraints> intentConstraints = new ArrayList<Constraints>();
+        if (failOverType==null) {
+            return intentConstraints;
+        }
+        short order = 1;
+        org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints.Constraints
+            protectionConstraint = null;
+        org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints.Constraints
+            failoverConstraint = null;
+        if (failOverType.equals(FAST_REROUTE)) {
+            protectionConstraint = new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent
+                    .constraints.constraints.ProtectionConstraintBuilder()
+                    .setProtectionConstraint(new ProtectionConstraintBuilder().setIsProtected(true).build()).build();
+            failoverConstraint = new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints
+                    .constraints.FailoverConstraintBuilder()
+                    .setFailoverConstraint(new FailoverConstraintBuilder().setFailoverSelector(FailoverType.FastReroute).build())
+                    .build();
+        } else if (failOverType.equals(SLOW_REROUTE)) {
+            protectionConstraint = new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent
+                    .constraints.constraints.ProtectionConstraintBuilder()
+                    .setProtectionConstraint(new ProtectionConstraintBuilder().setIsProtected(true).build()).build();
+            failoverConstraint = new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints
+                    .constraints.FailoverConstraintBuilder()
+                    .setFailoverConstraint(new FailoverConstraintBuilder().setFailoverSelector(FailoverType.SlowReroute).build())
+                    .build();
+        }
+        Constraints constraint1 = new ConstraintsBuilder().setOrder(order).setConstraints(protectionConstraint).build();
+        Constraints constraint2 = new ConstraintsBuilder().setOrder(++order).setConstraints(failoverConstraint).build();
+        intentConstraints.add(constraint1);
+        intentConstraints.add(constraint2);
+        return intentConstraints;
+    }
+}
diff --git a/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MappingServiceManager.java b/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MappingServiceManager.java
new file mode 100644 (file)
index 0000000..e025b91
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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.vpnservice.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.nic.mapping.api.IntentMappingService;
+
+import com.google.common.base.Preconditions;
+
+public class MappingServiceManager {
+
+    private IntentMappingService intentMappingService;
+    private String IP_PREFIX_PROPERTY = "ip_prefix";
+    private String SWITCH_PORT_ID_PROPERTY = "switch_port";
+    private String MPLS_LABEL_PROPERTY = "mpls_label";
+    private String NEXT_HOP_PROPERTY = "next_hop";
+
+    public MappingServiceManager(IntentMappingService intentMappingService) {
+        Preconditions.checkNotNull(intentMappingService);
+        this.intentMappingService = intentMappingService;
+    }
+
+    /**
+     * @param siteName
+     *            Name of the member
+     * @param ipPrefix
+     *            Ip prefix of the member
+     * @param switchPortId
+     *            Switch ID and port ID (i.e. openflow:1:2)
+     * @param mplsLabel
+     *            MPLS label, if needed
+     * @param nextHop
+     *            Next hop in the route
+     */
+    public void add(final String siteName, final String ipPrefix, final String switchPortId, final Long mplsLabel,
+            final String nextHop) {
+        Preconditions.checkNotNull(siteName);
+        Preconditions.checkNotNull(ipPrefix);
+        Preconditions.checkNotNull(switchPortId);
+
+        Map<String, String> objs = new HashMap<>();
+        objs.put(IP_PREFIX_PROPERTY, ipPrefix);
+        objs.put(SWITCH_PORT_ID_PROPERTY, switchPortId);
+
+        if (mplsLabel != null)
+            objs.put(MPLS_LABEL_PROPERTY, String.valueOf(mplsLabel));
+        if (nextHop != null)
+            objs.put(NEXT_HOP_PROPERTY, nextHop);
+
+        intentMappingService.add(siteName, objs);
+    }
+
+    /**
+     * @param siteName
+     *            Name of the member
+     * @return Map of parameters related to the member
+     */
+    public Map<String, String> get(String siteName) {
+        return intentMappingService.get(siteName);
+    }
+
+    /**
+     * @param siteName
+     *            Name of the member
+     * @return Return true if transaction succeed, otherwise false
+     */
+    public boolean delete(String siteName) {
+        try {
+            // TODO: Implement delete() in mapping service
+            // By now, it's going to overwrite data for this key
+            intentMappingService.add(siteName, null);
+            return true;
+        } catch (Exception e) {
+            throw e;
+        }
+    }
+}
diff --git a/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MplsLabelManagerService.java b/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MplsLabelManagerService.java
new file mode 100644 (file)
index 0000000..48b4986
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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.vpnservice.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.nic.utils.MdsalUtils;
+import org.opendaylight.vpnservice.utils.IidFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.MplsLabels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.labels.Label;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.labels.LabelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.labels.LabelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpn.intent.Endpoint;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MplsLabelManagerService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MplsLabelManagerService.class);
+    private static final Integer MAX_MPLS_LABEL = 524288;
+    private static InstanceIdentifier<Label> LABEL_IID = null;
+    public static final InstanceIdentifier<MplsLabels> MPLS_LABELS_IID = IidFactory.getMplsLabelsIid();
+    private final DataBroker dataBroker;
+    private final Random random = new Random();
+    private MdsalUtils mdsal;
+
+    public MplsLabelManagerService(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+        this.mdsal = new MdsalUtils(this.dataBroker);
+    }
+
+    /**
+     * Generate a unique Mpls Label
+     * Mpls label is of length 20 bits maximum
+     * @return :next unique Mpls label value
+     */
+    public Long getUniqueLabel(Endpoint endpoint)  {
+        Long nextUniqueLabel = (long) random.nextInt(MAX_MPLS_LABEL);
+        while(checkIsLabelUsed(nextUniqueLabel)) {
+            nextUniqueLabel = (long) random.nextInt(MAX_MPLS_LABEL);
+        }
+        updateToLabelStore(nextUniqueLabel, endpoint, true);
+        return nextUniqueLabel;
+    }
+
+    /**
+     * Delete label from datastore
+     * @param endpoint :endpoint whose label needs to be deleted
+     */
+    public void deleteLabel(Endpoint endpoint)  {
+        Map<Long, String> labelMap = getAllLabels();
+        for (Map.Entry<Long, String> labelEntry : labelMap.entrySet()) {
+            if(labelEntry.getValue().equalsIgnoreCase(endpoint.getSiteName())) {
+                updateToLabelStore(labelEntry.getKey(), endpoint, false);
+            }
+        }
+    }
+
+    /**
+     * Update the model for Labels with used Mpls label values
+     * @param label :mpls label allocated to an endpoint
+     * @param endpoint :endpoint to which mpls label is allocated to
+     * @param add :true if add label to datastore, false to delete label from datastore
+     */
+    private void updateToLabelStore(Long label, Endpoint endpoint, boolean add) {
+        LABEL_IID = IidFactory.getLabelIid(label);
+        Label mplsLabel = new LabelBuilder().
+                setKey(new LabelKey(label)).
+                setLabelId(label).
+                setSiteName(endpoint.getSiteName()).
+                setIpPrefix(endpoint.getIpPrefix()).
+                setSwitchPortId(endpoint.getSwitchPortId()).build();
+
+        if(add) {
+            mdsal.put(LogicalDatastoreType.OPERATIONAL, LABEL_IID, mplsLabel);
+            LOG.info("Add mpls label to operational datastore: {} for endpoint: {}", label, endpoint.getSiteName());
+        } else {
+            mdsal.delete(LogicalDatastoreType.OPERATIONAL, LABEL_IID);
+            LOG.info("Delete mpls label from operational datastore: {} for endpoint: {}", label, endpoint.getSiteName());
+        }
+    }
+
+    /**
+     * Check if label is already allocated to any endpoint
+     * @param nextUniqueLabel :value of mpls label
+     * @return :true is label is already used else false
+     */
+    private boolean checkIsLabelUsed(Long nextUniqueLabel) {
+        Map<Long, String> labelMap = getAllLabels();
+        if(labelMap.containsKey(nextUniqueLabel)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Get a map of all the labels allocated to the endpoints
+     * @return :hashmap of labels as key, site names as value
+     */
+    private Map<Long, String> getAllLabels() {
+        Map<Long, String> labelMap = new HashMap<>();
+        MplsLabels mplsLabels = mdsal.read(LogicalDatastoreType.OPERATIONAL, MPLS_LABELS_IID);
+        if(mplsLabels != null) {
+            for (Label label : mplsLabels.getLabel()) {
+                labelMap.put(label.getLabelId(), label.getSiteName());
+            }
+        }
+        return labelMap;
+    }
+}
diff --git a/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/VpnintentProvider.java b/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/VpnintentProvider.java
new file mode 100644 (file)
index 0000000..1618bb1
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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.vpnservice.impl;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.nic.mapping.api.IntentMappingService;
+import org.opendaylight.nic.utils.MdsalUtils;
+import org.opendaylight.vpnservice.utils.IidFactory;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.AddVpnEndpointInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.FailoverType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.MplsLabels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.MplsLabelsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.RemoveVpnEndpointInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.RemoveVpnInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.VpnintentService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.Vpns;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.VpnsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpn.intent.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpn.intent.EndpointBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpn.intent.EndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpns.VpnIntents;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpns.VpnIntentsKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+
+public class VpnintentProvider implements VpnintentService, BindingAwareProvider, AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(VpnintentProvider.class);
+    public static final InstanceIdentifier<MplsLabels> LABELS_IID = IidFactory.getMplsLabelsIid();
+    public static final InstanceIdentifier<Vpns> VPN_IID = IidFactory.getVpnsIid();
+    public static final InstanceIdentifier<VpnIntents> VPN_INTENT_IID = IidFactory.getVpnIntentIid();
+    public static final InstanceIdentifier<Endpoint> ENDPOINT_IID = IidFactory.getEndpointIid();
+
+    private DataBroker dataBroker;
+    private IntentMappingService intentMappingService;
+    private BindingAwareBroker.RpcRegistration<VpnintentService> rpcRegistration = null;
+    private MdsalUtils mdsal;
+
+    @Override
+    public void onSessionInitiated(ProviderContext session) {
+        LOG.info("VpnintentProvider Session Initiated");
+        dataBroker = session.getSALService(DataBroker.class);
+        rpcRegistration = session.addRpcImplementation(VpnintentService.class, this);
+        this.mdsal = new MdsalUtils(this.dataBroker);
+
+        // Load IntentMappingService Reference
+        loadIntentMappingServiceReference();
+
+        Vpns vpns = new VpnsBuilder().build();
+        MplsLabels labels = new MplsLabelsBuilder().build();
+
+        // Initialize MD-SAL data store for vpn-intents and mpls-labels
+        initDatastore(LogicalDatastoreType.CONFIGURATION, VPN_IID, vpns);
+        initDatastore(LogicalDatastoreType.OPERATIONAL, LABELS_IID, labels);
+    }
+
+    @Override
+    public void close() throws Exception {
+        LOG.info("VpnintentProvider Closed");
+    }
+
+    private <T extends DataObject> void initDatastore(LogicalDatastoreType store, InstanceIdentifier<T> iid, T object) {
+        // Put data to MD-SAL data store
+        WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
+        transaction.put(store, iid, object);
+
+        // Perform the tx.submit asynchronously
+        Futures.addCallback(transaction.submit(), new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(final Void result) {
+                LOG.info("initDatastore for VPN-Intents: transaction succeeded");
+            }
+
+            @Override
+            public void onFailure(final Throwable throwable) {
+                LOG.error("initDatastore for VPN-Intents: transaction failed");
+            }
+        });
+        LOG.info("initDatastore: data populated: {}, {}, {}", store, iid, object);
+    }
+
+    @Override
+    public Future<RpcResult<Void>> removeVpn(RemoveVpnInput input) {
+        InstanceIdentifier<VpnIntents> vpnIdentifier = InstanceIdentifier.builder(Vpns.class)
+                .child(VpnIntents.class, new VpnIntentsKey(input.getVpnName())).build();
+        MappingServiceManager msManager = new MappingServiceManager(intentMappingService);
+        MplsLabelManagerService mplsManager = new MplsLabelManagerService(dataBroker);
+
+        VpnIntents vpn = getVpn(input.getVpnName());
+
+        if (vpn.getEndpoint() != null && vpn.getEndpoint().size() > 0) {
+            for (Endpoint endpoint : vpn.getEndpoint()) {
+                // Release MPLS label
+                mplsManager.deleteLabel(endpoint);
+
+                // Remove all intents related to this endpoint
+                IntentServiceManager intentManager = new IntentServiceManager(dataBroker);
+                intentManager.removeIntentsByEndpoint(endpoint.getSiteName());
+
+                // Remove info from Mapping Service
+                msManager.delete(endpoint.getSiteName());
+            }
+        }
+
+        mdsal.delete(LogicalDatastoreType.CONFIGURATION, vpnIdentifier);
+        LOG.info("Deleted VPN {}", input.getVpnName());
+        return Futures.immediateFuture(RpcResultBuilder.<Void> success().build());
+    }
+
+    @Override
+    public Future<RpcResult<Void>> addVpnEndpoint(AddVpnEndpointInput input) {
+        Endpoint currentEndpoint = new EndpointBuilder().setIpPrefix(input.getIpPrefix())
+                .setSiteName(input.getSiteName()).setSwitchPortId(input.getSwitchPortId())
+                .setKey(new EndpointKey(input.getSiteName())).build();
+        VpnIntents vpn = getVpn(input.getVpnName());
+        String failOverType = null;
+        if (vpn.isPathProtection() && vpn.getFailoverType()!= null) {
+            if (vpn.getFailoverType().equals(FailoverType.FastReroute)) {
+                failOverType = IntentServiceManager.FAST_REROUTE;
+            } else if(vpn.getFailoverType().equals(FailoverType.SlowReroute)) {
+                failOverType = IntentServiceManager.SLOW_REROUTE;
+            }
+        }
+
+        MplsLabelManagerService mplsManager = new MplsLabelManagerService(dataBroker);
+
+        // Get unique MPLS label
+        Long mplsLabel = mplsManager.getUniqueLabel(currentEndpoint);
+
+        // Add info into Mapping Service
+        MappingServiceManager msManager = new MappingServiceManager(intentMappingService);
+        msManager.add(currentEndpoint.getSiteName(), extractIP(currentEndpoint.getIpPrefix()),
+                currentEndpoint.getSwitchPortId(), mplsLabel, null);
+
+        if (vpn.getEndpoint() != null && vpn.getEndpoint().size() > 0) {
+            IntentServiceManager intentManager = new IntentServiceManager(dataBroker);
+
+            for (Endpoint member : vpn.getEndpoint()) {
+                // Create mesh of Intents
+                intentManager.addIntent(member.getSiteName(), currentEndpoint.getSiteName(),
+                        IntentServiceManager.ACTION_ALLOW, failOverType);
+                intentManager.addIntent(currentEndpoint.getSiteName(), member.getSiteName(),
+                        IntentServiceManager.ACTION_ALLOW, failOverType);
+            }
+        }
+        // Associate endpoint with VPN
+        addEndpointToVpn(vpn, currentEndpoint);
+
+        return Futures.immediateFuture(RpcResultBuilder.<Void> success().build());
+    }
+
+    /**
+     * @param IpPrefix
+     *            object
+     * @return String representation of IP prefix
+     */
+    private String extractIP(IpPrefix ipPrefix) {
+        String ip = null;
+        if (ipPrefix.getIpv4Prefix() != null) {
+            ip = ipPrefix.getIpv4Prefix().getValue();
+        } else if (ipPrefix.getIpv6Prefix() != null) {
+            ip = ipPrefix.getIpv6Prefix().getValue();
+        }
+        return ip;
+    }
+
+    /**
+     * @param vpnName
+     *            VPN name
+     * @return VPN instance
+     */
+    private VpnIntents getVpn(String vpnName) {
+        InstanceIdentifier<VpnIntents> identifier = InstanceIdentifier.builder(Vpns.class)
+                .child(VpnIntents.class, new VpnIntentsKey(vpnName)).build();
+
+        VpnIntents vpnIntents = mdsal.read(LogicalDatastoreType.CONFIGURATION, identifier);
+        Preconditions.checkNotNull(vpnIntents);
+        return vpnIntents;
+    }
+
+    @Override
+    public Future<RpcResult<Void>> removeVpnEndpoint(RemoveVpnEndpointInput input) {
+        Endpoint endpoint = getEndpoint(input.getVpnName(), input.getSiteName());
+
+        // Release MPLS label
+        MplsLabelManagerService mplsManager = new MplsLabelManagerService(dataBroker);
+        mplsManager.deleteLabel(endpoint);
+
+        // Remove all intents related to this endpoint
+        IntentServiceManager intentManager = new IntentServiceManager(dataBroker);
+        intentManager.removeIntentsByEndpoint(input.getSiteName());
+
+        // Remove endpoint from VPN
+        removeEndpointFromVpn(input.getVpnName(), input.getSiteName());
+
+        return Futures.immediateFuture(RpcResultBuilder.<Void> success().build());
+    }
+
+    /**
+     * @param siteName
+     *            Site name of the VPN member
+     * @return VPN member (Endpoint)
+     */
+    private Endpoint getEndpoint(String vpnName, String siteName) {
+        InstanceIdentifier<Endpoint> endpointID = InstanceIdentifier.builder(Vpns.class)
+                .child(VpnIntents.class, new VpnIntentsKey(vpnName)).child(Endpoint.class, new EndpointKey(siteName))
+                .build();
+
+        return mdsal.read(LogicalDatastoreType.CONFIGURATION, endpointID);
+    }
+
+    /**
+     * @param vpnName
+     *            VPN name
+     * @param siteName
+     *            Site name
+     */
+    private void removeEndpointFromVpn(String vpnName, String siteName) {
+        InstanceIdentifier<Endpoint> identifier = InstanceIdentifier.builder(Vpns.class)
+                .child(VpnIntents.class, new VpnIntentsKey(vpnName)).child(Endpoint.class, new EndpointKey(siteName))
+                .build();
+
+        mdsal.delete(LogicalDatastoreType.CONFIGURATION, identifier);
+        LOG.info("Deleted VPN member : {} from VPN: {}", siteName, vpnName);
+    }
+
+    /**
+     * @param vpn
+     *            VPN
+     * @param vpnMember
+     *            VPN member (endpoint)
+     */
+    private void addEndpointToVpn(VpnIntents vpn, Endpoint vpnMember) {
+        InstanceIdentifier<Endpoint> identifier = InstanceIdentifier.builder(Vpns.class)
+                .child(VpnIntents.class, vpn.getKey())
+                .child(Endpoint.class, vpnMember.getKey()).build();
+
+        mdsal.put(LogicalDatastoreType.CONFIGURATION, identifier, vpnMember);
+        LOG.info("Added VPN member : {} to VPN: {}", vpnMember.getSiteName(), vpn.getVpnName());
+    }
+
+    /**
+     * Load IntentMappingService reference
+     */
+    private void loadIntentMappingServiceReference() {
+        ServiceReference<?> serviceReference = getBundleCtx().getServiceReference(IntentMappingService.class);
+        intentMappingService = (IntentMappingService) getBundleCtx().getService(serviceReference);
+    }
+
+    private BundleContext getBundleCtx() {
+        return FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+    }
+}
diff --git a/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/utils/IidFactory.java b/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/utils/IidFactory.java
new file mode 100644 (file)
index 0000000..e08cf67
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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.vpnservice.utils;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.Intents;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.MplsLabels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.Vpns;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.labels.Label;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.labels.LabelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpn.intent.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpns.VpnIntents;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class IidFactory {
+
+    public static InstanceIdentifier<MplsLabels> getMplsLabelsIid() {
+        return InstanceIdentifier.builder(MplsLabels.class).build();
+    }
+
+    public static InstanceIdentifier<Label> getLabelIid(Long label) {
+        return InstanceIdentifier.create(MplsLabels.class).child(Label.class, new LabelKey(label));
+    }
+
+    public static InstanceIdentifier<Intents> getIntentsIid() {
+        return InstanceIdentifier.builder(Intents.class).build();
+    }
+
+    public static InstanceIdentifier<Vpns> getVpnsIid() {
+        return InstanceIdentifier.builder(Vpns.class).build();
+    }
+
+    public static InstanceIdentifier<VpnIntents> getVpnIntentIid() {
+        return InstanceIdentifier.builder(Vpns.class).child(VpnIntents.class).build();
+    }
+
+    public static InstanceIdentifier<Endpoint> getEndpointIid() {
+        return InstanceIdentifier.builder(Vpns.class).child(VpnIntents.class).child(Endpoint.class).build();
+    }
+}
diff --git a/vpnintent/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnintent/impl/rev141210/VpnintentImplModule.java b/vpnintent/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnintent/impl/rev141210/VpnintentImplModule.java
new file mode 100644 (file)
index 0000000..7d0cfb1
--- /dev/null
@@ -0,0 +1,26 @@
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.impl.rev141210;
+
+import org.opendaylight.vpnservice.impl.VpnintentProvider;
+
+public class VpnintentImplModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.impl.rev141210.AbstractVpnintentImplModule {
+    public VpnintentImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public VpnintentImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.impl.rev141210.VpnintentImplModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        VpnintentProvider provider = new VpnintentProvider();
+        getBrokerDependency().registerProvider(provider);
+        return provider;
+    }
+
+}
diff --git a/vpnintent/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnintent/impl/rev141210/VpnintentImplModuleFactory.java b/vpnintent/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpnintent/impl/rev141210/VpnintentImplModuleFactory.java
new file mode 100644 (file)
index 0000000..a369ccc
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: vpnintent-impl yang module local name: vpnintent-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Dec 16 22:44:32 EST 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.impl.rev141210;
+public class VpnintentImplModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.impl.rev141210.AbstractVpnintentImplModuleFactory {
+
+}
diff --git a/vpnintent/impl/src/main/yang/vpnintent-impl.yang b/vpnintent/impl/src/main/yang/vpnintent-impl.yang
new file mode 100644 (file)
index 0000000..1016f7e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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 INTERNAL
+ */
+module vpnintent-impl {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:vpnintent:impl";
+    prefix "vpnintent-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+
+    description
+        "Service definition for vpnintent project";
+
+    revision "2014-12-10" {
+        description
+            "Initial revision";
+    }
+
+    identity vpnintent-impl {
+        base config:module-type;
+        config:java-name-prefix VpnintentImpl;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case vpnintent-impl {
+            when "/config:modules/config:module/config:type = 'vpnintent-impl'";
+            container broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding:binding-broker-osgi-registry;
+                    }
+                }
+            }
+            container rpc-registry {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding:binding-rpc-registry;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/IntentServiceManagerTest.java b/vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/IntentServiceManagerTest.java
new file mode 100644 (file)
index 0000000..71ef33c
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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.vpnservice.impl;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.nic.utils.MdsalUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.Intents;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.IntentsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.Intent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.IntentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.types.rev150122.Uuid;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@PrepareForTest({IntentServiceManager.class})
+@RunWith(PowerMockRunner.class)
+public class IntentServiceManagerTest {
+
+    private static final String SRC_SITE_NAME = "site a";
+    private static final String DST_SITE_NAME = "site b";
+    private static final String INTENT_ALLOW_ACTION = "ALLOW";
+    private IntentServiceManager intentServiceManager;
+    @Mock private MdsalUtils mdsal;
+
+    @Before
+    public void setUp() throws Exception {
+        intentServiceManager = mock(IntentServiceManager.class, Mockito.CALLS_REAL_METHODS);
+        MemberModifier.field(IntentServiceManager.class, "mdsal").set(intentServiceManager, mdsal);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testAddIntent() throws Exception {
+        IntentBuilder intentBldr = mock(IntentBuilder.class);
+        PowerMockito.whenNew(IntentBuilder.class).withNoArguments().thenReturn(intentBldr);
+        when(intentBldr.setId(any(Uuid.class))).thenReturn(intentBldr);
+        when(intentBldr.setSubjects(any(List.class))).thenReturn(intentBldr);
+        when(intentBldr.setActions(any(List.class))).thenReturn(intentBldr);
+        when(intentBldr.setConstraints(any(List.class))).thenReturn(intentBldr);
+        when(intentBldr.build()).thenReturn(mock(Intent.class));
+
+        Intents currentIntents = mock(Intents.class);
+        PowerMockito.when(mdsal.read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class))).thenReturn(currentIntents);
+        IntentsBuilder intentsBldr = mock(IntentsBuilder.class);
+        PowerMockito.whenNew(IntentsBuilder.class).withNoArguments().thenReturn(intentsBldr);
+        when(intentsBldr.setIntent(any(List.class))).thenReturn(intentsBldr);
+        PowerMockito.when(mdsal.put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Intents.class))).thenReturn(true);
+
+        intentServiceManager.addIntent(SRC_SITE_NAME, DST_SITE_NAME, INTENT_ALLOW_ACTION, "fast-reroute");
+        verify(intentBldr).setId(any(Uuid.class));
+        verify(mdsal).read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(mdsal).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Intents.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testRemoveIntents() {
+        Uuid id = mock(Uuid.class);
+        when(mdsal.delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class))).thenReturn(true);
+
+        intentServiceManager.removeIntent(id);
+        verify(mdsal).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+    }
+}
diff --git a/vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/MappingServiceManagerTests.java b/vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/MappingServiceManagerTests.java
new file mode 100644 (file)
index 0000000..2fa5cb3
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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.vpnservice.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+import org.opendaylight.nic.mapping.api.IntentMappingService;
+
+public class MappingServiceManagerTests {
+
+    @Test
+    public void addInfo() {
+        // Arrange
+        String siteName = "UoR";
+        String ipPrefix = "16.101.233.2/8";
+        String switchPortId = "openflow:1:3";
+        long mplsLabel = 10L;
+        String nextHop = "16.101.233.1/8";
+
+        Map<String, String> map = new HashMap<>();
+        map.put("ip_prefix", ipPrefix);
+        map.put("switch_port", switchPortId);
+        map.put("mpls_label", String.valueOf(mplsLabel));
+        map.put("next_hop", nextHop);
+
+        IntentMappingService mapSvc = mock(IntentMappingService.class);
+        when(mapSvc.get(any(String.class))).thenReturn(map);
+
+        MappingServiceManager manager = new MappingServiceManager(mapSvc);
+
+        // Act
+        manager.add(siteName, ipPrefix, switchPortId, mplsLabel, nextHop);
+
+        Map<String, String> returnedObjs = manager.get(siteName);
+
+        // Assert
+        assertEquals(ipPrefix, returnedObjs.get("ip_prefix"));
+        assertEquals(switchPortId, returnedObjs.get("switch_port"));
+        assertEquals(mplsLabel, Long.parseLong(returnedObjs.get("mpls_label")));
+        assertEquals(nextHop, returnedObjs.get("next_hop"));
+    }
+
+    @Test
+    public void removeInfo() {
+        // Arrange
+        String siteName = "UoR";
+        String ipPrefix = "16.101.233.2/8";
+        String switchPortId = "openflow:1:3";
+
+        Map<String, String> map = new HashMap<>();
+        map.put("ip_prefix", ipPrefix);
+        map.put("switch_port", switchPortId);
+
+        IntentMappingService mapSvc = mock(IntentMappingService.class);
+
+        MappingServiceManager manager = new MappingServiceManager(mapSvc);
+
+        // Add first to delete next
+        manager.add(siteName, ipPrefix, switchPortId, null, null);
+
+        // Act
+        boolean result = manager.delete(siteName);
+
+        // Assert
+        assertTrue(result);
+    }
+}
diff --git a/vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/VpnintentProviderTest.java b/vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/VpnintentProviderTest.java
new file mode 100644 (file)
index 0000000..a23d8ae
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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.vpnservice.impl;
+
+import static org.mockito.Mockito.mock;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+
+public class VpnintentProviderTest {
+    @Ignore
+    @Test
+    public void testOnSessionInitiated() {
+        VpnintentProvider provider = new VpnintentProvider();
+
+        // ensure no exceptions
+        // currently this method is empty
+        provider.onSessionInitiated(mock(BindingAwareBroker.ProviderContext.class));
+    }
+
+    @Ignore
+    @Test
+    public void testClose() throws Exception {
+        VpnintentProvider provider = new VpnintentProvider();
+
+        // ensure no exceptions
+        // currently this method is empty
+        provider.close();
+    }
+}
diff --git a/vpnintent/pom.xml b/vpnintent/pom.xml
new file mode 100644 (file)
index 0000000..32d0504
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2016 Inocybe Technologies 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 INTERNAL
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent-lite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+  </parent>
+
+  <groupId>org.opendaylight.vpnservice</groupId>
+  <artifactId>vpnintent-aggregator</artifactId>
+  <version>0.3.0-SNAPSHOT</version>
+  <name>vpnintent</name>
+  <packaging>pom</packaging>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <modules>
+    <module>api</module>
+    <module>impl</module>
+  </modules>
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
+
diff --git a/vpnintent/resources/vpnintent.postman_collection b/vpnintent/resources/vpnintent.postman_collection
new file mode 100644 (file)
index 0000000..f1a5d92
--- /dev/null
@@ -0,0 +1,384 @@
+{
+       "id": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+       "name": "VPN Intents",
+       "description": "Apply protection and failover-type constraints to VpnService and NIC. When protections is set to true, and failover type is either soft-reroute or hard-reroute then the end-to-end connectivity is self-healing in case of link/node failure. VpnService shall create Intent object with constraints embedded in it (constraints are set by users) and NIC renders flows according based on the constraints.\n\nDisjoint Path Calculation using Suurballe Algorithm when soft-reroute constraint is applied to NIC, two disjoint paths are calculated. When one of the paths is non-usable due to a link/node failure the other disjoint path is automatically invoked to push required flows for all the intents that get affection by the failed path.\n\nDelete flows from the switch when an intent is removed: NIC did not support deleting flows from the nodes when an intent was removed, this was also fixed.",
+       "order": [],
+       "folders": [
+               {
+                       "id": "d424223b-11b7-b00d-3875-70b5fb4e6e85",
+                       "name": "Add Members to VPN",
+                       "description": "",
+                       "order": [
+                               "bfcc70b5-208a-d64e-7277-f4174b5f9ff9",
+                               "45328601-ed77-b7ff-0ae6-c5734c69c170",
+                               "84f7e114-532c-02d4-45fa-6e335f2a7e5d",
+                               "6421391f-20de-e31b-00a4-5cf36297c074"
+                       ],
+                       "owner": "255113",
+                       "collectionId": "6f9c9d85-2bda-9f02-eaec-a5269af5c0b5"
+               },
+               {
+                       "id": "2049f3c6-ebf5-a456-61de-ee9abd1811f4",
+                       "name": "Create VPN",
+                       "description": "",
+                       "order": [
+                               "e5f75d2a-c350-e601-5029-e6e5ea736eef",
+                               "91d91020-d5e0-2aaf-6c09-ed9cdec077de",
+                               "72ac6ee2-90a8-36b1-0dda-9eb886df197c"
+                       ],
+                       "owner": "255113",
+                       "collectionId": "6f9c9d85-2bda-9f02-eaec-a5269af5c0b5"
+               },
+               {
+                       "id": "a2deb454-a0e6-3870-0c64-ba7fdffaccba",
+                       "name": "MPLS Label Management",
+                       "description": "Includes a set of GET operations to access the labels assigned to each member",
+                       "order": [
+                               "e7ba99ee-7804-d411-e652-9d932687a35c"
+                       ],
+                       "owner": "255113",
+                       "collectionId": "efd3dae9-0818-468a-0d86-86fcec008d22"
+               },
+               {
+                       "id": "118a7d9f-7925-4e75-d59a-f9c151b1c4c4",
+                       "name": "Network Intent Composition Operations",
+                       "description": "GET operations to check the state of Intents",
+                       "order": [
+                               "109d1ae7-bdd4-907e-be5d-61b6f493640b"
+                       ],
+                       "owner": "255113",
+                       "collectionId": "748af960-874f-028d-cbd0-74134a3c6db7"
+               },
+               {
+                       "id": "3ab1d430-5cc5-f506-0619-b827cc6f645b",
+                       "name": "Remove Member from VPN",
+                       "description": "",
+                       "order": [
+                               "d3250d1d-ca8d-9a31-dec7-4ded8720e530",
+                               "42034ad0-1789-a773-6be3-9b9b5c4881bf",
+                               "13757df8-f5ea-c933-a991-b9a8e4d60b07",
+                               "0063438d-94b1-5ca3-88f2-1d789f3d2251"
+                       ],
+                       "owner": "255113",
+                       "collectionId": "6f9c9d85-2bda-9f02-eaec-a5269af5c0b5"
+               },
+               {
+                       "id": "3958cf6c-b82e-f0d4-a5c3-ce0bb85464c7",
+                       "name": "Remove VPN",
+                       "description": "",
+                       "order": [
+                               "63050e81-9cac-5de5-2180-7ed5c6bd361a",
+                               "b0ac20bf-7cad-e958-761c-a83a456afdd4"
+                       ],
+                       "owner": "255113"
+               }
+       ],
+       "timestamp": 1450878947771,
+       "owner": "255113",
+       "remoteLink": "",
+       "public": false,
+       "requests": [
+               {
+                       "id": "0063438d-94b1-5ca3-88f2-1d789f3d2251",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/operations/vpnintent:remove-vpn-endpoint",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452741595237,
+                       "name": "Remove Member 4 (site 4)  from unprotected VPN",
+                       "description": "Remove a Member from a VPN\n\nParameters description\nsite-name: Name of the member\nvpn-name: The VPN from which the member should be deleted",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "rawModeData": "{\n \"input\": {\n       \"vpn-name\": \"VPN unprotected\",\n        \"site-name\": \"site 4\"\n   }\n}"
+               },
+               {
+                       "id": "109d1ae7-bdd4-907e-be5d-61b6f493640b",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/config/intent:intents/",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "GET",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "data": [],
+                       "dataMode": "params",
+                       "name": "GET intents",
+                       "description": "Gets a list of intents added",
+                       "descriptionFormat": "html",
+                       "time": 1450721033712,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "folder": "118a7d9f-7925-4e75-d59a-f9c151b1c4c4"
+               },
+               {
+                       "id": "13757df8-f5ea-c933-a991-b9a8e4d60b07",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/operations/vpnintent:remove-vpn-endpoint",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452741569695,
+                       "name": "Remove Member 3 (site 3)   from unprotected VPN",
+                       "description": "Remove a Member from a VPN\n\nParameters description\nsite-name: Name of the member\nvpn-name: The VPN from which the member should be deleted",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "rawModeData": "{\n \"input\": {\n       \"vpn-name\": \"VPN unprotected\",\n        \"site-name\": \"site 3\"\n   }\n}"
+               },
+               {
+                       "id": "42034ad0-1789-a773-6be3-9b9b5c4881bf",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/operations/vpnintent:remove-vpn-endpoint",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452741544712,
+                       "name": "Remove Member 2 (site 2)   from protected VPN",
+                       "description": "Remove a Member from a VPN\n\nParameters description\nsite-name: Name of the member\nvpn-name: The VPN from which the member should be deleted",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "rawModeData": "{\n \"input\": {\n       \"vpn-name\": \"VPN protected\",\n        \"site-name\": \"site 2\"\n   }\n}"
+               },
+               {
+                       "id": "45328601-ed77-b7ff-0ae6-c5734c69c170",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/operations/vpnintent:add-vpn-endpoint",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452741386479,
+                       "name": "Add Member 2 (site 2)  to protected VPN",
+                       "description": "Add a Member to a protected VPN\n\nParameters description\nsite-name: Name of the member\nip-prefix: The IP Prefix associated with the Site-Name\nswitch-port-id: The PE switch id:port to which the site is connected to\nvpn-name: The VPN to which the member should belong to",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "rawModeData": "{\n \"input\": {\n       \"vpn-name\": \"VPN protected\",\n        \"site-name\": \"site 2\",\n        \"ip-prefix\": \"10.0.0.2/32\",\n        \"switch-port-id\": \"openflow:2:1\"\n   }\n}"
+               },
+               {
+                       "id": "63050e81-9cac-5de5-2180-7ed5c6bd361a",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/operations/vpnintent:remove-vpn",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452741509183,
+                       "name": "Remove protected VPN",
+                       "description": "Delete a VPN\n\nParameters description\nvpn-name: The VPN that needs to be deleted",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "rawModeData": "{\n \"input\": {\n       \"vpn-name\": \"VPN protected\"\n   }\n}"
+               },
+               {
+                       "id": "6421391f-20de-e31b-00a4-5cf36297c074",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/operations/vpnintent:add-vpn-endpoint",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452741358417,
+                       "name": "Add Member 4 (site 4)  to unprotected VPN",
+                       "description": "Add a Member to an unprotected VPN\n\nParameters description\nsite-name: Name of the member\nip-prefix: The IP Prefix associated with the Site-Name\nswitch-port-id: The PE switch id:port to which the site is connected to\nvpn-name: The VPN to which the member should belong to",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "rawModeData": "{\n \"input\": {\n       \"vpn-name\": \"VPN unprotected\",\n        \"site-name\": \"site 4\",\n        \"ip-prefix\": \"10.0.0.4/32\",\n        \"switch-port-id\": \"openflow:4:1\"\n   }\n}"
+               },
+               {
+                       "id": "72ac6ee2-90a8-36b1-0dda-9eb886df197c",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/config/vpnintent:vpns/",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "GET",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "data": [],
+                       "dataMode": "params",
+                       "name": "GET VPNs",
+                       "description": "Gets a list of all the VPNs along with the list of members that belong to these VPNs",
+                       "descriptionFormat": "html",
+                       "time": 1450716801343,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "folder": "2049f3c6-ebf5-a456-61de-ee9abd1811f4"
+               },
+               {
+                       "id": "84f7e114-532c-02d4-45fa-6e335f2a7e5d",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/operations/vpnintent:add-vpn-endpoint",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452741323406,
+                       "name": "Add Member 3 (site 3)  to unprotected VPN",
+                       "description": "Add a Member to an unprotected VPN\n\nParameters description\nsite-name: Name of the member\nip-prefix: The IP Prefix associated with the Site-Name\nswitch-port-id: The PE switch id:port to which the site is connected to\nvpn-name: The VPN to which the member should belong to",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "rawModeData": "{\n \"input\": {\n       \"vpn-name\": \"VPN unprotected\",\n        \"site-name\": \"site 3\",\n        \"ip-prefix\": \"10.0.0.1/32\",\n        \"switch-port-id\": \"openflow:3:1\"\n   }\n}"
+               },
+               {
+                       "id": "91d91020-d5e0-2aaf-6c09-ed9cdec077de",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/config/vpnintent:vpns/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452741250149,
+                       "name": "Create an unprotected VPN",
+                       "description": "Create a protected VPN by pushing to config data tree to the Vpn-intents Yang model\n\nParameters description\nvpn-name: The name of the VPN that you intend to create\nprotection: True if path protection is needed\nfailover-type: Type of failover mechanism\n               - slow-reroute\n               - fast-reroute",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "rawModeData": "{\n    \"vpn-intents\": [\n        {\n            \"vpn-name\": \"VPN unprotected\",\n            \"path-protection\": \"false\",\n            \"failover-type\": \"slow-reroute\"\n        }\n    ]\n}"
+               },
+               {
+                       "id": "b0ac20bf-7cad-e958-761c-a83a456afdd4",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/operations/vpnintent:remove-vpn",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452741501187,
+                       "name": "Remove unprotected VPN",
+                       "description": "Delete a VPN\n\nParameters description\nvpn-name: The VPN that needs to be deleted",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "rawModeData": "{\n \"input\": {\n       \"vpn-name\": \"VPN unprotected\"\n   }\n}"
+               },
+               {
+                       "id": "bfcc70b5-208a-d64e-7277-f4174b5f9ff9",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/operations/vpnintent:add-vpn-endpoint",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452741369995,
+                       "name": "Add Member 1 (site 1)  to protected VPN",
+                       "description": "Add a Member to a protected VPN\n\nParameters description\nsite-name: Name of the member\nip-prefix: The IP Prefix associated with the Site-Name\nswitch-port-id: The PE switch id:port to which the site is connected to\nvpn-name: The VPN to which the member should belong to",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "rawModeData": "{\n \"input\": {\n       \"vpn-name\": \"VPN protected\",\n        \"site-name\": \"site 1\",\n        \"ip-prefix\": \"10.0.0.1/32\",\n        \"switch-port-id\": \"openflow:1:1\"\n   }\n}"
+               },
+               {
+                       "id": "d3250d1d-ca8d-9a31-dec7-4ded8720e530",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/operations/vpnintent:remove-vpn-endpoint",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452741522615,
+                       "name": "Remove Member 1 (site 1)  from protected VPN",
+                       "description": "Remove a Member from a VPN\n\nParameters description\nsite-name: Name of the member\nvpn-name: The VPN from which the member should be deleted",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "rawModeData": "{\n \"input\": {\n       \"vpn-name\": \"VPN protected\",\n        \"site-name\": \"site 1\"\n   }\n}"
+               },
+               {
+                       "id": "e5f75d2a-c350-e601-5029-e6e5ea736eef",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/config/vpnintent:vpns/",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "POST",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452741238916,
+                       "name": "Create a protected VPN",
+                       "description": "Create a protected VPN by pushing to config data tree to the Vpn-intents Yang model\n\nParameters description\nvpn-name: The name of the VPN that you intend to create\nprotection: True if path protection is needed\nfailover-type: Type of failover mechanism\n               - slow-reroute\n               - fast-reroute",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "rawModeData": "{\n    \"vpn-intents\": [\n        {\n            \"vpn-name\": \"VPN protected\",\n            \"path-protection\": \"true\",\n            \"failover-type\": \"slow-reroute\"\n        }\n    ]\n}"
+               },
+               {
+                       "id": "e7ba99ee-7804-d411-e652-9d932687a35c",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nAccept: application/xml\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/operational/vpnintent:mpls-labels",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "params",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1452282516268,
+                       "name": "GET all unique MPLS Labels",
+                       "description": "Gets a list of unique labels assigned to every Member in the VPN",
+                       "collectionId": "6250512e-90d0-2fb5-259d-2496c6cd8426",
+                       "responses": [],
+                       "folder": "a2deb454-a0e6-3870-0c64-ba7fdffaccba"
+               }
+       ]
+}
\ No newline at end of file
index 599f70380f12b18ab36c76ea206378bed0b5ed61..206f884a3c6dcfb56bbd25669cd6e9c9bb33d7f2 100644 (file)
@@ -76,14 +76,14 @@ public class InterfaceStateChangeListener extends AbstractDataChangeListener<Int
         LOG.info("Received port UP event for interface {} ", interfaceName);
         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface
             configInterface = InterfaceUtils.getInterface(broker, interfaceName);
+        BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(intrf);
         if (configInterface != null && configInterface.getType().equals(Tunnel.class)) {
-          BigInteger dpnId = InterfaceUtils.getDpnForInterface(interfaceManager, interfaceName);
           if(intrf.getOperStatus().equals(Interface.OperStatus.Up)) {
             //advertise all prefixes in all vpns for this dpn to bgp
             vpnInterfaceManager.updatePrefixesForDPN(dpnId, VpnInterfaceManager.UpdateRouteAction.ADVERTISE_ROUTE);
           }
         } else {
-          vpnInterfaceManager.processVpnInterfaceUp(interfaceName, intrf.getIfIndex());
+          vpnInterfaceManager.processVpnInterfaceUp(dpnId, interfaceName, intrf.getIfIndex());
         }
       } catch (Exception e) {
         LOG.error("Exception caught in Interface Operational State Up event", e);
@@ -103,20 +103,15 @@ public class InterfaceStateChangeListener extends AbstractDataChangeListener<Int
         LOG.info("Received port DOWN event for interface {} ", interfaceName);
         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface
             intf = InterfaceUtils.getInterface(broker, interfaceName);
+        BigInteger dpId = InterfaceUtils.getDpIdFromInterface(intrf);
         if (intf != null && intf.getType().equals(Tunnel.class)) {
-          // Get the dpId from del reference itself. Because interfaceManager.getDpnForInterface returns
-          // NPE because entry is already deleted in operational data store
-          BigInteger dpId = getDpIdFromInterface(intrf);
-          if (dpId == null) {
-            return;
-          }
           if(intrf.getOperStatus().equals(Interface.OperStatus.Down)) {
             //withdraw all prefixes in all vpns for this dpn from bgp
             vpnInterfaceManager.updatePrefixesForDPN(dpId, VpnInterfaceManager.UpdateRouteAction.WITHDRAW_ROUTE);
           }
         } else {
           if (VpnUtil.isVpnInterfaceConfigured(broker, interfaceName)) {
-            vpnInterfaceManager.processVpnInterfaceDown(interfaceName, intrf.getIfIndex(), true);
+            vpnInterfaceManager.processVpnInterfaceDown(dpId, interfaceName, intrf.getIfIndex(), true);
           }
         }
       } catch (Exception e) {
@@ -132,7 +127,7 @@ public class InterfaceStateChangeListener extends AbstractDataChangeListener<Int
       org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface
           intf = InterfaceUtils.getInterface(broker, interfaceName);
       if (intf != null && intf.getType().equals(Tunnel.class)) {
-        BigInteger dpnId = InterfaceUtils.getDpnForInterface(interfaceManager, interfaceName);
+        BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(update);
         if(update.getOperStatus().equals(Interface.OperStatus.Up)) {
           //advertise all prefixes in all vpns for this dpn to bgp
           vpnInterfaceManager.updatePrefixesForDPN(dpnId, VpnInterfaceManager.UpdateRouteAction.ADVERTISE_ROUTE);
@@ -144,12 +139,4 @@ public class InterfaceStateChangeListener extends AbstractDataChangeListener<Int
 
     }
 
-  public BigInteger getDpIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface infState) {
-    org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
-        InterfaceUtils.getInterfaceStateFromOperDS(broker, infState.getName());
-    String lowerLayerIf = ifState.getLowerLayerIf().get(0);
-    NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
-    return new BigInteger(InterfaceUtils.getDpnFromNodeConnectorId(nodeConnectorId));
-  }
-
 }
index 61ff3b818d97630a3ab68ce16407f862fdb95834..d4dd28813275770c4469305e425fc7ca74e2377a 100644 (file)
@@ -182,13 +182,13 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
         if (interfaceState != null) {
             // Interface state is up
-            processVpnInterfaceUp(interfaceName, interfaceState.getIfIndex());
+            processVpnInterfaceUp(InterfaceUtils.getDpIdFromInterface(interfaceState), interfaceName, interfaceState.getIfIndex());
         } else {
             LOG.trace("VPN interfaces are not yet operational.");
         }
     }
 
-    protected void processVpnInterfaceUp(String interfaceName, int lPortTag) {
+    protected void processVpnInterfaceUp(BigInteger dpId, String interfaceName, int lPortTag) {
 
         VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, interfaceName);
         if(vpnInterface == null) {
@@ -208,7 +208,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
         synchronized (interfaceName.intern()) {
 
-            bindService(vpnName, interfaceName, lPortTag);
+            bindService(dpId, vpnName, interfaceName, lPortTag);
             updateDpnDbs(vpnName, interfaceName, true);
             processVpnInterfaceAdjacencies(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
         }
@@ -227,7 +227,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 
     }
 
-    private void bindService(String vpnInstanceName, String vpnInterfaceName, int lPortTag) {
+    private void bindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName, int lPortTag) {
         int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
         long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
 
@@ -244,7 +244,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                                             VpnConstants.COOKIE_VM_INGRESS_TABLE, instructions);
         VpnUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
                           InterfaceUtils.buildServiceId(vpnInterfaceName, VpnConstants.L3VPN_SERVICE_IDENTIFIER), serviceInfo);
-        makeArpFlow(VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName, vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW);
+        makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
+                    vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW);
 
     }
 
@@ -307,7 +308,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
     }
 
-    private void makeArpFlow(short sIndex, int lPortTag, String vpnInterfaceName, long vpnId, ArpReplyOrRequest replyOrRequest, int addOrRemoveFlow){
+    private void makeArpFlow(BigInteger dpId,short sIndex, int lPortTag, String vpnInterfaceName,
+                             long vpnId, ArpReplyOrRequest replyOrRequest, int addOrRemoveFlow){
         List<MatchInfo> matches = new ArrayList<MatchInfo>();
         BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lPortTag, ++sIndex, BigInteger.valueOf(vpnId));
         BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
@@ -327,7 +329,6 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
 
         // Install the flow entry in L3_INTERFACE_TABLE
-        BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, vpnInterfaceName);
         String flowRef = VpnUtil.getFlowRef(dpId, NwConstants.L3_INTERFACE_TABLE,
                     NwConstants.ETHTYPE_ARP, lPortTag, replyOrRequest.getArpOperation());
         FlowEntity flowEntity;
@@ -446,13 +447,13 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
 
         if (existingVpnInterface.isPresent() && interfaceState != null) {
-            processVpnInterfaceDown(interfaceName, interfaceState.getIfIndex(), false);
+            processVpnInterfaceDown(InterfaceUtils.getDpIdFromInterface(interfaceState), interfaceName, interfaceState.getIfIndex(), false);
         } else {
             LOG.warn("VPN interface {} was unavailable in operational data store to handle remove event", interfaceName);
         }
     }
 
-    protected void processVpnInterfaceDown(String interfaceName, int lPortTag, boolean isInterfaceStateDown) {
+    protected void processVpnInterfaceDown(BigInteger dpId, String interfaceName, int lPortTag, boolean isInterfaceStateDown) {
         VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
         if(vpnInterface == null) {
             LOG.info("Unable to process delete/down for interface {} as it is not available in operational data store", interfaceName);
@@ -464,7 +465,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         synchronized (interfaceName.intern()) {
             removeAdjacenciesFromVpn(identifier, vpnInterface);
             LOG.info("Unbinding vpn service from interface {} ", interfaceName);
-            unbindService(vpnName, interfaceName, lPortTag, isInterfaceStateDown);
+            unbindService(dpId, vpnName, interfaceName, lPortTag, isInterfaceStateDown);
 
             //wait till DCN for removal of vpn interface in operational DS arrives
             Runnable notifyTask = new VpnNotifyTask();
@@ -513,7 +514,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     }
 
 
-    private void unbindService(String vpnInstanceName, String vpnInterfaceName, int lPortTag, boolean isInterfaceStateDown) {
+    private void unbindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName,
+                               int lPortTag, boolean isInterfaceStateDown) {
         if (!isInterfaceStateDown) {
             VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION,
                            InterfaceUtils.buildServiceId(vpnInterfaceName,
@@ -521,7 +523,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                            VpnUtil.DEFAULT_CALLBACK);
         }
         long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
-        makeArpFlow(VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
+        makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
                     vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW);
     }
 
index bd0f22a35ccc89b300363e2421e298c2cda63e44..36ffe3d20e6c0a792c0e5bc4a69983a5def0a8d2 100644 (file)
@@ -144,4 +144,11 @@ public class InterfaceUtils {
     String[] split = portId.getValue().split(OF_URI_SEPARATOR);
     return split[1];
   }
+
+  public static BigInteger getDpIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
+    String lowerLayerIf = ifState.getLowerLayerIf().get(0);
+    NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
+    return new BigInteger(getDpnFromNodeConnectorId(nodeConnectorId));
+  }
+
 }