SubnetRoute enhancements to VPN Service models 01/37001/5
authorSuraj Ranjan <suraj.ranjan@ericsson.com>
Fri, 1 Apr 2016 12:18:39 +0000 (17:48 +0530)
committerSuraj Ranjan <suraj.ranjan@ericsson.com>
Tue, 5 Apr 2016 07:40:52 +0000 (07:40 +0000)
This commit deals with changes required to construct
internal data structures to provide SubnetRoute
facility in VPN Service.  With SubnetRoute facility
all packets intended for a cloud coming from a
DC gateway will be punted to one DPN that will be
considered as designated DPN.

Change-Id: Ie33ad0c62bf686496460b94bd4de6f9e28e1ae5b
Signed-off-by: Suraj Ranjan <suraj.ranjan@ericsson.com>
Co-Authored-By: Vivekanandan Narasimhan <n.vivekanandan@ericsson.com>
Co-Authored-By: Karan Raj Singh <karan.raj.s.singh@ericsson.com>
Co-Authored-By: Achuth Maniyedath <achuth.maniyedath@ericsson.com>
21 files changed:
bgpmanager/bgpmanager-api/src/main/java/org.opendaylight.bgpmanager.api/IBgpManager.java
bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpManager.java
fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java
neutronvpn/neutronvpn-api/src/main/yang/neutronvpn.yang
neutronvpn/neutronvpn-impl/src/main/config/default-config.xml
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronPortChangeListener.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnManager.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnProvider.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/neutronvpn/impl/rev150325/NeutronvpnImplModule.java
neutronvpn/neutronvpn-impl/src/main/yang/neutronvpn-impl.yang
vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang
vpnmanager/vpnmanager-impl/pom.xml
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/InterfaceStateChangeListener.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/SubnetOpDpnManager.java [new file with mode: 0644]
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/SubnetRoutePacketInHandler.java [new file with mode: 0644]
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnConstants.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnManager.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnSubnetRouteHandler.java [new file with mode: 0644]
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnUtil.java
vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnserviceProvider.java

index 3ffa33f2f29dfce9b467c20ed9876282a35e1e3c..d0fabf4add71da83dae40d2e9837abd448264e6c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. 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,
@@ -49,6 +49,22 @@ public interface IBgpManager {
      */
     public void setQbgpLog(String fileName, String logLevel) throws Exception;
 
+    /**
+     * @param rd
+     * @param prefix
+     * @param nextHop
+     * @param vpnLabel
+     */
+    public void advertisePrefix(String rd, String prefix, String nextHop, int vpnLabel) throws Exception;
+
+    /**
+     *
+     * @param rd
+     * @param prefix
+     */
+    public void withdrawPrefix(String rd, String prefix) throws Exception;
+
+
     public String getDCGwIP();
 
 }
index 909b82a89d28cd5168c082042ebf369cad240039..6e9a1a5b2eee44a0f4c491dbcb73989533c6f520 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. 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,
@@ -139,6 +139,16 @@ public class BgpManager implements BindingAwareProvider, AutoCloseable, IBgpMana
       bcm.delPrefix(rd, prefix);
     }
 
+    @Override
+    public void advertisePrefix(String rd, String prefix, String nextHop, int vpnLabel) throws Exception {
+        bcm.addPrefix(rd, prefix, nextHop, vpnLabel);
+    }
+
+    @Override
+    public void withdrawPrefix(String rd, String prefix) throws Exception {
+        bcm.delPrefix(rd, prefix);
+    }
+
     public void setQbgpLog(String fileName, String debugLevel) throws Exception {
       bcm.addLogging(fileName, debugLevel);
     }
index 128444c65991b8f57dbcb88593d7c75afda3587e..b9906ada2455bb32e8062d80fd2088bb09802d9f 100644 (file)
@@ -17,6 +17,7 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
@@ -43,6 +44,9 @@ import org.opendaylight.vpnservice.mdsalutil.NwConstants;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.RdToElanOp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnToExtraroute;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
@@ -182,6 +186,17 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
     Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + "has null vpnId!");
 
     Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
+    Long vpnId = vpnInstance.getVpnId();
+    RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, vrfTableKey.getRouteDistinguisher(),
+            vrfEntry.getDestPrefix());
+    if (rdToElanOpEntry!=null) {
+        if (vpnToDpnList!=null) {
+            for (VpnToDpnList curDpn :  vpnToDpnList) {
+                installSubnetRouteInFib(curDpn.getDpnId(), rdToElanOpEntry, vpnId.longValue(), vrfEntry);
+            }
+        }
+        return;
+    }
     BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
               vrfTableKey.getRouteDistinguisher(), vrfEntry);
     if (vpnToDpnList != null) {
@@ -194,6 +209,74 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
     }
   }
 
+  private void installSubnetRouteInFib(BigInteger dpnId, RdToElanOpEntry rdToElanOpEntry,
+                                       long vpnId, VrfEntry vrfEntry){
+      makeSubnetRouteFlow(dpnId);
+      List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+      List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+      Long elanTag = rdToElanOpEntry.getElanTag();
+      instructions.add(new InstructionInfo(InstructionType.write_metadata,  new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
+      instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
+      makeConnectedRoute(dpnId,vpnId,vrfEntry,rdToElanOpEntry.getRd(),
+              instructions,NwConstants.ADD_FLOW);
+      makeLFibTableEntry(dpnId,vrfEntry.getLabel(),instructions,
+              vrfEntry.getNextHopAddress(),NwConstants.ADD_FLOW);
+      // TODO makeTunnelTableEntry();
+  }
+
+  private RdToElanOpEntry getRdToElanOpEntry(DataBroker broker, String rd, String subnetIp) {
+      InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(rd,subnetIp);
+      Optional<RdToElanOpEntry> sn = read(broker, LogicalDatastoreType.OPERATIONAL, id);
+      if(sn.isPresent()) {
+          return sn.get();
+      }
+      return null;
+  }
+
+  private InstanceIdentifier<RdToElanOpEntry> getRdToElanOpEntryDataPath(String rd, String subnetIp) {
+      return InstanceIdentifier.builder(RdToElanOp.class).child(RdToElanOpEntry.class,
+              new RdToElanOpEntryKey(rd,subnetIp)).build();
+  }
+  private  <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
+                                                  InstanceIdentifier<T> path) {
+
+      ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
+
+      Optional<T> result = Optional.absent();
+      try {
+          result = tx.read(datastoreType, path).get();
+      } catch (Exception e) {
+          throw new RuntimeException(e);
+      }
+
+      return result;
+  }
+
+  private void makeSubnetRouteFlow(BigInteger dpnId) {
+      //Ask Vivek cookie
+      final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
+      List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+      List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+      actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
+      instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+      List<MatchInfo> matches = new ArrayList<MatchInfo>();
+      String flowRef = getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
+      FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
+              NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
+
+      LOG.debug("Invoking MDSAL to install Table Miss Entries");
+      mdsalManager.syncInstallFlow(flowEntity,1);
+  }
+
+  private Collection<BigInteger> getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) {
+      Collection<BigInteger> dpns = new HashSet<>();
+      for(VpnToDpnList dpn : vpnInstance.getVpnToDpnList()) {
+          dpns.add(dpn.getDpnId());
+      }
+
+      return dpns;
+  }
+
   public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
     BigInteger localDpnId = BigInteger.ZERO;
     Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
@@ -209,18 +292,26 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
     }
 
     if(localNextHopInfo != null) {
-      localDpnId = localNextHopInfo.getDpnId();
-      long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
-      List<ActionInfo> actionInfos = new ArrayList<ActionInfo>();
+        localDpnId = localNextHopInfo.getDpnId();
+        long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
 
-      actionInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+
+        actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
+        instructions.add(new InstructionInfo(InstructionType.write_actions,actionsInfos));
+        makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
 
-      makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW);
-      makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), groupId, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
+        actionsInfos=new ArrayList<ActionInfo>();;
+        instructions=new ArrayList<InstructionInfo>();
+        actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
+        actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
+        instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+        makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), instructions, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
 
-      LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}", 
-                      localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
-      makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
+        LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
+                localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
+        makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
 
     }
     return localDpnId;
@@ -293,7 +384,7 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
       Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix());
         makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
                            NwConstants.DEL_FLOW);
-        makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), 0 /* invalid */,
+        makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), null /* invalid */,
                            vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
         removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
         deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
@@ -377,6 +468,8 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
                 tunnelId}));
     }
     actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface));
+    List<InstructionInfo> instructions= new ArrayList<InstructionInfo>();
+    instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
 /*
     List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
     if(actionInfos == null) {
@@ -404,35 +497,34 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
                 MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
     }
 **/
-      makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW);
-    LOG.debug(
-        "Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
-  }
-
-    private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
-        InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
-        Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
-        if (dpnInVpn.isPresent()) {
-            List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
-                    .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
-            org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
-                    currVpnInterface = new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder().setInterfaceName(intfName).build();
-
-            if (vpnInterfaces.remove(currVpnInterface)) {
-                if (vpnInterfaces.isEmpty()) {
+      makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
+      LOG.debug("Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
+  }
+
+  private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
+      InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
+      Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+      if (dpnInVpn.isPresent()) {
+          List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
+                  .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
+          org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
+                  currVpnInterface = new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder().setInterfaceName(intfName).build();
+
+          if (vpnInterfaces.remove(currVpnInterface)) {
+              if (vpnInterfaces.isEmpty()) {
                   LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
                   FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
                   cleanUpDpnForVpn(dpnId, vpnId, rd);
-                } else {
+              } else {
                   LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
-                    FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
-                            org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
-                                    .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
-                            new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey(intfName)));
-                }
-            }
-        }
-    }
+                  FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
+                          org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
+                                  .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
+                          new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey(intfName)));
+              }
+          }
+      }
+  }
 
   private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
     /* Get interface info from prefix to interface mapping;
@@ -487,6 +579,24 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
     VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
     Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
     Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
+    RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker,vrfTableKey.getRouteDistinguisher(),
+            vrfEntry.getDestPrefix());
+    if (rdToElanOpEntry != null) {
+        if (vpnToDpnList!=null) {
+            for(VpnToDpnList curDpn :  vpnToDpnList) {
+                makeConnectedRoute(curDpn.getDpnId(),vpnInstance.getVpnId(),vrfEntry,vrfTableKey
+                        .getRouteDistinguisher(), null,NwConstants.DEL_FLOW);
+                makeLFibTableEntry(curDpn.getDpnId(),vrfEntry.getLabel(),null,
+                        vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
+                // TODO DeleteTunnelTableEntry();
+            }
+        }
+        //Delete rd-to-elan-op-entry
+        InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(vrfTableKey.getRouteDistinguisher(),
+                vrfEntry.getDestPrefix());
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,id);
+        return;
+    }
     BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
               vrfTableKey.getRouteDistinguisher(), vrfEntry);
     if (vpnToDpnList != null) {
@@ -535,8 +645,7 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
   }
 
   private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
-                                  List<ActionInfo> actionInfos, int addOrRemove) {
-    LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
+                                  List<InstructionInfo> instructions, int addOrRemove) {    LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
     String values[] = vrfEntry.getDestPrefix().split("/");
     String ipAddress = values[0];
     int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
@@ -558,13 +667,8 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
                               new long[] { 0x0800L }));
 
     if(prefixLength != 0) {
-      matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
-          getIpAddress(destPrefix.getAddress()), prefixLength }));
-    }
-
-    List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
-    if(addOrRemove == NwConstants.ADD_FLOW) {
-      instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
+        matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
+                destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
     }
 
     String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
@@ -588,19 +692,13 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
     }
   }
 
-  private void makeLFibTableEntry(BigInteger dpId, long label, long groupId,
+  private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions,
                                   String nextHop, int addOrRemove) {
     List<MatchInfo> matches = new ArrayList<MatchInfo>();
     matches.add(new MatchInfo(MatchFieldType.eth_type,
                               new long[] { 0x8847L }));
     matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
 
-    List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
-    List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
-    actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
-    actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
-    instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
-
     // Install the flow entry in L3_LFIB_TABLE
     String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
 
@@ -620,7 +718,7 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
     } else {
       mdsalManager.syncRemoveFlow(flowEntity, 1);
     }
-    LOG.debug("LFIB Entry for dpID {} : label : {} group {} modified successfully {}",dpId, label, groupId );
+      LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",dpId, label, instructions );
   }
 
   private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
@@ -640,6 +738,12 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
       Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
       if (vrfTable.isPresent()) {
         for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
+            RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, rd,
+                    vrfEntry.getDestPrefix());
+            if (rdToElanOpEntry!= null) {
+                installSubnetRouteInFib(dpnId, rdToElanOpEntry, vpnId, vrfEntry);
+                continue;
+            }
           // Passing null as we don't know the dpn
           // to which prefix is attached at this point
           createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
index f128c5bc17feb89f272c44dbac87cf0459457d1f..92c084a75deb98b6df51c1247fb4095b975db702 100644 (file)
@@ -301,4 +301,93 @@ module neutronvpn {
         }
     }
 
+    notification subnet-added-to-vpn{
+            description "new subnet added to vpn";
+            leaf subnet-id {
+                type yang:uuid;
+            }
+            leaf subnet-ip {
+                type string;
+            }
+            leaf vpn-name {
+                type string;
+            }
+            leaf external-vpn {
+                type boolean;
+            }
+            leaf elan-tag {
+                type uint32;
+            }
+    }
+
+    notification subnet-deleted-from-vpn{
+            description "subnet deleted from vpn";
+            leaf subnet-id {
+                type yang:uuid;
+            }
+            leaf subnet-ip {
+                type string;
+            }
+            leaf vpn-name {
+                type string;
+            }
+            leaf external-vpn {
+                type boolean;
+            }
+            leaf elan-tag {
+                type uint32;
+            }
+    }
+
+    notification subnet-updated-in-vpn{
+            description "subnet updated in vpn";
+            leaf subnet-id {
+                 type yang:uuid;
+            }
+            leaf subnet-ip {
+                 type string;
+            }
+            leaf vpn-name {
+                 type string;
+            }
+            leaf external-vpn {
+                 type boolean;
+            }
+            leaf elan-tag {
+                type uint32;
+            }
+    }
+
+    notification port-added-to-subnet{
+            description "new port added to subnet";
+            leaf subnet-id{
+                type yang:uuid;
+            }
+            leaf subnet-ip{
+                type string;
+            }
+            leaf port-id{
+                type yang:uuid;
+            }
+            leaf elan-tag {
+                type uint32;
+            }
+    }
+
+    notification port-removed-from-subnet{
+            description "port removed from subnet";
+            leaf subnet-id{
+                type yang:uuid;
+            }
+            leaf subnet-ip{
+                type string;
+            }
+            leaf port-id{
+                type yang:uuid;
+            }
+            leaf elan-tag {
+                type uint32;
+            }
+    }
+
 }
\ No newline at end of file
index 86f904e50b8e6b4ddca9902e7b5cb9a1b22cac47..e8c777e8d28f71bff10a87397352a61bb7d483c7 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. 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,
@@ -47,6 +47,14 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
                         <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-normalized-node-serializer</type>
                         <name>runtime-mapping-singleton</name>
                     </binding-normalized-node-serializer>
+                    <notification-publish-service>
+                        <type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-publish-service</type>
+                        <name>binding-notification-publish-adapter</name>
+                    </notification-publish-service>
+                    <notification-service>
+                        <type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-service</type>
+                        <name>binding-notification-adapter</name>
+                    </notification-service>
                 </module>
             </modules>
             <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
index 0d98bb57da002270273cc6fc5a8f87d25dbe9d17..bc0aa30a9095006a83ac8929d8aba699e290399a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. 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,
@@ -12,6 +12,8 @@ import com.google.common.base.Optional;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
@@ -33,6 +35,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfL2vlanBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.lockmanager.rev150819.LockManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.PortAddedToSubnetBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.PortRemovedFromSubnetBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.neutron.port.data
         .PortFixedipToPortNameBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.Subnetmap;
@@ -52,15 +57,24 @@ public class NeutronPortChangeListener extends AbstractDataChangeListener<Port>
     private ListenerRegistration<DataChangeListener> listenerRegistration;
     private final DataBroker broker;
     private NeutronvpnManager nvpnManager;
+    private LockManagerService lockManager;
+    private NotificationPublishService notificationPublishService;
+    private NotificationService notificationService;
 
 
-    public NeutronPortChangeListener(final DataBroker db, NeutronvpnManager nVpnMgr) {
+    public NeutronPortChangeListener(final DataBroker db, NeutronvpnManager nVpnMgr,NotificationPublishService notiPublishService, NotificationService notiService) {
         super(Port.class);
         broker = db;
         nvpnManager = nVpnMgr;
+        notificationPublishService = notiPublishService;
+        notificationService = notiService;
         registerListener(db);
     }
 
+    public void setLockManager(LockManagerService lockManager) {
+        this.lockManager = lockManager;
+    }
+
     @Override
     public void close() throws Exception {
         if (listenerRegistration != null) {
@@ -245,6 +259,8 @@ public class NeutronPortChangeListener extends AbstractDataChangeListener<Port>
         Uuid vpnId = null;
         Subnetmap subnetmap = null;
         String infName = port.getUuid().getValue();
+        boolean isLockAcquired = false;
+        String lockName = port.getUuid().getValue();
 
         // find the subnet to which this port is associated
         FixedIps ip = port.getFixedIps().get(0);
@@ -260,6 +276,19 @@ public class NeutronPortChangeListener extends AbstractDataChangeListener<Port>
         if (subnetmap != null) {
             vpnId = subnetmap.getVpnId();
         }
+        if(vpnId != null) {
+            try {
+                isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
+                checkAndPublishPortAddNotification(subnetmap.getSubnetIp(), subnetId, port.getUuid());
+                LOG.debug("Port added to subnet notification sent");
+            } catch (Exception e) {
+                LOG.error("Port added to subnet notification failed", e);
+            } finally {
+                if (isLockAcquired) {
+                    NeutronvpnUtils.unlock(lockManager, lockName);
+                }
+            }
+        }
         return vpnId;
     }
 
@@ -267,6 +296,8 @@ public class NeutronPortChangeListener extends AbstractDataChangeListener<Port>
         Uuid subnetId = null;
         Uuid vpnId = null;
         Subnetmap subnetmap = null;
+        boolean isLockAcquired = false;
+        String lockName = port.getUuid().getValue();
 
         // find the subnet to which this port is associated
         FixedIps ip = port.getFixedIps().get(0);
@@ -279,6 +310,43 @@ public class NeutronPortChangeListener extends AbstractDataChangeListener<Port>
         if (subnetmap != null) {
             vpnId = subnetmap.getVpnId();
         }
+        if(vpnId != null) {
+            try {
+                isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
+                checkAndPublishPortRemoveNotification(subnetmap.getSubnetIp(), subnetId, port.getUuid());
+                LOG.debug("Port removed from subnet notification sent");
+            } catch (Exception e) {
+                LOG.error("Port removed from subnet notification failed", e);
+            } finally {
+                if (isLockAcquired) {
+                    NeutronvpnUtils.unlock(lockManager, lockName);
+                }
+            }
+        }
         return vpnId;
     }
+
+    private void checkAndPublishPortAddNotification(String subnetIp, Uuid subnetId, Uuid portId)throws InterruptedException{
+        PortAddedToSubnetBuilder builder = new PortAddedToSubnetBuilder();
+
+        LOG.info("publish notification called");
+
+        builder.setSubnetIp(subnetIp);
+        builder.setSubnetId(subnetId);
+        builder.setPortId(portId);
+
+        notificationPublishService.putNotification(builder.build());
+    }
+
+    private void checkAndPublishPortRemoveNotification(String subnetIp, Uuid subnetId, Uuid portId)throws InterruptedException{
+        PortRemovedFromSubnetBuilder builder = new PortRemovedFromSubnetBuilder();
+
+        LOG.info("publish notification called");
+
+        builder.setPortId(portId);
+        builder.setSubnetIp(subnetIp);
+        builder.setSubnetId(subnetId);
+
+        notificationPublishService.putNotification(builder.build());
+    }
 }
index 52e33d7d85a83e2b7754b3a2d6fa43422b49e52b..201a2f4d35e6cf95f8463e475afbf70ddb683e92 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. 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,
@@ -10,6 +10,8 @@ package org.opendaylight.vpnservice.neutronvpn;
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.SettableFuture;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
@@ -46,33 +48,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInstances;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstanceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.lockmanager.rev150819.LockManagerService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.AssociateNetworksInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.AssociateNetworksOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.AssociateNetworksOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.AssociateRouterInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.CreateL3VPNInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.CreateL3VPNOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.CreateL3VPNOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DeleteL3VPNInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DeleteL3VPNOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DeleteL3VPNOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DissociateNetworksInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DissociateNetworksOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DissociateNetworksOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DissociateRouterInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetFixedIPsForNeutronPortInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602
-        .GetFixedIPsForNeutronPortOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetL3VPNInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetL3VPNInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetL3VPNOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetL3VPNOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.L3vpnInstance;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.Subnetmaps;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.VpnMaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.*;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.createl3vpn.input.L3vpn;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.getl3vpn.output.L3vpnInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.getl3vpn.output
@@ -84,10 +64,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev15
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.vpnmaps.VpnMapBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.vpnmaps.VpnMapKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import java.util.EventListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import java.util.ArrayList;
@@ -96,20 +78,26 @@ import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
-public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
+public class NeutronvpnManager implements NeutronvpnService, AutoCloseable , EventListener{
 
     private static final Logger logger = LoggerFactory.getLogger(NeutronvpnManager.class);
     private final DataBroker broker;
     private LockManagerService lockManager;
     IMdsalApiManager mdsalUtil;
+    private NotificationPublishService notificationPublishService;
+    private NotificationService notificationService;
+    Boolean isExternalVpn;
 
     /**
      * @param db           - dataBroker reference
      * @param mdsalManager - MDSAL Util API access
      */
-    public NeutronvpnManager(final DataBroker db, IMdsalApiManager mdsalManager) {
+    public NeutronvpnManager(final DataBroker db, IMdsalApiManager mdsalManager,NotificationPublishService notiPublishService,
+                             NotificationService notiService) {
         broker = db;
         mdsalUtil = mdsalManager;
+        notificationPublishService = notiPublishService;
+        notificationService = notiService;
     }
 
     public void setLockManager(LockManagerService lockManager) {
@@ -820,6 +808,25 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
     protected void addSubnetToVpn(Uuid vpnId, Uuid subnet) {
         logger.debug("Adding subnet {} to vpn {}", subnet.getValue(), vpnId.getValue());
         Subnetmap sn = updateSubnetNode(subnet, null, null, null, null, vpnId, null);
+        boolean isLockAcquired = false;
+        String lockName = vpnId.getValue() + subnet.getValue();
+        String elanInstanceName = sn.getNetworkId().getValue();
+        InstanceIdentifier<ElanInstance>elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
+        Optional<ElanInstance> elanInstance = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
+        long elanTag = elanInstance.get().getElanTag();
+        if(vpnId.equals(NeutronvpnUtils.getVpnMap(broker,vpnId).getRouterId())){isExternalVpn = false;}
+        else {isExternalVpn = true;}
+        try {
+            isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
+            checkAndPublishSubnetAddNotification(subnet, sn.getSubnetIp(), vpnId.getValue(), isExternalVpn, elanTag);
+            logger.debug("Subnet added to Vpn notification sent");
+        }catch (Exception e){
+            logger.error("Subnet added to Vpn notification failed",e);
+        }finally {
+            if (isLockAcquired) {
+                NeutronvpnUtils.unlock(lockManager, lockName);
+            }
+        }
         // Check if there are ports on this subnet and add corresponding vpn-interfaces
         List<Uuid> portList = sn.getPortList();
         if (portList != null) {
@@ -830,9 +837,26 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
         }
     }
 
-    protected void updateVpnForSubnet(Uuid vpnId, Uuid subnet) {
+    protected void updateVpnForSubnet(Uuid vpnId, Uuid subnet, boolean isBeingAssociated) {
         logger.debug("Updating VPN {} for subnet {}", vpnId.getValue(), subnet.getValue());
         Subnetmap sn = updateSubnetNode(subnet, null, null, null, null, vpnId, null);
+        boolean isLockAcquired = false;
+        String lockName = vpnId.getValue() + subnet.getValue();
+        String elanInstanceName = sn.getNetworkId().getValue();
+        InstanceIdentifier<ElanInstance>elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
+        Optional<ElanInstance> elanInstance = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
+        long elanTag = elanInstance.get().getElanTag();
+        try {
+            isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
+            checkAndPublishSubnetUpdNotification(subnet, sn.getSubnetIp(), vpnId.getValue(), isBeingAssociated, elanTag);
+            logger.debug("Subnet updated in Vpn notification sent");
+        }catch (Exception e){
+            logger.error("Subnet updated in Vpn notification failed",e);
+        }finally {
+            if (isLockAcquired) {
+                NeutronvpnUtils.unlock(lockManager, lockName);
+            }
+        }
         // Check for ports on this subnet and update association of corresponding vpn-interfaces to external vpn
         List<Uuid> portList = sn.getPortList();
         if (portList != null) {
@@ -944,6 +968,25 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
     protected void removeSubnetFromVpn(Uuid vpnId, Uuid subnet) {
         logger.debug("Removing subnet {} from vpn {}", subnet.getValue(), vpnId.getValue());
         Subnetmap sn = NeutronvpnUtils.getSubnetmap(broker, subnet);
+        boolean isLockAcquired = false;
+        String lockName = vpnId.getValue() + subnet.getValue();
+        String elanInstanceName = sn.getNetworkId().getValue();
+        InstanceIdentifier<ElanInstance>elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
+        Optional<ElanInstance> elanInstance = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
+        long elanTag = elanInstance.get().getElanTag();
+        if(vpnId.equals(NeutronvpnUtils.getVpnMap(broker,vpnId).getRouterId())){isExternalVpn = false;}
+        else {isExternalVpn = true;}
+        try {
+            isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
+            checkAndPublishSubnetDelNotification(subnet, sn.getSubnetIp(), vpnId.getValue(), isExternalVpn, elanTag);
+            logger.debug("Subnet removed from Vpn notification sent");
+        }catch (Exception e){
+            logger.error("Subnet removed from Vpn notification failed",e);
+        }finally {
+            if (isLockAcquired) {
+                NeutronvpnUtils.unlock(lockManager, lockName);
+            }
+        }
         if (sn != null) {
             // Check if there are ports on this subnet; remove corresponding vpn-interfaces
             List<Uuid> portList = sn.getPortList();
@@ -967,7 +1010,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
             logger.debug("Updating association of subnets to external vpn {}", vpnId.getValue());
             if (routerSubnets != null) {
                 for (Uuid subnetId : routerSubnets) {
-                    updateVpnForSubnet(vpnId, subnetId);
+                    updateVpnForSubnet(vpnId, subnetId,true);
                 }
             }
         } else {
@@ -984,7 +1027,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
         if (routerSubnets != null) {
             for (Uuid subnetId : routerSubnets) {
                 logger.debug("Updating association of subnets to internal vpn {}", routerId.getValue());
-                updateVpnForSubnet(routerId, subnetId);
+                updateVpnForSubnet(routerId, subnetId,false);
             }
         }
         clearFromVpnMaps(vpnId, routerId, null);
@@ -1412,4 +1455,46 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
         return help.toString();
     }
 
+    private void checkAndPublishSubnetAddNotification(Uuid subnetId, String subnetIp, String vpnName, Boolean isExternalvpn, Long elanTag)throws InterruptedException{
+        SubnetAddedToVpnBuilder builder = new SubnetAddedToVpnBuilder();
+
+        logger.info("publish notification called");
+
+        builder.setSubnetId(subnetId);
+        builder.setSubnetIp(subnetIp);
+        builder.setVpnName(vpnName);
+        builder.setExternalVpn(isExternalvpn);
+        builder.setElanTag(elanTag);
+
+        notificationPublishService.putNotification(builder.build());
+    }
+
+    private void checkAndPublishSubnetDelNotification(Uuid subnetId, String subnetIp, String vpnName, Boolean isExternalvpn, Long elanTag)throws InterruptedException{
+        SubnetDeletedFromVpnBuilder builder = new SubnetDeletedFromVpnBuilder();
+
+        logger.info("publish notification called");
+
+        builder.setSubnetId(subnetId);
+        builder.setSubnetIp(subnetIp);
+        builder.setVpnName(vpnName);
+        builder.setExternalVpn(isExternalvpn);
+        builder.setElanTag(elanTag);
+
+        notificationPublishService.putNotification(builder.build());
+    }
+
+    private void checkAndPublishSubnetUpdNotification(Uuid subnetId, String subnetIp, String vpnName, Boolean isExternalvpn, Long elanTag)throws InterruptedException{
+        SubnetUpdatedInVpnBuilder builder = new SubnetUpdatedInVpnBuilder();
+
+        logger.info("publish notification called");
+
+        builder.setSubnetId(subnetId);
+        builder.setSubnetIp(subnetIp);
+        builder.setVpnName(vpnName);
+        builder.setExternalVpn(isExternalvpn);
+        builder.setElanTag(elanTag);
+
+        notificationPublishService.putNotification(builder.build());
+    }
+
 }
index 5784906e01e97761bba5e2f158ba1b31305e800c..a374e1de30cb5b43f840f359ca7baf39c72924c9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. 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,
@@ -8,6 +8,8 @@
 package org.opendaylight.vpnservice.neutronvpn;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
 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;
@@ -23,6 +25,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.por
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.lockmanager.rev150819.LockManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,9 +46,14 @@ public class NeutronvpnProvider implements BindingAwareProvider, INeutronVpnMana
     private L2GatewayProvider l2GatewayProvider;
     private EntityOwnershipService entityOwnershipService;
     private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
+    private NotificationPublishService notificationPublishService;
+    private NotificationService notificationService;
 
-    public NeutronvpnProvider(RpcProviderRegistry rpcRegistry) {
+    public NeutronvpnProvider(RpcProviderRegistry rpcRegistry,NotificationPublishService notificationPublishService,
+                              NotificationService notificationService) {
         this.rpcProviderRegistry = rpcRegistry;
+        this.notificationPublishService = notificationPublishService;
+        this.notificationService = notificationService;
     }
 
     public RpcProviderRegistry getRpcProviderRegistry() {
@@ -76,14 +84,15 @@ public class NeutronvpnProvider implements BindingAwareProvider, INeutronVpnMana
     public void onSessionInitiated(ProviderContext session) {
         try {
             final DataBroker dbx = session.getSALService(DataBroker.class);
-            nvManager = new NeutronvpnManager(dbx, mdsalManager);
+            nvManager = new NeutronvpnManager(dbx, mdsalManager,notificationPublishService,notificationService);
             final BindingAwareBroker.RpcRegistration<NeutronvpnService> rpcRegistration =
                     getRpcProviderRegistry().addRpcImplementation(NeutronvpnService.class, nvManager);
             bgpvpnListener = new NeutronBgpvpnChangeListener(dbx, nvManager);
             networkListener = new NeutronNetworkChangeListener(dbx, nvManager);
             subnetListener = new NeutronSubnetChangeListener(dbx, nvManager);
             routerListener = new NeutronRouterChangeListener(dbx, nvManager);
-            portListener = new NeutronPortChangeListener(dbx, nvManager);
+            portListener = new NeutronPortChangeListener(dbx, nvManager,notificationPublishService,notificationService);
+            portListener.setLockManager(lockManager);
             nvManager.setLockManager(lockManager);
             l2GatewayProvider = new L2GatewayProvider(dbx, rpcProviderRegistry, entityOwnershipService,
                     bindingNormalizedNodeSerializer);
index 1510b39a4135479ade82b30e992699f324c95727..90198d70a213a238f85e0e3ac0081a0fc2c8e876 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. 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,
@@ -34,7 +34,8 @@ public class NeutronvpnImplModule extends org.opendaylight.yang.gen.v1.urn.opend
     public java.lang.AutoCloseable createInstance() {
         // TODO:implement
         LockManagerService lockManagerService = getRpcRegistryDependency().getRpcService(LockManagerService.class);
-        NeutronvpnProvider provider = new NeutronvpnProvider(getRpcRegistryDependency());
+        NeutronvpnProvider provider = new NeutronvpnProvider(getRpcRegistryDependency(),
+                getNotificationPublishServiceDependency(),getNotificationServiceDependency());
         provider.setMdsalManager(getMdsalutilDependency());
         provider.setLockManager(lockManagerService);
         provider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
index bbf1201cc83749ce0ee318df78bde9ace5376740..33a3b0368c9c02e8f4f2fcf1919e4b6423cb5c3b 100644 (file)
@@ -68,6 +68,23 @@ module neutronvpn-impl {
                     }
                 }
             }
+
+            container notification-publish-service {
+                uses config:service-ref {
+                    refine type {
+                         mandatory true;
+                         config:required-identity md-sal-binding-impl:binding-new-notification-publish-service;
+                    }
+                }
+            }
+            container notification-service {
+                uses config:service-ref {
+                    refine type {
+                         mandatory true;
+                         config:required-identity md-sal-binding-impl:binding-new-notification-service;
+                         }
+                }
+            }
         }
     }
 }
index 93d25bdf59b15a146ba5a795abf8131b7511359e..6857e98ec55b1a2c73624d70f5523b4e06cfda7c 100644 (file)
@@ -4,6 +4,7 @@ module odl-l3vpn {
 
     import yang-ext {prefix ext; revision-date "2013-07-09";}
     import l3vpn { prefix l3vpn; revision-date "2014-08-15"; }
+    import ietf-yang-types { prefix "yang"; }
 
     revision "2013-09-11" {
         description "L3 VPN Service module";
@@ -125,4 +126,112 @@ module odl-l3vpn {
         }
     }
 
+    typedef task-state {
+         type enumeration {
+           enum na {
+             value "0";
+             description
+              "Task not applicable";
+           }
+           enum pending {
+             value "1";
+             description
+              "Task is in pending state";
+           }
+           enum done {
+             value "2";
+             description
+              "Task has been completed";
+           }
+         }
+         description
+          "This value the status of any task.
+           The possible values are NA, PENDING or DONE.
+           ";
+    }
+
+
+    container subnet-op-data {
+        list subnet-op-data-entry {
+            key subnet-id;
+            leaf subnet-id {
+                type    yang:uuid;
+                description "UUID representing the subnet ";
+            }
+            leaf nh-dpnId {
+                type uint64;
+                description "DpnId for the DPN used as nexthop for this subnet";
+            }
+            leaf vpn-name {
+                type string;
+                description "VPN Instance name";
+            }
+            leaf vrf-id {
+                type string;
+            }
+            leaf subnet-cidr {
+                type string;
+                description "Subnet in cidr notation";
+            }
+            leaf route-adv-state {
+                type task-state;
+                description "The status of the subnet route advertisement. Route advertisement could be in a NA, PENDING or DONE state.";
+            }
+            leaf elan-tag{
+                type uint32;
+            }
+            list subnet-to-dpn {
+                key dpnId;
+                leaf dpnId {
+                    type uint64;
+                }
+                list vpn-interfaces {
+                    key interface-name;
+                    leaf interface-name {
+                        type string;
+                    }
+                }
+            }
+
+        }
+    }
+
+    container port-op-data {
+        list port-op-data-entry {
+            key port-id;
+            leaf port-id {
+                type  string;
+                description "UUID in string format representing the port ";
+            }
+            leaf subnet-id {
+                type  yang:uuid;
+                description "Back reference to obtain the subnet for a port ";
+            }
+            leaf dpnId {
+                type uint64;
+            }
+        }
+    }
+
+    container rd-to-elan-op{
+        list rd-to-elan-op-entry{
+            key "rd subnet-ip";
+            leaf rd {
+                type string;
+            }
+            leaf subnet-ip {
+                type string;
+            }
+            leaf next-hop-ip {
+                type string;
+            }
+            leaf vpn-name {
+                type string;
+            }
+            leaf elan-tag{
+                type uint32;
+            }
+        }
+    }
+
 }
\ No newline at end of file
index 6ef028d02559ebe0daa457d5841cae39cc439575..43936df9093374139acdbc173c7ce3d4ac6d6920 100644 (file)
@@ -61,6 +61,16 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>arputil-api</artifactId>
       <version>${vpnservices.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.vpnservice</groupId>
+      <artifactId>neutronvpn-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.vpnservice</groupId>
+      <artifactId>elanmanager-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-binding-broker-impl</artifactId>
index de1f4aac3278d60214e89e682a4938e110ee2884..5e6cc303cd61fefa48cfdd898175cedc1def958c 100644 (file)
@@ -85,6 +85,7 @@ public class InterfaceStateChangeListener extends AbstractDataChangeListener<Int
           }
         } else {
           vpnInterfaceManager.processVpnInterfaceUp(dpnId, interfaceName, intrf.getIfIndex());
+          vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceUp(intrf);
         }
       } catch (Exception e) {
         LOG.error("Exception caught in Interface Operational State Up event", e);
@@ -110,6 +111,7 @@ public class InterfaceStateChangeListener extends AbstractDataChangeListener<Int
         } else {
           if (VpnUtil.isVpnInterfaceConfigured(broker, interfaceName)) {
             vpnInterfaceManager.processVpnInterfaceDown(dpId, interfaceName, intrf.getIfIndex(), true);
+            vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceDown(intrf);
           }
         }
       } catch (Exception e) {
@@ -131,9 +133,11 @@ public class InterfaceStateChangeListener extends AbstractDataChangeListener<Int
         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);
+                    vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceUp(update);
         } else if(update.getOperStatus().equals(Interface.OperStatus.Down)) {
           //withdraw all prefixes in all vpns for this dpn from bgp
           // vpnInterfaceManager.updatePrefixesForDPN(dpnId, VpnInterfaceManager.UpdateRouteAction.WITHDRAW_ROUTE);
+                   vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceDown(update);
         }*/
       }
 
diff --git a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/SubnetOpDpnManager.java b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/SubnetOpDpnManager.java
new file mode 100644 (file)
index 0000000..9ec7585
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.port.op.data.PortOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.port.op.data.PortOpDataEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.subnet.to.dpn.VpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.subnet.to.dpn.VpnInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.subnet.to.dpn.VpnInterfacesKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PortOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.SubnetOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpnBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpnKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.math.BigInteger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+
+public class SubnetOpDpnManager {
+    private static final Logger logger = LoggerFactory.getLogger(SubnetOpDpnManager.class);
+
+    private final DataBroker broker;
+
+    public SubnetOpDpnManager(final DataBroker db) {
+        broker = db;
+    }
+
+    private SubnetToDpn addDpnToSubnet(Uuid subnetId, BigInteger dpnId) {
+        SubnetToDpn subDpn = null;
+        try {
+            InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+                    child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+            InstanceIdentifier<SubnetToDpn> dpnOpId = subOpIdentifier.child(SubnetToDpn.class, new SubnetToDpnKey(dpnId));
+            Optional<SubnetToDpn> optionalSubDpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId);
+            if (optionalSubDpn.isPresent()) {
+                logger.error("Cannot create, SubnetToDpn for subnet " + subnetId.getValue() +
+                        " as DPN " + dpnId + " already seen in datastore");
+                return null;
+            }
+            SubnetToDpnBuilder subDpnBuilder = new SubnetToDpnBuilder().setKey(new SubnetToDpnKey(dpnId));
+            List<VpnInterfaces> vpnIntfList = new ArrayList<VpnInterfaces>();
+            subDpnBuilder.setVpnInterfaces(vpnIntfList);
+            subDpn = subDpnBuilder.build();
+            logger.trace("Creating SubnetToDpn entry for subnet  " + subnetId.getValue() + " with DPNId "+ dpnId);
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId, subDpn);
+        } catch (Exception ex) {
+            logger.error("Creation of SubnetToDpn for subnet " +
+                    subnetId.getValue() + " with DpnId " + dpnId + " failed {}" + ex);
+            return null;
+        } finally {
+        }
+        return subDpn;
+    }
+
+    private void removeDpnFromSubnet(Uuid subnetId, BigInteger dpnId) {
+        try {
+            InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+                    child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+            InstanceIdentifier<SubnetToDpn> dpnOpId =subOpIdentifier.child(SubnetToDpn.class, new SubnetToDpnKey(dpnId));
+            Optional<SubnetToDpn> optionalSubDpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId);
+            if (!optionalSubDpn.isPresent()) {
+                logger.warn("Cannot delete, SubnetToDpn for subnet " + subnetId.getValue() +
+                        " DPN " + dpnId + " not available in datastore");
+                return;
+            }
+            logger.trace("Deleting SubnetToDpn entry for subnet  " + subnetId.getValue() + " with DPNId "+ dpnId);
+            MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId);
+        } catch (Exception ex) {
+            logger.error("Deletion of SubnetToDpn for subnet " +
+                    subnetId.getValue() + " with DPN " + dpnId + " failed {}" + ex);
+        } finally {
+        }
+    }
+
+    public SubnetToDpn addInterfaceToDpn(Uuid subnetId, BigInteger dpnId, String intfName) {
+        SubnetToDpn subDpn = null;
+        try {
+            // Create and add SubnetOpDataEntry object for this subnet to the SubnetOpData container
+            InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+                    child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+            //Please use a synchronize block here as we donot need a cluster-wide lock
+            InstanceIdentifier<SubnetToDpn> dpnOpId = subOpIdentifier.child(SubnetToDpn.class, new SubnetToDpnKey(dpnId));
+            Optional<SubnetToDpn> optionalSubDpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId);
+            if (!optionalSubDpn.isPresent()) {
+                // Create a new DPN Entry
+                subDpn = addDpnToSubnet(subnetId, dpnId);
+            } else {
+                subDpn = optionalSubDpn.get();
+            }
+            SubnetToDpnBuilder subDpnBuilder = new SubnetToDpnBuilder(subDpn);
+            List<VpnInterfaces> vpnIntfList = subDpnBuilder.getVpnInterfaces();
+            VpnInterfaces vpnIntfs = new VpnInterfacesBuilder().setKey(new VpnInterfacesKey(intfName)).setInterfaceName(intfName).build();
+            vpnIntfList.add(vpnIntfs);
+            subDpnBuilder.setVpnInterfaces(vpnIntfList);
+            subDpn = subDpnBuilder.build();
+
+            logger.trace("Creating SubnetToDpn entry for subnet  " + subnetId.getValue() + " with DPNId "+ dpnId);
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId, subDpn);
+        } catch (Exception ex) {
+            logger.error("Addition of Interface " + intfName + " for SubnetToDpn on subnet " +
+                    subnetId.getValue() + " with DPN " + dpnId + " failed {}" + ex);
+            return null;
+        } finally {
+        }
+        return subDpn;
+    }
+
+    public void addPortOpDataEntry(String intfName, Uuid subnetId, BigInteger dpnId)  {
+        try {
+            // Add to PortOpData as well.
+            PortOpDataEntryBuilder portOpBuilder = null;
+            PortOpDataEntry portOpEntry = null;
+
+            InstanceIdentifier<PortOpDataEntry> portOpIdentifier = InstanceIdentifier.builder(PortOpData.class).
+                    child(PortOpDataEntry.class, new PortOpDataEntryKey(intfName)).build();
+            Optional<PortOpDataEntry> optionalPortOp = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
+            if (!optionalPortOp.isPresent()) {
+                // Create PortOpDataEntry only if not present
+                portOpBuilder = new PortOpDataEntryBuilder().setKey(new PortOpDataEntryKey(intfName)).setPortId(intfName);
+                portOpBuilder.setSubnetId(subnetId);
+                portOpBuilder.setDpnId(dpnId);
+                portOpEntry = portOpBuilder.build();
+            } else {
+                portOpBuilder = new PortOpDataEntryBuilder(optionalPortOp.get());
+                portOpBuilder.setSubnetId(subnetId);
+                portOpBuilder.setDpnId(dpnId);
+                portOpEntry = portOpBuilder.build();
+            }
+            logger.trace("Creating PortOpData entry for port " + intfName + " with DPNId "+ dpnId);
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier, portOpEntry);
+        } catch (Exception ex) {
+            logger.error("Addition of Interface " + intfName + " for SubnetToDpn on subnet " +
+                    subnetId.getValue() + " with DPN " + dpnId + " failed {}" + ex);
+        } finally {
+        }
+    }
+
+    public boolean removeInterfaceFromDpn(Uuid subnetId, BigInteger dpnId, String intfName) {
+        boolean dpnRemoved = false;
+        try {
+            InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+                    child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+            InstanceIdentifier<SubnetToDpn> dpnOpId = subOpIdentifier.child(SubnetToDpn.class, new SubnetToDpnKey(dpnId));
+            Optional<SubnetToDpn> optionalSubDpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId);
+            if (!optionalSubDpn.isPresent()) {
+                logger.warn("Cannot delete, SubnetToDpn for subnet " + subnetId.getValue() +
+                        " DPN " + dpnId + " not available in datastore");
+                return false;
+            }
+
+            SubnetToDpnBuilder subDpnBuilder = new SubnetToDpnBuilder(optionalSubDpn.get());
+            List<VpnInterfaces> vpnIntfList = subDpnBuilder.getVpnInterfaces();
+            VpnInterfaces vpnIntfs = new VpnInterfacesBuilder().setKey(new VpnInterfacesKey(intfName)).setInterfaceName(intfName).build();
+            vpnIntfList.remove(vpnIntfs);
+            if (vpnIntfList.isEmpty()) {
+                // Remove the DPN as well
+                removeDpnFromSubnet(subnetId, dpnId);
+                dpnRemoved = true;
+            } else {
+                subDpnBuilder.setVpnInterfaces(vpnIntfList);
+                MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId, subDpnBuilder.build());
+            }
+        } catch (Exception ex) {
+            logger.error("Deletion of Interface " + intfName + " for SubnetToDpn on subnet " +
+                    subnetId.getValue() + " with DPN " + dpnId + " failed {}" + ex);
+            return false;
+        } finally {
+        }
+        return dpnRemoved;
+    }
+
+    public PortOpDataEntry removePortOpDataEntry(String intfName) {
+        // Remove PortOpData and return out
+        InstanceIdentifier<PortOpDataEntry> portOpIdentifier = InstanceIdentifier.builder(PortOpData.class).
+                child(PortOpDataEntry.class, new PortOpDataEntryKey(intfName)).build();
+        PortOpDataEntry portOpEntry = null;
+        Optional<PortOpDataEntry> optionalPortOp = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
+        if (!optionalPortOp.isPresent()) {
+            logger.error("Cannot delete, portOp for port " + intfName +
+                    " is not available in datastore");
+            return null;
+        } else {
+            portOpEntry = optionalPortOp.get();
+            logger.trace("Deleting portOpData entry for port " + intfName);
+            MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
+        }
+        return portOpEntry;
+    }
+
+    public PortOpDataEntry getPortOpDataEntry(String intfName) {
+        // Remove PortOpData and return out
+        InstanceIdentifier<PortOpDataEntry> portOpIdentifier = InstanceIdentifier.builder(PortOpData.class).
+                child(PortOpDataEntry.class, new PortOpDataEntryKey(intfName)).build();
+        Optional<PortOpDataEntry> optionalPortOp = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
+        if (!optionalPortOp.isPresent()) {
+            logger.error("Cannot get, portOp for port " + intfName +
+                    " is not available in datastore");
+            return null;
+        }
+        return optionalPortOp.get();
+    }
+
+}
diff --git a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/SubnetRoutePacketInHandler.java b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/SubnetRoutePacketInHandler.java
new file mode 100644 (file)
index 0000000..de7a5cc
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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;
+
+import com.google.common.base.Optional;
+import com.google.common.primitives.Ints;
+import org.opendaylight.controller.liblldp.EtherTypes;
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.SubnetOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NetworkMaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.networkmaps.NetworkMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.networkmaps.NetworkMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagName;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.vpnservice.mdsalutil.packet.ARP;
+import org.opendaylight.vpnservice.mdsalutil.packet.IPv4;
+import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.controller.liblldp.Packet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.nio.charset.StandardCharsets;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+
+public class SubnetRoutePacketInHandler implements PacketProcessingListener {
+
+    private static final Logger s_logger = LoggerFactory.getLogger(SubnetRoutePacketInHandler.class);
+    private final DataBroker broker;
+    private PacketProcessingService packetService;
+    private VpnInterfaceManager ifManager;
+    private IdManagerService idManager;
+    //List maintains info about the arp request sent - id src+dst ip
+    private ArrayList<String> arpList = new ArrayList();
+
+    public SubnetRoutePacketInHandler(DataBroker dataBroker, IdManagerService idManager) {
+        broker = dataBroker;
+        this.idManager = idManager;
+    }
+
+    public void onPacketReceived(PacketReceived notification) {
+
+        s_logger.debug("SubnetRoutePacketInHandler: PacketReceived invoked...");
+
+        short tableId = notification.getTableId().getValue();
+        byte[] data = notification.getPayload();
+        BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
+        Ethernet res = new Ethernet();
+
+        if (notification.getPacketInReason() == SendToController.class) { /*&& tableId == VpnConstants.FIB_TABLE) {*/
+            try {
+                s_logger.debug("SubnetRoutePacketInHandler: Some packet received");
+                res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
+                Packet pkt = res.getPayload();
+                if (pkt instanceof IPv4) {
+                    IPv4 ipv4 = (IPv4) pkt;
+                    byte[] srcMac = res.getSourceMACAddress();
+                    byte[] dstMac = res.getDestinationMACAddress();
+                    byte[] srcIp = Ints.toByteArray(ipv4.getSourceAddress());
+                    byte[] dstIp = Ints.toByteArray(ipv4.getDestinationAddress());
+                    String dstIpStr = toStringIpAddress(dstIp);
+                    String srcIpStr = toStringIpAddress(srcIp);
+                    if (VpnUtil.getNeutronPortNamefromPortFixedIp(broker, dstIpStr) != null) {
+                        s_logger.debug("SubnetRoutePacketInHandler: IPv4 Packet received with "
+                                + "Target IP {} is a valid Neutron port, ignoring subnet route processing", dstIpStr);
+                        return;
+                    }
+                    long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
+                    s_logger.debug("SubnetRoutePacketInHandler: Elan Tag obtained as {}" , elanTag);
+                    if (elanTag == 0) {
+                        s_logger.error("SubnetRoutePacketInHandler: elanTag value from metadata found to be 0, for IPv4 " +
+                                "Packet received with Target IP {}", dstIpStr);
+                        return;
+                    }
+                    s_logger.info("SubnetRoutePacketInHandler: Processing IPv4 Packet received with Source IP {} "
+                            + "and Target IP {}", srcIpStr, dstIpStr);
+                    BigInteger dpnId = getTargetDpnForPacketOut(broker, elanTag,  ipv4.getDestinationAddress());
+                    //Handle subnet routes ip requests
+                    if (dpnId != BigInteger.ZERO) {
+                        long groupid = VpnUtil.getRemoteBCGroup(elanTag);
+                        String key = srcIpStr + dstIpStr;
+                        sendArpRequest(dpnId, groupid, srcMac, srcIp, dstIp);
+                        arpList.add(key);
+                    }
+                    return;
+                }
+
+                if (pkt instanceof ARP) {
+                    s_logger.debug("SubnetRoutePacketInHandler: ARP packet received");
+                    ARP arpPacket = (ARP) pkt;
+                    boolean arpReply = (arpPacket.getOpCode() == 2) ? true : false;
+                    if (arpReply) {
+                        //Handle subnet routes arp responses
+                        s_logger.debug("SubnetRoutePacketInHandler: ARP reply received");
+                        byte[] respSrc = arpPacket.getSenderProtocolAddress();
+                        byte[] respDst = arpPacket.getTargetProtocolAddress();
+                        String respIp = toStringIpAddress(respSrc);
+                        String check = toStringIpAddress(respDst) + respIp;
+                        if (arpList.contains(check)) {
+                            s_logger.debug("SubnetRoutePacketInHandler: ARP reply received for listening target IP " + respIp);
+                            String destination = VpnUtil.getIpPrefix(respIp);
+                            long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
+                            s_logger.debug("SubnetRoutePacketInHandler Lport Tag of arp replier " + portTag);
+                            IfIndexInterface interfaceInfo = VpnUtil.getInterfaceInfoByInterfaceTag(broker, portTag);
+                            String ifName = interfaceInfo.getInterfaceName();
+                            InstanceIdentifier<VpnInterface> vpnIfIdentifier = VpnUtil.getVpnInterfaceIdentifier(ifName);
+                            VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, ifName);
+
+                            //Get VPN interface adjacencies
+                            if (vpnInterface != null) {
+                                InstanceIdentifier<Adjacencies> path = vpnIfIdentifier.augmentation(Adjacencies.class);
+                                Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
+                                String nextHopIpAddr = null;
+                                String nextHopMacAddress = null;
+                                if (adjacencies.isPresent()) {
+                                    List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
+                                    for (Adjacency adjacs : adjacencyList) {
+                                        if (adjacs.getMacAddress() != null && !adjacs.getMacAddress().isEmpty()) {
+                                            nextHopIpAddr = adjacs.getIpAddress();
+                                            nextHopMacAddress = adjacs.getMacAddress();
+                                            break;
+                                        }
+                                    }
+                                    if (nextHopMacAddress != null && destination != null) {
+                                        String rd = VpnUtil.getVpnRd(broker, vpnInterface.getVpnInstanceName());
+                                        long label =
+                                                VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
+                                                        VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnInterface.getVpnInstanceName(), destination));
+                                        String nextHopIp = nextHopIpAddr.split("/")[0];
+                                        Adjacency newAdj = new AdjacencyBuilder().setIpAddress(destination).setKey
+                                                (new AdjacencyKey(destination)).setNextHopIp(nextHopIp).build();
+                                        adjacencyList.add(newAdj);
+                                        Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
+                                        VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface.getName())).
+                                                setName(vpnInterface.getName()).setVpnInstanceName(vpnInterface.getVpnInstanceName()).
+                                                addAugmentation(Adjacencies.class, aug).build();
+                                        VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, newVpnIntf);
+                                        s_logger.debug("SubnetRoutePacketInHandler: Successfully stored subnetroute Adjacency into VpnInterface {}", newVpnIntf);
+                                    }
+                                }
+                            }
+                            //Remove from list once response was processed
+                            arpList.remove(check);
+                        }
+                    }
+                }
+            } catch (Exception ex) {
+                //Failed to decode packet
+                s_logger.error("SubnetRoutePacketInHandler: Failed to handle subnetroute packets {}", ex);
+            }
+        }
+    }
+
+    private static BigInteger getTargetDpnForPacketOut(DataBroker broker, long elanTag, int ipAddress) {
+        BigInteger dpnid = BigInteger.ZERO;
+        ElanTagName elanInfo = VpnUtil.getElanInfoByElanTag(broker, elanTag);
+        if (elanInfo == null) {
+            s_logger.trace("SubnetRoutePacketInHandler: Unable to retrieve ElanInfo for elanTag {}", elanTag);
+            return dpnid;
+        }
+        InstanceIdentifier<NetworkMap> networkId = InstanceIdentifier.builder(NetworkMaps.class)
+                .child(NetworkMap.class, new NetworkMapKey(new Uuid(elanInfo.getName()))).build();
+        s_logger.trace("SubnetRoutePacketInHandler: Obtained target ip address as " + ipAddress);
+        s_logger.trace("SubnetRoutePacketInHandler: Obtained elanTag as " + elanTag);
+        s_logger.trace("SubnetRoutePacketInHandler: Obtained elanInfo as " + elanInfo);
+        s_logger.trace("SubnetRoutePacketInHandler: Obtained network name as " + elanInfo.getName());
+
+        Optional<NetworkMap> optionalNetworkMap = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, networkId);
+        if (optionalNetworkMap.isPresent()) {
+            List<Uuid> subnetList = optionalNetworkMap.get().getSubnetIdList();
+            s_logger.trace("SubnetRoutePacketInHandler: Obtained subnetList as " + subnetList);
+            for (Uuid subnetId : subnetList) {
+                InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+                        child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+                Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+                        subOpIdentifier);
+                if (!optionalSubs.isPresent()) {
+                    continue;
+                }
+                s_logger.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId.getValue());
+                SubnetOpDataEntry subOpEntry = optionalSubs.get();
+                if (subOpEntry.getNhDpnId() != null) {
+                    boolean match = VpnUtil.isIpInSubnet(ipAddress, subOpEntry.getSubnetCidr());
+                    s_logger.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId + " matching " + match);
+                    if (match) {
+                        dpnid = subOpEntry.getNhDpnId();
+                        return dpnid;
+                    }
+                }
+            }
+        }
+        return dpnid;
+    }
+
+    private static String toStringIpAddress(byte[] ipAddress)
+    {
+        String ip = null;
+        if (ipAddress == null) {
+            return ip;
+        }
+
+        try {
+            ip = InetAddress.getByAddress(ipAddress).getHostAddress();
+        } catch(UnknownHostException e) {
+            s_logger.error("SubnetRoutePacketInHandler: Unable to translate byt[] ipAddress to String {}", e);
+        }
+
+        return ip;
+    }
+
+    public void setPacketProcessingService(PacketProcessingService service) {
+        this.packetService = service;
+    }
+
+    private long getDpnIdFromPktRcved(PacketReceived packet) {
+        InstanceIdentifier<?> identifier = packet.getIngress().getValue();
+        NodeId id = identifier.firstKeyOf(Node.class, NodeKey.class).getId();
+        return getDpnIdFromNodeName(id.getValue());
+    }
+
+    private long getDpnIdFromNodeName(String nodeName) {
+        String dpId = nodeName.substring(nodeName.lastIndexOf(":") + 1);
+        return Long.parseLong(dpId);
+    }
+
+    private void sendArpRequest(BigInteger dpnId, long groupId, byte[] abySenderMAC, byte[] abySenderIpAddress,
+                                byte[] abyTargetIpAddress) {
+
+        s_logger.info("SubnetRoutePacketInHandler: sendArpRequest dpnId {}, groupId {}, senderMAC {}, senderIPAddress {}, targetIPAddress {}",
+                dpnId, groupId,new String(abySenderMAC, StandardCharsets.UTF_8),
+                toStringIpAddress(abySenderIpAddress),toStringIpAddress(abyTargetIpAddress));
+        if (abySenderIpAddress != null) {
+            byte[] arpPacket;
+            byte[] ethPacket;
+            List<ActionInfo> lstActionInfo;
+            TransmitPacketInput transmitPacketInput;
+
+            arpPacket = createARPPacket(ARP.REQUEST, abySenderMAC, abySenderIpAddress, VpnConstants.MAC_Broadcast,
+                    abyTargetIpAddress);
+            ethPacket = createEthernetPacket(abySenderMAC, VpnConstants.EthernetDestination_Broadcast, arpPacket);
+            lstActionInfo = new ArrayList<ActionInfo>();
+            lstActionInfo.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
+            transmitPacketInput = MDSALUtil.getPacketOutDefault(lstActionInfo, ethPacket, dpnId);
+            packetService.transmitPacket(transmitPacketInput);
+        } else {
+            s_logger.info("SubnetRoutePacketInHandler: Unable to send ARP request because client port has no IP  ");
+        }
+    }
+
+    private static byte[] createARPPacket(short opCode, byte[] senderMacAddress, byte[] senderIP, byte[] targetMacAddress,
+                                          byte[] targetIP) {
+        ARP arp = new ARP();
+        byte[] rawArpPkt = null;
+        try {
+            arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
+            arp.setProtocolType(EtherTypes.IPv4.shortValue());
+            arp.setHardwareAddressLength((byte) 6);
+            arp.setProtocolAddressLength((byte) 4);
+            arp.setOpCode(opCode);
+            arp.setSenderHardwareAddress(senderMacAddress);
+            arp.setSenderProtocolAddress(senderIP);
+            arp.setTargetHardwareAddress(targetMacAddress);
+            arp.setTargetProtocolAddress(targetIP);
+            rawArpPkt = arp.serialize();
+        } catch (Exception ex) {
+            s_logger.error("VPNUtil:  Serialized ARP packet with senderMacAddress {} senderIp {} targetIP {} exception {}",
+                    senderMacAddress, senderIP, targetIP, ex);
+        }
+
+        return rawArpPkt;
+    }
+
+    private static byte[] createEthernetPacket(byte[] sourceMAC, byte[] targetMAC, byte[] arp) {
+        Ethernet ethernet = new Ethernet();
+        byte[] rawEthPkt = null;
+        try {
+            ethernet.setSourceMACAddress(sourceMAC);
+            ethernet.setDestinationMACAddress(targetMAC);
+            ethernet.setEtherType(EtherTypes.ARP.shortValue());
+            ethernet.setRawPayload(arp);
+            rawEthPkt = ethernet.serialize();
+        } catch (Exception ex) {
+            s_logger.error("VPNUtil:  Serialized Ethernet packet with sourceMacAddress {} targetMacAddress {} exception {}",
+                    sourceMAC, targetMAC, ex);
+        }
+        return rawEthPkt;
+    }
+}
index 862a6c49c24a83f3d301f445ce0e7ad246b43f16..62d6db72e2992a5d59c6c744d6d6a73470e1dfc2 100644 (file)
@@ -22,4 +22,11 @@ public class VpnConstants {
     public static final BigInteger COOKIE_L3_BASE = new BigInteger("8000000", 16);
     public static final String FLOWID_PREFIX = "L3.";
     public static final long WAIT_TIME_IN_MILLISECONDS = 5000;
+    public static final int ELAN_GID_MIN = 200000;
+    public static final short ELAN_SMAC_TABLE = 50;
+    public static final short FIB_TABLE = 21;
+    public static byte[] EthernetDestination_Broadcast = new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF };
+    public static byte[] MAC_Broadcast = new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 };
+
 }
index b33fea8d226418e66572bde08f04bed564c31d7a..2a9a96138aa8c6a3fb5689531fa7fe1f81452fa8 100644 (file)
@@ -16,6 +16,7 @@ import com.google.common.util.concurrent.JdkFutureAdapters;
 import org.opendaylight.controller.md.sal.binding.api.*;
 import org.opendaylight.vpnservice.mdsalutil.*;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
@@ -48,6 +49,7 @@ import java.util.concurrent.*;
 
 import com.google.common.base.Optional;
 
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
 import org.opendaylight.bgpmanager.api.IBgpManager;
 import org.opendaylight.fibmanager.api.IFibManager;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
@@ -87,6 +89,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     private ItmRpcService itmProvider;
     private IdManagerService idManager;
     private OdlArputilService arpManager;
+    private NeutronvpnService neuService;
+    private VpnSubnetRouteHandler vpnSubnetRouteHandler;
     private InterfaceStateChangeListener interfaceListener;
     private VpnInterfaceOpListener vpnInterfaceOpListener;
     private ArpNotificationHandler arpNotificationHandler;
@@ -107,6 +111,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         vpnInterfaceOpListener = new VpnInterfaceOpListener();
         arpNotificationHandler = new ArpNotificationHandler(this, broker);
         notificationService.registerNotificationListener(arpNotificationHandler);
+        vpnSubnetRouteHandler = new VpnSubnetRouteHandler(broker, bgpManager, this);
+        notificationService.registerNotificationListener(vpnSubnetRouteHandler);
         registerListener(db);
     }
 
@@ -129,12 +135,19 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 
     public void setIdManager(IdManagerService idManager) {
         this.idManager = idManager;
+        vpnSubnetRouteHandler.setIdManager(idManager);
     }
 
     public void setArpManager(OdlArputilService arpManager) {
         this.arpManager = arpManager;
     }
 
+    public void setNeutronvpnManager(NeutronvpnService neuService) { this.neuService = neuService; }
+
+    public VpnSubnetRouteHandler getVpnSubnetRouteHandler() {
+        return this.vpnSubnetRouteHandler;
+    }
+
     @Override
     public void close() throws Exception {
         if (listenerRegistration != null) {
@@ -249,6 +262,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                           InterfaceUtils.buildServiceId(vpnInterfaceName, VpnConstants.L3VPN_SERVICE_IDENTIFIER), serviceInfo);
         makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
                     vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW);
+        makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
+                vpnId, ArpReplyOrRequest.REPLY, NwConstants.ADD_FLOW);
 
     }
 
@@ -536,6 +551,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
         makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
                     vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW);
+        makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
+                vpnId, ArpReplyOrRequest.REPLY, NwConstants.DEL_FLOW);
     }
 
 
@@ -749,12 +766,11 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 (rd != null) ? rd : routerID, destination),
             VpnUtil.getVpnToExtraroute(destination, nextHop));
 
-        if(intfName != null && !intfName.isEmpty()) {
+        if (intfName != null && !intfName.isEmpty()) {
             BigInteger dpnId = InterfaceUtils.getDpnForInterface(interfaceManager, intfName);
             String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
-            if (nextHopIp == null && !nextHopIp.isEmpty()) {
-                LOG.error("NextHop for interface {} is null. Adding extra route {} without nextHop", intfName,
-                        destination);
+            if (nextHopIp == null || nextHopIp.isEmpty()) {
+                LOG.warn("NextHop for interface {} is null / empty. Failed advertising extra route for prefix {}", intfName, destination);
             }
             nextHop = nextHopIp;
         }
index 7c9a403957c0ff2dd6df05d1b88d9c65109416ab..88c73c2de8b7d68a6522dd2517175a62e712b8b7 100644 (file)
@@ -16,6 +16,7 @@ import com.google.common.util.concurrent.CheckedFuture;
 import org.opendaylight.bgpmanager.api.IBgpManager;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
@@ -63,6 +64,7 @@ public class VpnManager extends AbstractDataChangeListener<VpnInstance> implemen
     private VpnInterfaceManager vpnInterfaceManager;
     private final FibEntriesListener fibListener;
     private final VpnInstanceOpListener vpnInstOpListener;
+    private NotificationService notificationService;
 
     private static final FutureCallback<Void> DEFAULT_CALLBACK =
             new FutureCallback<Void>() {
diff --git a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnSubnetRouteHandler.java b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnSubnetRouteHandler.java
new file mode 100644 (file)
index 0000000..9e3ba8f
--- /dev/null
@@ -0,0 +1,730 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.bgpmanager.api.IBgpManager;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.utilities.InterfaceUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.port.op.data.PortOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.Subnetmap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.subnet.to.dpn.VpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.math.BigInteger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+
+public class VpnSubnetRouteHandler implements NeutronvpnListener {
+    private static final Logger logger = LoggerFactory.getLogger(VpnSubnetRouteHandler.class);
+
+    private final DataBroker broker;
+    private SubnetOpDpnManager subOpDpnManager;
+    private final IBgpManager bgpManager;
+    private IdManagerService idManager;
+    private VpnInterfaceManager vpnInterfaceManager;
+
+    public VpnSubnetRouteHandler(final DataBroker db, IBgpManager bgpManager, VpnInterfaceManager vpnIntfManager) {
+        broker = db;
+        subOpDpnManager = new SubnetOpDpnManager(broker);
+        this.bgpManager = bgpManager;
+        this.vpnInterfaceManager = vpnIntfManager;
+    }
+
+    public void setIdManager(IdManagerService idManager) {
+        this.idManager = idManager;
+    }
+
+    @Override
+    public void onSubnetAddedToVpn(SubnetAddedToVpn notification) {
+        if (!notification.isExternalVpn()) {
+            return;
+        }
+
+        Uuid subnetId = notification.getSubnetId();
+        String vpnName = notification.getVpnName();
+        String subnetIp = notification.getSubnetIp();
+        Long elanTag = notification.getElanTag();
+
+        Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
+        Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
+        Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!");
+        Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!");
+
+        logger.info("onSubnetAddedToVpn: Subnet" + subnetId.getValue() + " being added to vpn");
+        //TODO(vivek): Change this to use more granularized lock at subnetId level
+        synchronized (this) {
+            try {
+                //Create and add SubnetOpDataEntry object for this subnet to the SubnetOpData container
+                InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+                        child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+                Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker,
+                        LogicalDatastoreType.OPERATIONAL,
+                        subOpIdentifier);
+                if (optionalSubs.isPresent()) {
+                    logger.error("onSubnetAddedToVpn: SubnetOpDataEntry for subnet " + subnetId.getValue() +
+                            " already detected to be present");
+                    return;
+                }
+                logger.debug("onSubnetAddedToVpn: Creating new SubnetOpDataEntry node for subnet: " +  subnetId.getValue());
+                Map<BigInteger, SubnetToDpn> subDpnMap = new HashMap<BigInteger, SubnetToDpn>();
+                SubnetOpDataEntry subOpEntry = null;
+                BigInteger dpnId = null;
+                BigInteger nhDpnId = null;
+                SubnetToDpn subDpn = null;
+
+                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder().setKey(new SubnetOpDataEntryKey(subnetId));
+                subOpBuilder.setSubnetId(subnetId);
+                subOpBuilder.setSubnetCidr(subnetIp);
+                String rd = VpnUtil.getVpnRd(broker, vpnName);
+                if (rd == null) {
+                    logger.error("onSubnetAddedToVpn: The VPN Instance name " + notification.getVpnName() + " does not have RD ");
+                    return;
+                }
+                subOpBuilder.setVrfId(rd);
+                subOpBuilder.setVpnName(vpnName);
+                subOpBuilder.setSubnetToDpn(new ArrayList<SubnetToDpn>());
+                subOpBuilder.setRouteAdvState(TaskState.Na);
+                subOpBuilder.setElanTag(elanTag);
+
+                // First recover set of ports available in this subnet
+                InstanceIdentifier<Subnetmap> subMapid = InstanceIdentifier.builder(Subnetmaps.class).
+                        child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
+                Optional<Subnetmap> sm = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subMapid);
+                if (!sm.isPresent()) {
+                    logger.error("onSubnetAddedToVpn: Unable to retrieve subnetmap entry for subnet : " + subnetId);
+                    return;
+                }
+                Subnetmap subMap = sm.get();
+                List<Uuid> portList = subMap.getPortList();
+                if (portList != null) {
+                    for (Uuid port: portList) {
+                        Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(broker,port.getValue());
+                        if (intfState != null) {
+                            dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
+                            if (dpnId == null) {
+                                logger.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not assigned DPN yet, ignoring ");
+                                continue;
+                            }
+                            subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, dpnId);
+                            if (intfState.getOperStatus() != OperStatus.Up) {
+                                logger.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not UP yet, ignoring ");
+                                continue;
+                            }
+                            subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, port.getValue());
+                            if (intfState.getOperStatus() == OperStatus.Up) {
+                                // port is UP
+                                subDpnMap.put(dpnId, subDpn);
+                                if (nhDpnId == null) {
+                                    nhDpnId = dpnId;
+                                }
+                            }
+                        } else {
+                            subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, null);
+                        }
+                    }
+                    if (subDpnMap.size() > 0) {
+                        subOpBuilder.setSubnetToDpn(new ArrayList<SubnetToDpn>(subDpnMap.values()));
+                    }
+                }
+
+                if (nhDpnId != null) {
+                    subOpBuilder.setNhDpnId(nhDpnId);
+                    try {
+                        /*
+                        Write the subnet route entry to the FIB.
+                        And also advertise the subnet route entry via BGP.
+                        */
+                        addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag);
+                        advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag);
+                        subOpBuilder.setRouteAdvState(TaskState.Done);
+                    } catch (Exception ex) {
+                        logger.error("onSubnetAddedToVpn: FIB rules and Advertising nhDpnId " + nhDpnId +
+                                " information for subnet " + subnetId.getValue() + " to BGP failed {}", ex);
+                        subOpBuilder.setRouteAdvState(TaskState.Pending);
+                    }
+                } else {
+                    try {
+                        /*
+                        Write the subnet route entry to the FIB.
+                        NOTE: Will not advertise to BGP as NextHopDPN is not available yet.
+                        */
+                        addSubnetRouteToFib(rd, subnetIp, null, vpnName, elanTag);
+                    } catch (Exception ex) {
+                        logger.error("onSubnetAddedToVpn: FIB rules writing for subnet {} with exception {} " +
+                                subnetId.getValue(), ex);
+                        subOpBuilder.setRouteAdvState(TaskState.Pending);
+                    }
+                }
+
+                subOpEntry = subOpBuilder.build();
+                MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+                logger.info("onSubnetAddedToVpn: Added subnetopdataentry to OP Datastore for subnet " + subnetId.getValue());
+            } catch (Exception ex) {
+                logger.error("Creation of SubnetOpDataEntry for subnet " +
+                        subnetId.getValue() + " failed {}", ex);
+            } finally {
+            }
+        }
+    }
+
+    @Override
+    public void onSubnetDeletedFromVpn(SubnetDeletedFromVpn notification) {
+        Uuid subnetId = notification.getSubnetId();
+
+        if (!notification.isExternalVpn()) {
+            return;
+        }
+        logger.info("onSubnetDeletedFromVpn: Subnet" + subnetId.getValue() + " being removed to vpn");
+        //TODO(vivek): Change this to use more granularized lock at subnetId level
+        synchronized (this) {
+            try {
+                InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+                        child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+                logger.trace(" Removing the SubnetOpDataEntry node for subnet: " +  subnetId.getValue());
+                Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker,
+                        LogicalDatastoreType.OPERATIONAL,
+                        subOpIdentifier);
+                if (!optionalSubs.isPresent()) {
+                    logger.error("onSubnetDeletedFromVpn: SubnetOpDataEntry for subnet " + subnetId.getValue() +
+                            " not available in datastore");
+                    return;
+                }
+                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
+                List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
+                for (SubnetToDpn subDpn: subDpnList) {
+                    List<VpnInterfaces> vpnIntfList = subDpn.getVpnInterfaces();
+                    for (VpnInterfaces vpnIntf: vpnIntfList) {
+                        subOpDpnManager.removePortOpDataEntry(vpnIntf.getInterfaceName());
+                    }
+                }
+                //Removing Stale Ports in portOpData
+                InstanceIdentifier<Subnetmap> subMapid = InstanceIdentifier.builder(Subnetmaps.class).
+                        child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
+                Optional<Subnetmap> sm = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subMapid);
+                if (!sm.isPresent()) {
+                    logger.error("Stale ports removal: Unable to retrieve subnetmap entry for subnet : " + subnetId);
+                }
+                Subnetmap subMap = sm.get();
+                List<Uuid> portList = subMap.getPortList();
+                if(portList!=null){
+                    InstanceIdentifier<PortOpData> portOpIdentifier = InstanceIdentifier.builder(PortOpData.class).build();
+                    Optional<PortOpData> optionalPortOp = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
+                    if(!optionalPortOp.isPresent()){
+                        logger.error("Stale ports removal: Cannot delete port. Not available in data store");
+                        return;
+                    } else{
+                        PortOpData portOpData = optionalPortOp.get();
+                        List<PortOpDataEntry> portOpDataList = portOpData.getPortOpDataEntry();
+                        if(portOpDataList!=null){
+                            for(PortOpDataEntry portOpDataListEntry :  portOpDataList){
+                                if(portList.contains(new Uuid(portOpDataListEntry.getPortId()))){
+                                    logger.trace("Removing stale port: " + portOpDataListEntry + "for dissociated subnetId: " + subnetId);
+                                    MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier.
+                                            child(PortOpDataEntry.class, new PortOpDataEntryKey(portOpDataListEntry.getKey())));
+                                }
+                            }
+                        }
+                    }
+                }
+
+                String rd = subOpBuilder.getVrfId();
+                String subnetIp = subOpBuilder.getSubnetCidr();
+                BigInteger nhDpnId = subOpBuilder.getNhDpnId();
+                MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
+                logger.trace("Removed subnetopdataentry successfully to CONFIG Datastore");
+                try {
+                    //Withdraw the routes for all the interfaces on this subnet
+                    //Remove subnet route entry from FIB
+                    withdrawSubnetRoutefromBgp(rd, subnetIp);
+                    deleteSubnetRouteFromFib(rd, subnetIp);
+                } catch (Exception ex) {
+                    logger.error("onSubnetAddedToVpn: Withdrawing routes from BGP for subnet " +
+                            subnetId.getValue() + " failed {}" + ex);
+                }
+            } catch (Exception ex) {
+                logger.error("Removal of SubnetOpDataEntry for subnet " +
+                        subnetId.getValue() + " failed {}" + ex);
+            } finally {
+            }
+        }
+    }
+
+    @Override
+    public void onSubnetUpdatedInVpn(SubnetUpdatedInVpn notification) {
+        Uuid subnetId = notification.getSubnetId();
+        String vpnName = notification.getVpnName();
+        String subnetIp = notification.getSubnetIp();
+        Long elanTag = notification.getElanTag();
+
+        Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
+        Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
+        Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!");
+        Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!");
+
+        InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+                child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+        Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker,
+                LogicalDatastoreType.OPERATIONAL,
+                subOpIdentifier);
+        if (optionalSubs.isPresent()) {
+            if (!notification.isExternalVpn()) {
+                SubnetDeletedFromVpnBuilder bldr = new SubnetDeletedFromVpnBuilder().setVpnName(vpnName);
+                bldr.setElanTag(elanTag).setExternalVpn(true).setSubnetIp(subnetIp).setSubnetId(subnetId);
+                onSubnetDeletedFromVpn(bldr.build());
+            }
+            // TODO(vivek): Something got updated, but we donot know what ?
+        } else {
+            if (notification.isExternalVpn()) {
+                SubnetAddedToVpnBuilder bldr = new SubnetAddedToVpnBuilder().setVpnName(vpnName).setElanTag(elanTag);
+                bldr.setSubnetIp(subnetIp).setSubnetId(subnetId).setExternalVpn(true);;
+                onSubnetAddedToVpn(bldr.build());
+            }
+            // TODO(vivek): Something got updated, but we donot know what ?
+        }
+    }
+
+    @Override
+    public void onPortAddedToSubnet(PortAddedToSubnet notification) {
+        Uuid subnetId = notification.getSubnetId();
+        Uuid portId = notification.getPortId();
+
+        logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " being added to subnet " + subnetId.getValue());
+        //TODO(vivek): Change this to use more granularized lock at subnetId level
+        synchronized (this) {
+            try {
+                InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+                        child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+
+                Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+                        subOpIdentifier);
+                if (!optionalSubs.isPresent()) {
+                    logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is part of a subnet " + subnetId.getValue() +
+                            " that is not in VPN, ignoring");
+                    return;
+                }
+                Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(broker,portId.getValue());
+                if (intfState == null) {
+                    // Interface State not yet available
+                    subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, null);
+                    return;
+                }
+                BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
+                if (dpnId == null) {
+                    logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not assigned DPN yet, ignoring ");
+                    return;
+                }
+                subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, dpnId);
+                if (intfState.getOperStatus() != OperStatus.Up) {
+                    logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not UP yet, ignoring ");
+                    return;
+                }
+                logger.debug("onPortAddedToSubnet: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
+                SubnetToDpn subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, portId.getValue());
+                if (subDpn == null) {
+                    return;
+                }
+                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
+                List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
+                subDpnList.add(subDpn);
+                subOpBuilder.setSubnetToDpn(subDpnList);
+                if (subOpBuilder.getNhDpnId()  == null) {
+                    subOpBuilder.setNhDpnId(dpnId);
+                }
+                BigInteger nhDpnId = subOpBuilder.getNhDpnId();
+                String rd = subOpBuilder.getVrfId();
+                String subnetIp = subOpBuilder.getSubnetCidr();
+                String vpnName = subOpBuilder.getVpnName();
+                Long elanTag = subOpBuilder.getElanTag();
+                if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) ||
+                        (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
+                    try {
+                        // Write the Subnet Route Entry to FIB
+                        // Advertise BGP Route here and set route_adv_state to DONE
+                        addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag);
+                        advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag);
+                        subOpBuilder.setRouteAdvState(TaskState.Done);
+                    } catch (Exception ex) {
+                        logger.error("onPortAddedToSubnet: Advertising NextHopDPN "+ nhDpnId +
+                                " information for subnet " + subnetId.getValue() + " to BGP failed {}", ex);
+                    }
+                }
+                SubnetOpDataEntry subOpEntry = subOpBuilder.build();
+                MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+                logger.info("onPortAddedToSubnet: Updated subnetopdataentry to OP Datastore for port " + portId.getValue());
+
+            } catch (Exception ex) {
+                logger.error("Creation of SubnetOpDataEntry for subnet " +
+                        subnetId.getValue() + " failed {}", ex);
+            } finally {
+            }
+        }
+    }
+
+    @Override
+    public void onPortRemovedFromSubnet(PortRemovedFromSubnet notification) {
+        Uuid subnetId = notification.getSubnetId();
+        Uuid portId = notification.getPortId();
+
+        logger.info("onPortRemovedFromSubnet: Port " + portId.getValue() + " being removed from subnet " + subnetId.getValue());
+        //TODO(vivek): Change this to use more granularized lock at subnetId level
+        synchronized (this) {
+            try {
+                PortOpDataEntry portOpEntry = subOpDpnManager.removePortOpDataEntry(portId.getValue());
+                if (portOpEntry == null) {
+                    return;
+                }
+                BigInteger dpnId = portOpEntry.getDpnId();
+                if (dpnId == null) {
+                    logger.debug("onPortRemovedFromSubnet:  Port {} does not have a DPNId associated, ignoring", portId.getValue());
+                    return;
+                }
+                logger.debug("onPortRemovedFromSubnet: Updating the SubnetOpDataEntry node for subnet: " +  subnetId.getValue());
+                boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, portId.getValue());
+                InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+                        child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+                Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+                        subOpIdentifier);
+                if (!optionalSubs.isPresent()) {
+                    logger.info("onPortRemovedFromSubnet: Port " + portId.getValue() + " is part of a subnet " + subnetId.getValue() +
+                            " that is not in VPN, ignoring");
+                    return;
+                }
+                SubnetOpDataEntry subOpEntry = null;
+                List<SubnetToDpn> subDpnList = null;
+                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
+                String rd = subOpBuilder.getVrfId();
+                String subnetIp = subOpBuilder.getSubnetCidr();
+                String vpnName = subOpBuilder.getVpnName();
+                Long elanTag = subOpBuilder.getElanTag();
+                BigInteger nhDpnId = subOpBuilder.getNhDpnId();
+                if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
+                    // select another NhDpnId
+                    if (last) {
+                        logger.debug("onPortRemovedFromSubnet: Last port " + portId + " on the subnet: " +  subnetId.getValue());
+                        // last port on this DPN, so we need to swap the NHDpnId
+                        subDpnList = subOpBuilder.getSubnetToDpn();
+                        if (subDpnList.isEmpty()) {
+                            subOpBuilder.setNhDpnId(null);
+                            try {
+                                // withdraw route from BGP
+                                deleteSubnetRouteFromFib(rd, subnetIp);
+                                withdrawSubnetRoutefromBgp(rd, subnetIp);
+                                subOpBuilder.setRouteAdvState(TaskState.Na);
+                            } catch (Exception ex) {
+                                logger.error("onPortRemovedFromSubnet: Withdrawing NextHopDPN " + dpnId + " information for subnet " +
+                                        subnetId.getValue() + " from BGP failed ", ex);
+                                subOpBuilder.setRouteAdvState(TaskState.Pending);
+                            }
+                        } else {
+                            nhDpnId = subDpnList.get(0).getDpnId();
+                            subOpBuilder.setNhDpnId(nhDpnId);
+                            logger.debug("onInterfaceDown: Swapping the Designated DPN to " + nhDpnId + " for subnet " + subnetId.getValue());
+                            try {
+                                // Best effort Withdrawal of route from BGP for this subnet
+                                // Advertise the new NexthopIP to BGP for this subnet
+                                withdrawSubnetRoutefromBgp(rd, subnetIp);
+                                addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag);
+                                advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag);
+                                subOpBuilder.setRouteAdvState(TaskState.Done);
+                            } catch (Exception ex) {
+                                logger.error("onPortRemovedFromSubnet: Swapping Withdrawing NextHopDPN " + dpnId +
+                                        " information for subnet " + subnetId.getValue() +
+                                        " to BGP failed {}" + ex);
+                                subOpBuilder.setRouteAdvState(TaskState.Pending);
+                            }
+                        }
+                    }
+                }
+                subOpEntry = subOpBuilder.build();
+                MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+                logger.info("onPortRemovedFromSubnet: Updated subnetopdataentry to OP Datastore removing port " + portId.getValue());
+            } catch (Exception ex) {
+                logger.error("Creation of SubnetOpDataEntry for subnet " +
+                        subnetId.getValue() + " failed {}" + ex);
+            } finally {
+            }
+        }
+    }
+
+    public void onInterfaceUp(Interface intfState) {
+
+        logger.info("onInterfaceUp: Port " + intfState.getName());
+        //TODO(vivek): Change this to use more granularized lock at subnetId level
+        synchronized (this) {
+            SubnetToDpn subDpn = null;
+            String intfName = intfState.getName();
+            PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intfName);
+            if (portOpEntry == null) {
+                logger.info("onInterfaceUp: Port " + intfState.getName()  + "is part of a subnet not in VPN, ignoring");
+                return;
+            }
+            BigInteger dpnId = portOpEntry.getDpnId();
+            if (dpnId  == null) {
+                dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
+                if (dpnId == null) {
+                    logger.error("onInterfaceUp: Unable to determine the DPNID for port " + intfName);
+                    return;
+                }
+            }
+            Uuid subnetId = portOpEntry.getSubnetId();
+            try {
+                InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+                        child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+                Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+                        subOpIdentifier);
+                if (!optionalSubs.isPresent()) {
+                    logger.error("onInterfaceUp: SubnetOpDataEntry for subnet " + subnetId.getValue() +
+                            " is not available");
+                    return;
+                }
+
+                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
+                logger.debug("onInterfaceUp: Updating the SubnetOpDataEntry node for subnet: " +  subnetId.getValue());
+                subOpDpnManager.addPortOpDataEntry(intfName, subnetId, dpnId);
+                subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, intfName);
+                if (subDpn == null) {
+                    return;
+                }
+                List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
+                subDpnList.add(subDpn);
+                subOpBuilder.setSubnetToDpn(subDpnList);
+                if (subOpBuilder.getNhDpnId()  == null) {
+                    subOpBuilder.setNhDpnId(dpnId);
+                }
+                BigInteger nhDpnId = subOpBuilder.getNhDpnId();
+                String rd = subOpBuilder.getVrfId();
+                String subnetIp = subOpBuilder.getSubnetCidr();
+                String vpnName = subOpBuilder.getVpnName();
+                Long elanTag = subOpBuilder.getElanTag();
+                if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) || (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
+                    try {
+                        // Write the Subnet Route Entry to FIB
+                        // Advertise BGP Route here and set route_adv_state to DONE
+                        addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag);
+                        advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag);
+                        subOpBuilder.setRouteAdvState(TaskState.Done);
+                    } catch (Exception ex) {
+                        logger.error("onInterfaceUp: Advertising NextHopDPN " + nhDpnId + " information for subnet " +
+                                subnetId.getValue() + " to BGP failed {}" + ex);
+                    }
+                }
+                SubnetOpDataEntry subOpEntry = subOpBuilder.build();
+                MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+                logger.info("onInterfaceUp: Updated subnetopdataentry to OP Datastore port up " + intfName);
+            } catch (Exception ex) {
+                logger.error("Creation of SubnetOpDataEntry for subnet " +
+                        subnetId.getValue() + " failed {}" + ex);
+            } finally {
+            }
+        }
+    }
+
+    public void onInterfaceDown(Interface intfState) {
+        logger.info("onInterfaceDown: Port " + intfState.getName());
+        //TODO(vivek): Change this to use more granularized lock at subnetId level
+        synchronized (this) {
+            String intfName = intfState.getName();
+            PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intfName);
+            if (portOpEntry == null) {
+                logger.info("onInterfaceDown: Port " + intfState.getName()  + "is part of a subnet not in VPN, ignoring");
+                return;
+            }
+            BigInteger dpnId = portOpEntry.getDpnId();
+            if (dpnId  == null) {
+                dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
+                if (dpnId == null) {
+                    logger.error("onInterfaceDown: Unable to determine the DPNID for port " + intfName);
+                    return;
+                }
+            }
+            Uuid subnetId = portOpEntry.getSubnetId();
+            try {
+                logger.debug("onInterfaceDown: Updating the SubnetOpDataEntry node for subnet: " +  subnetId.getValue());
+                boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, intfName);
+                InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+                        child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+                Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker,
+                        LogicalDatastoreType.OPERATIONAL,
+                        subOpIdentifier);
+                if (!optionalSubs.isPresent()) {
+                    logger.error("onInterfaceDown: SubnetOpDataEntry for subnet " + subnetId.getValue() +
+                            " is not available");
+                    return;
+                }
+                SubnetOpDataEntry subOpEntry = null;
+                List<SubnetToDpn> subDpnList = null;
+                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
+                String rd = subOpBuilder.getVrfId();
+                String subnetIp = subOpBuilder.getSubnetCidr();
+                String vpnName = subOpBuilder.getVpnName();
+                Long elanTag = subOpBuilder.getElanTag();
+                BigInteger nhDpnId = subOpBuilder.getNhDpnId();
+                if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
+                    // select another NhDpnId
+                    if (last) {
+                        logger.debug("onInterfaceDown: Last active port " + intfState.getName() + " on the subnet: " +  subnetId.getValue());
+                        // last port on this DPN, so we need to swap the NHDpnId
+                        subDpnList = subOpBuilder.getSubnetToDpn();
+                        if (subDpnList.isEmpty()) {
+                            subOpBuilder.setNhDpnId(null);
+                            try {
+                                // Withdraw route from BGP for this subnet
+                                deleteSubnetRouteFromFib(rd, subnetIp);
+                                withdrawSubnetRoutefromBgp(rd, subnetIp);
+                                subOpBuilder.setRouteAdvState(TaskState.Na);
+                            } catch (Exception ex) {
+                                logger.error("onInterfaceDown: Withdrawing NextHopDPN " + dpnId + " information for subnet " +
+                                        subnetId.getValue() + " from BGP failed {}" + ex);
+                                subOpBuilder.setRouteAdvState(TaskState.Pending);
+                            }
+                        } else {
+                            nhDpnId = subDpnList.get(0).getDpnId();
+                            subOpBuilder.setNhDpnId(nhDpnId);
+                            logger.debug("onInterfaceDown: Swapping the Designated DPN to " + nhDpnId + " for subnet " + subnetId.getValue());
+                            try {
+                                // Best effort Withdrawal of route from BGP for this subnet
+                                withdrawSubnetRoutefromBgp(rd, subnetIp);
+                                addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag);
+                                advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag);
+                                subOpBuilder.setRouteAdvState(TaskState.Done);
+                            } catch (Exception ex) {
+                                logger.error("onInterfaceDown: Swapping Withdrawing NextHopDPN " + dpnId + " information for subnet " +
+                                        subnetId.getValue() + " to BGP failed {}" + ex);
+                                subOpBuilder.setRouteAdvState(TaskState.Pending);
+                            }
+                        }
+                    }
+                }
+                subOpEntry = subOpBuilder.build();
+                MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+                logger.info("onInterfaceDown: Updated subnetopdataentry to OP Datastore port down " + intfName);
+            } catch (Exception ex) {
+                logger.error("Creation of SubnetOpDataEntry for subnet " +
+                        subnetId.getValue() + " failed {}" + ex);
+            } finally {
+            }
+        }
+    }
+
+    private static void setRdToElanOpEntry(DataBroker broker,
+                                           String rd, String subnetIp, String nextHopIp, String vpnName,
+                                           Long elanTag) {
+        RdToElanOpEntryBuilder rdElanBuilder = null;
+        RdToElanOpEntry rdElan = null;
+
+        try {
+            InstanceIdentifier<RdToElanOpEntry> rdIdentifier = InstanceIdentifier.builder(RdToElanOp.class).
+                    child(RdToElanOpEntry.class, new RdToElanOpEntryKey(rd, subnetIp)).build();
+            Optional<RdToElanOpEntry> optionalRd = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, rdIdentifier);
+            if (!optionalRd.isPresent()) {
+                // Create PortOpDataEntry only if not present
+                rdElanBuilder = new RdToElanOpEntryBuilder().setKey(new RdToElanOpEntryKey(rd,subnetIp));
+                rdElanBuilder.setRd(rd).setSubnetIp(subnetIp).setNextHopIp(nextHopIp);
+                rdElanBuilder.setElanTag(elanTag);
+                rdElanBuilder.setVpnName(vpnName);
+                rdElan = rdElanBuilder.build();
+            } else {
+                rdElanBuilder = new RdToElanOpEntryBuilder(optionalRd.get());
+                rdElanBuilder.setRd(rd).setSubnetIp(subnetIp).setNextHopIp(nextHopIp);
+                rdElanBuilder.setElanTag(elanTag);
+                rdElanBuilder.setVpnName(vpnName);
+                rdElan = rdElanBuilder.build();
+            }
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, rdIdentifier, rdElan);
+            logger.info("Creating RdToElan entry Rd {} SubnetIp {} NextHopIp {} Elan {} " ,rd, subnetIp, nextHopIp, elanTag);
+        } catch (Exception ex) {
+            logger.error("Exception when creating RdToElan entry {}" + ex);
+        } finally {
+        }
+    }
+
+    private void addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
+                                     Long elanTag) {
+        Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
+        Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
+        Preconditions.checkNotNull(vpnName, "vpnName cannot be null or empty!");
+        Preconditions.checkNotNull(elanTag, "elanTag cannot be null or empty!");
+        String nexthopIp = null;
+        if (nhDpnId != null) {
+            nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, nhDpnId);
+        }
+        int label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
+                VpnUtil.getNextHopLabelKey(rd, subnetIp));
+        setRdToElanOpEntry(broker, rd, subnetIp, nexthopIp, vpnName, elanTag);
+        vpnInterfaceManager.addFibEntryToDS(rd, subnetIp, nexthopIp, label);
+    }
+
+    private void deleteSubnetRouteFromFib(String rd, String subnetIp) {
+        Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
+        Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
+        vpnInterfaceManager.removeFibEntryFromDS(rd, subnetIp);
+    }
+
+    private void advertiseSubnetRouteToBgp(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
+                                           Long elanTag) throws Exception {
+        Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
+        Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
+        Preconditions.checkNotNull(elanTag, "elanTag cannot be null or empty!");
+        Preconditions.checkNotNull(nhDpnId, "nhDpnId cannot be null or empty!");
+        Preconditions.checkNotNull(vpnName, "vpnName cannot be null or empty!");
+        String nexthopIp = null;
+        nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, nhDpnId);
+        if (nexthopIp == null) {
+            logger.error("createSubnetRouteInVpn: Unable to obtain endpointIp address for DPNId " + nhDpnId);
+            throw new Exception("Unable to obtain endpointIp address for DPNId " + nhDpnId);
+        }
+        int label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
+                VpnUtil.getNextHopLabelKey(rd, subnetIp));
+        setRdToElanOpEntry(broker, rd, subnetIp, nexthopIp, vpnName, elanTag);
+        try {
+            bgpManager.advertisePrefix(rd, subnetIp, nexthopIp, label);
+        } catch (Exception e) {
+            logger.error("Subnet route not advertised for rd " + rd + " failed ", e);
+            throw e;
+        }
+    }
+
+    private void withdrawSubnetRoutefromBgp(String rd, String subnetIp) throws Exception {
+        Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
+        Preconditions.checkNotNull(subnetIp, "SubnetIp cannot be null or empty!");
+        try {
+            bgpManager.withdrawPrefix(rd, subnetIp);
+        } catch (Exception e) {
+            logger.error("Subnet route not advertised for rd " + rd + " failed ", e);
+            throw e;
+        }
+    }
+}
+
index 67ad13b84ae3cd0dd150e0c9b5b3fe6b22ed1cf7..76ad366faad1b3a4b98d607cd9c5ec9a17a87f8e 100644 (file)
@@ -9,11 +9,13 @@
 package org.opendaylight.vpnservice;
 
 import java.math.BigInteger;
+import java.net.InetAddress;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.List;
 
 import com.google.common.base.Optional;
+import com.google.common.primitives.Ints;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
@@ -24,6 +26,8 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.packet.ARP;
+import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
@@ -53,6 +57,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extr
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdPools;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPool;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPoolKey;
@@ -62,6 +70,15 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.IfIndexesInterfaceMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronPortData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.neutron.port.data.PortFixedipToPortName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.neutron.port.data.PortFixedipToPortNameKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanTagNameMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagNameKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -309,6 +326,8 @@ public class VpnUtil {
             result = tx.read(datastoreType, path).get();
         } catch (Exception e) {
             throw new RuntimeException(e);
+        } finally {
+            tx.close();
         }
 
         return result;
@@ -361,4 +380,81 @@ public class VpnUtil {
         }
     }
 
-}
+    public static long getRemoteBCGroup(long elanTag) {
+        return VpnConstants.ELAN_GID_MIN + ((elanTag % VpnConstants.ELAN_GID_MIN) *2);
+    }
+
+    // interface-index-tag operational container
+    public static IfIndexInterface getInterfaceInfoByInterfaceTag(DataBroker broker, long interfaceTag) {
+        InstanceIdentifier<IfIndexInterface> interfaceId = getInterfaceInfoEntriesOperationalDataPath(interfaceTag);
+        Optional<IfIndexInterface> existingInterfaceInfo = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
+        if(existingInterfaceInfo.isPresent()) {
+            return existingInterfaceInfo.get();
+        }
+        return null;
+    }
+
+    private static InstanceIdentifier<IfIndexInterface> getInterfaceInfoEntriesOperationalDataPath(long interfaceTag) {
+        return InstanceIdentifier.builder(IfIndexesInterfaceMap.class).child(IfIndexInterface.class,
+                new IfIndexInterfaceKey((int) interfaceTag)).build();
+    }
+
+    public static String getNeutronPortNamefromPortFixedIp(DataBroker broker, String fixedIp) {
+        InstanceIdentifier id = buildFixedIpToPortNameIdentifier(fixedIp);
+        Optional<PortFixedipToPortName> portFixedipToPortNameData = read(broker, LogicalDatastoreType.CONFIGURATION,
+                id);
+        if (portFixedipToPortNameData.isPresent()) {
+            return portFixedipToPortNameData.get().getPortName();
+        }
+        return null;
+    }
+
+    private static InstanceIdentifier<PortFixedipToPortName> buildFixedIpToPortNameIdentifier(String fixedIp) {
+        InstanceIdentifier<PortFixedipToPortName> id = InstanceIdentifier.builder(NeutronPortData.class).child
+                (PortFixedipToPortName.class, new PortFixedipToPortNameKey(fixedIp)).build();
+        return id;
+    }
+
+    public static ElanTagName getElanInfoByElanTag(DataBroker broker,long elanTag) {
+        InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
+        Optional<ElanTagName> existingElanInfo = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanId);
+        if(existingElanInfo.isPresent()) {
+            return existingElanInfo.get();
+        }
+        return null;
+    }
+
+    private static InstanceIdentifier<ElanTagName> getElanInfoEntriesOperationalDataPath(long elanTag) {
+        return InstanceIdentifier.builder(ElanTagNameMap.class).child(ElanTagName.class,
+                new ElanTagNameKey(elanTag)).build();
+    }
+
+
+    public static boolean isIpInSubnet(int ipAddress, String subnetCidr) {
+        String[] subSplit = subnetCidr.split("/");
+        LOG.trace("SubnetRoutePacketInHandler: Viewing Subnet Split " + subSplit);
+        if (subSplit.length < 2) {
+            return false;
+        }
+
+        String subnetStr = subSplit[0];
+        int subnet = 0;
+        try {
+            InetAddress subnetAddress = InetAddress.getByName(subnetStr);
+            subnet = Ints.fromByteArray(subnetAddress.getAddress());
+        } catch (Exception ex) {
+            LOG.error("Passed in Subnet IP string not convertible to InetAdddress " + subnetStr);
+            return false;
+        }
+        int prefixLength = Integer.valueOf(subSplit[1]);
+        int mask = -1 << (32 - prefixLength);
+        LOG.trace("SubnetRoutePacketInHandler: prefixLength " + prefixLength + " mask " + mask);
+        LOG.trace("SubnetRoutePacketInHandler: subnet & mask " + (subnet & mask));
+        LOG.trace("SubnetRoutePacketInHandler: subnet & mask " + (ipAddress & mask));
+        if ((subnet & mask) == (ipAddress & mask)) {
+            return true;
+        }
+        return false;
+    }
+
+}
\ No newline at end of file
index ce72eb6ac19489d155d874d14c16d2de680bb280..67eccf91ad3f6a613662c8e02026f24191510756 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderCo
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.fibmanager.api.IFibManager;
 import org.opendaylight.vpnmanager.api.IVpnManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
@@ -25,6 +26,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,6 +44,9 @@ public class VpnserviceProvider implements BindingAwareProvider, IVpnManager,
     private ItmRpcService itmProvider;
     private IdManagerService idManager;
     private OdlArputilService arpManager;
+    private NeutronvpnService neuService;
+    private PacketProcessingService m_packetProcessingService;
+    private SubnetRoutePacketInHandler subnetRoutePacketInHandler;
     private NotificationService notificationService;
 
     @Override
@@ -57,6 +62,12 @@ public class VpnserviceProvider implements BindingAwareProvider, IVpnManager,
             vpnInterfaceManager.setITMProvider(itmProvider);
             vpnInterfaceManager.setIdManager(idManager);
             vpnInterfaceManager.setArpManager(arpManager);
+            vpnInterfaceManager.setNeutronvpnManager(neuService);
+            //Handles subnet route entries
+            subnetRoutePacketInHandler = new SubnetRoutePacketInHandler(dataBroker, idManager);
+            m_packetProcessingService = session.getRpcService(PacketProcessingService.class);
+            subnetRoutePacketInHandler.setPacketProcessingService(m_packetProcessingService);
+            notificationService.registerNotificationListener(subnetRoutePacketInHandler);
             vpnManager.setVpnInterfaceManager(vpnInterfaceManager);
             createIdPool();
         } catch (Exception e) {
@@ -77,10 +88,6 @@ public class VpnserviceProvider implements BindingAwareProvider, IVpnManager,
         this.mdsalManager = mdsalManager;
     }
 
-    public void setFibManager(IFibManager fibManager) {
-        this.fibManager = fibManager;
-    }
-
     public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
         this.interfaceManager = interfaceManager;
     }