JUnits for Interface Manager
[vpnservice.git] / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / vpnservice / VpnInterfaceManager.java
index 3221a474f4f50612d263fe4537ef4f6ef3164f85..b56c1d060e2000bcb66fde682cbe505165a161d6 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.vpnservice;
 
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+
 import java.math.BigInteger;
 import java.util.Collection;
 import java.util.Collections;
@@ -17,15 +19,14 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
-
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.FutureCallback;
-
 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.fibmanager.api.IFibManager;
 import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
@@ -34,6 +35,7 @@ import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -45,8 +47,10 @@ 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.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+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.opendaylight.l3vpn.rev130911.AdjacencyList;
 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;
@@ -70,14 +74,16 @@ import org.slf4j.LoggerFactory;
 
 public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface> implements AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
-    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private ListenerRegistration<DataChangeListener> listenerRegistration, interfaceListenerRegistration;
     private final DataBroker broker;
     private final IBgpManager bgpManager;
+    private IFibManager fibManager;
     private IMdsalApiManager mdsalManager;
     private IInterfaceManager interfaceManager;
     private IdManagerService idManager;
-    private Map<Long, Collection<Long>> vpnToDpnsDb;
-    private Map<Long, Collection<String>> dpnToInterfaceDb;
+    private Map<Long, Collection<BigInteger>> vpnToDpnsDb;
+    private Map<BigInteger, Collection<String>> dpnToInterfaceDb;
+    private InterfaceListener interfaceListener;
 
     private static final FutureCallback<Void> DEFAULT_CALLBACK =
             new FutureCallback<Void>() {
@@ -102,6 +108,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         this.bgpManager = bgpManager;
         vpnToDpnsDb = new ConcurrentHashMap<>();
         dpnToInterfaceDb = new ConcurrentHashMap<>();
+        interfaceListener = new InterfaceListener();
         registerListener(db);
     }
 
@@ -113,6 +120,10 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         this.interfaceManager = interfaceManager;
     }
 
+    public void setFibManager(IFibManager fibManager) {
+        this.fibManager = fibManager;
+    }
+
     public void setIdManager(IdManagerService idManager) {
         this.idManager = idManager;
     }
@@ -122,10 +133,12 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         if (listenerRegistration != null) {
             try {
                 listenerRegistration.close();
+                interfaceListenerRegistration.close();
             } catch (final Exception e) {
                 LOG.error("Error when cleaning up DataChangeListener.", e);
             }
             listenerRegistration = null;
+            interfaceListenerRegistration = null;
         }
         LOG.info("VPN Interface Manager Closed");
     }
@@ -134,12 +147,19 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         try {
             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
                     getWildCardPath(), VpnInterfaceManager.this, DataChangeScope.SUBTREE);
+            interfaceListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    getInterfaceListenerPath(), interfaceListener, DataChangeScope.SUBTREE);
         } catch (final Exception e) {
             LOG.error("VPN Service DataChange listener registration fail!", e);
             throw new IllegalStateException("VPN Service registration Listener failed.", e);
         }
     }
 
+    private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> getInterfaceListenerPath() {
+        return InstanceIdentifier.create(InterfacesState.class)
+        .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
+    }
+
     @Override
     protected void add(final InstanceIdentifier<VpnInterface> identifier,
             final VpnInterface vpnInterface) {
@@ -157,7 +177,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
         if (port.isPresent()) {
             Interface interf = port.get();
-            bindServiceOnInterface(interf, getVpnId(vpnInterface.getVpnInstanceName()));
+            bindServiceOnInterface(interf, vpnInterface.getVpnInstanceName());
             updateNextHops(identifier, vpnInterface);
         }
     }
@@ -175,23 +195,26 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             //Get the rd of the vpn instance
             String rd = getRouteDistinguisher(intf.getVpnInstanceName());
 
-            long dpnId = interfaceManager.getDpnForInterface(intfName);
+            BigInteger dpnId = interfaceManager.getDpnForInterface(intfName);
             String nextHopIp = interfaceManager.getEndpointIpForDpn(dpnId);
 
-            if (!nextHops.isEmpty()) {
-                LOG.trace("NextHops are {}", nextHops);
-                for (Adjacency nextHop : nextHops) {
-                    String key = nextHop.getIpAddress();
-                    long label = getUniqueId(key);
 
-                    updatePrefixToBGP(rd, nextHop, nextHopIp, label);
-                    value.add(new AdjacencyBuilder(nextHop).setLabel(label).build());
-                }
+            LOG.trace("NextHops are {}", nextHops);
+            for (Adjacency nextHop : nextHops) {
+                String key = rd + VpnConstants.SEPARATOR + nextHop.getIpAddress();
+                long label = getUniqueId(key);
+                value.add(new AdjacencyBuilder(nextHop).setLabel(label).build());
             }
+
             Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
             VpnInterface opInterface = VpnUtil.getVpnInterface(intfName, intf.getVpnInstanceName(), aug);
             InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName);
-            asyncWrite(LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface, DEFAULT_CALLBACK);
+            syncWrite(LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface, DEFAULT_CALLBACK);
+            for (Adjacency nextHop : nextHops) {
+                String key = rd + VpnConstants.SEPARATOR + nextHop.getIpAddress();
+                long label = getUniqueId(key);
+                updatePrefixToBGP(rd, nextHop, nextHopIp, label);
+            }
         }
     }
 
@@ -219,8 +242,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         InstanceIdentifier<VpnInstance1> id = InstanceIdentifier.builder(VpnInstances.class)
                 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).augmentation(VpnInstance1.class).build();
         Optional<VpnInstance1> vpnInstance = read(LogicalDatastoreType.OPERATIONAL, id);
-        //TODO: Default vpnid should be a constant.
-        long vpnId = -1;
+
+        long vpnId = VpnConstants.INVALID_ID;
         if(vpnInstance.isPresent()) {
             vpnId = vpnInstance.get().getVpnId();
         }
@@ -240,14 +263,14 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         return rd;
     }
 
-    private synchronized void updateMappingDbs(long vpnId, long dpnId, String intfName) {
-        Collection<Long> dpnIds = vpnToDpnsDb.get(vpnId);
+    private synchronized void updateMappingDbs(long vpnId, BigInteger dpnId, String intfName, String rd) {
+        Collection<BigInteger> dpnIds = vpnToDpnsDb.get(vpnId);
         if(dpnIds == null) {
             dpnIds = new HashSet<>();
         }
         if(dpnIds.add(dpnId)) {
             vpnToDpnsDb.put(vpnId, dpnIds);
-            //TODO: Send an Event that new DPN added...
+            fibManager.populateFibOnNewDpn(dpnId, vpnId, rd);
         }
 
         Collection<String> intfNames = dpnToInterfaceDb.get(dpnId);
@@ -258,32 +281,36 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         dpnToInterfaceDb.put(dpnId, intfNames);
     }
 
-    private synchronized void remoteFromMappingDbs(long vpnId, long dpnId, String inftName) {
+    private synchronized void remoteFromMappingDbs(long vpnId, BigInteger dpnId, String inftName, String rd) {
         Collection<String> intfNames = dpnToInterfaceDb.get(dpnId);
         if(intfNames == null) {
             return;
         }
         intfNames.remove(inftName);
         dpnToInterfaceDb.put(dpnId, intfNames);
+        //TODO: Delay 'DPN' removal so that other services can cleanup the entries for this dpn
         if(intfNames.isEmpty()) {
-            Collection<Long> dpnIds = vpnToDpnsDb.get(vpnId);
+            Collection<BigInteger> dpnIds = vpnToDpnsDb.get(vpnId);
             if(dpnIds == null) {
                 return;
             }
             dpnIds.remove(dpnId);
             vpnToDpnsDb.put(vpnId, dpnIds);
+            fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
         }
     }
 
-    private void bindServiceOnInterface(Interface intf, long vpnId) {
-        LOG.trace("Bind service on interface {} for VPN: {}", intf, vpnId);
+    private void bindServiceOnInterface(Interface intf, String vpnName) {
+        LOG.trace("Bind service on interface {} for VPN: {}", intf, vpnName);
 
-        long dpId = interfaceManager.getDpnForInterface(intf.getName()); 
-        if(dpId == 0L) {
+        long vpnId = getVpnId(vpnName);
+        BigInteger dpId = interfaceManager.getDpnForInterface(intf.getName()); 
+        if(dpId.equals(BigInteger.ZERO)) {
             LOG.warn("DPN for interface {} not found. Bind service on this interface aborted.", intf.getName());
             return;
         } else {
-            updateMappingDbs(vpnId, dpId, intf.getName());
+            String rd = getRouteDistinguisher(vpnName);
+            updateMappingDbs(vpnId, dpId, intf.getName(), rd);
         }
 
         long portNo = interfaceManager.getPortForInterface(intf.getName());
@@ -294,6 +321,9 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 
         int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
         short gotoTableId = VpnConstants.FIB_TABLE;
+        if(intf.getType().equals(Tunnel.class)){
+            gotoTableId = VpnConstants.LFIB_TABLE;
+        }
 
         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
         mkInstructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
@@ -302,8 +332,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { gotoTableId }));
 
         List<MatchInfo> matches = new ArrayList<MatchInfo>();
-        matches.add(new MatchInfo(MatchFieldType.in_port, new long[] {
-                dpId, portNo }));
+        matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {
+                dpId, BigInteger.valueOf(portNo) }));
 
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, VpnConstants.LPORT_INGRESS_TABLE, flowRef,
                           priority, flowName, 0, 0, COOKIE_VM_INGRESS_TABLE, matches, mkInstructions);
@@ -311,7 +341,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         mdsalManager.installFlow(flowEntity);
     }
 
-    private String getVpnInterfaceFlowRef(long dpId, short tableId,
+    private String getVpnInterfaceFlowRef(BigInteger dpId, short tableId,
             long vpnId, long portNo) {
         return new StringBuilder().append(dpId).append(tableId).append(vpnId).append(portNo).toString();
     }
@@ -355,7 +385,9 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         if (port.isPresent()) {
             Interface interf = port.get();
             removeNextHops(identifier, vpnInterface);
-            unbindServiceOnInterface(interf, getVpnId(vpnInterface.getVpnInstanceName()));
+            unbindServiceOnInterface(interf, vpnInterface.getVpnInstanceName());
+            //InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
+            delete(LogicalDatastoreType.OPERATIONAL, identifier);
         } else {
             LOG.warn("No nexthops were available to handle remove event {}", interfaceName);
         }
@@ -377,8 +409,6 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 }
             }
         }
-        InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName);
-        delete(LogicalDatastoreType.OPERATIONAL, interfaceId);
     }
 
     private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
@@ -387,18 +417,21 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
     }
 
-    private void unbindServiceOnInterface(Interface intf, long vpnId) {
-        LOG.trace("Unbind service on interface {} for VPN: {}", intf, vpnId);
+    private void unbindServiceOnInterface(Interface intf, String vpnName) {
+        LOG.trace("Unbind service on interface {} for VPN: {}", intf, vpnName);
 
-        long dpId = interfaceManager.getDpnForInterface(intf.getName());
-        if(dpId == 0L) {
+        long vpnId = getVpnId(vpnName);
+        BigInteger dpId = interfaceManager.getDpnForInterface(intf);
+        if(dpId.equals(BigInteger.ZERO)) {
             LOG.warn("DPN for interface {} not found. Unbind service on this interface aborted.", intf.getName());
             return;
         } else {
-            remoteFromMappingDbs(vpnId, dpId, intf.getName());
+            String rd = getRouteDistinguisher(vpnName);
+            remoteFromMappingDbs(vpnId, dpId, intf.getName(), rd);
+            LOG.debug("removed vpn mapping for interface {} from VPN RD {}", intf.getName(), rd);
         }
 
-        long portNo = interfaceManager.getPortForInterface(intf.getName());
+        long portNo = interfaceManager.getPortForInterface(intf);
         String flowRef = getVpnInterfaceFlowRef(dpId, VpnConstants.LPORT_INGRESS_TABLE, vpnId, portNo);
 
         String flowName = intf.getName();
@@ -406,17 +439,17 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
 
         List<MatchInfo> matches = new ArrayList<MatchInfo>();
-        matches.add(new MatchInfo(MatchFieldType.in_port, new long[] {
-                dpId, portNo }));
+        matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {
+                dpId, BigInteger.valueOf(portNo) }));
 
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, VpnConstants.LPORT_INGRESS_TABLE, flowRef,
                           priority, flowName, 0, 0, null, matches, null);
+        LOG.debug("Remove ingress flow for port {} in dpn {}", portNo, dpId.intValue());
 
         mdsalManager.removeFlow(flowEntity);
     }
 
     private void removePrefixFromBGP(String rd, Adjacency nextHop) {
-        //public void deletePrefix(String rd, String prefix) throws Exception;
         try {
             bgpManager.deletePrefix(rd, nextHop.getIpAddress());
         } catch(Exception e) {
@@ -427,8 +460,59 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     @Override
     protected void update(InstanceIdentifier<VpnInterface> identifier, 
                                    VpnInterface original, VpnInterface update) {
-        // TODO Auto-generated method stub
+        LOG.trace("Update VPN Interface {} , original {}, update {}", 
+                                                  identifier, original, update);
+        String vpnName = original.getVpnInstanceName();
+
+        boolean vpnNameChanged = false;
+        String rd = getRouteDistinguisher(vpnName);
+        String newRd = rd;
+        if(!vpnName.equals(update.getVpnInstanceName())) {
+            //VPN for this interface got changed. 
+            //Remove the interface from old VPN and add it to new VPN
+            String newVpnName = update.getVpnInstanceName();
+            newRd = getRouteDistinguisher(newVpnName);
+            if(newRd.equals("")) {
+                LOG.warn("VPN Instance {} not found. Update operation aborted", newVpnName);
+                return;
+            }
+            vpnNameChanged = true;
+            LOG.debug("New VPN Name for the interface {} is {}", newVpnName, original.getName());
+        }
 
+        BigInteger dpnId = interfaceManager.getDpnForInterface(original.getName());
+        String nextHopIp = interfaceManager.getEndpointIpForDpn(dpnId);
+        //List<Adjacency> oldAdjs = original.getAugmentation(Adjacencies.class).getAdjacency();
+        List<Adjacency> newAdjs = update.getAugmentation(Adjacencies.class).getAdjacency();
+        if(vpnNameChanged && newAdjs != null && !newAdjs.isEmpty()) {
+            long label = VpnConstants.INVALID_ID;
+            InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
+            Optional<Adjacencies> adjacencies = read(LogicalDatastoreType.OPERATIONAL, path);
+            if (adjacencies.isPresent()) {
+                List<Adjacency> nextHops = adjacencies.get().getAdjacency();
+                for(Adjacency nextHop : nextHops) {
+                    label = nextHop.getLabel();
+                    if(label == VpnConstants.INVALID_ID) {
+                        //Generate label using ID Manager
+                        String key = newRd + VpnConstants.SEPARATOR + nextHop.getIpAddress();
+                        label = getUniqueId(key);
+                    }
+                    removePrefixFromBGP(rd, nextHop);
+                    //updatePrefixToBGP(newRd, nextHop, nextHopIp, label);
+                }
+                updateNextHops(identifier, update);
+                asyncUpdate(LogicalDatastoreType.OPERATIONAL, identifier, update, DEFAULT_CALLBACK);
+            }
+        } else {
+            LOG.debug("No Update information is available for VPN Interface to proceed");
+        }
+    }
+
+    protected <T extends DataObject> void asyncUpdate(LogicalDatastoreType datastoreType,
+            InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        tx.merge(datastoreType, path, data, true);
+        Futures.addCallback(tx.submit(), callback);
     }
 
     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
@@ -438,12 +522,141 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         Futures.addCallback(tx.submit(), callback);
     }
 
-    synchronized Collection<Long> getDpnsForVpn(long vpnId) {
-        Collection<Long> dpnIds = vpnToDpnsDb.get(vpnId);
+    private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
+                        InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        tx.put(datastoreType, path, data, true);
+        tx.submit();
+    }
+
+    synchronized Collection<BigInteger> getDpnsForVpn(long vpnId) {
+        Collection<BigInteger> dpnIds = vpnToDpnsDb.get(vpnId);
         if(dpnIds != null) {
             return ImmutableList.copyOf(dpnIds);
         } else {
             return Collections.emptyList();
         }
     }
+
+    VpnInterface getVpnInterface(String interfaceName) {
+        Optional<VpnInterfaces> optVpnInterfaces = read(LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnInterfacesIdentifier());
+        if(optVpnInterfaces.isPresent()) {
+            List<VpnInterface> interfaces = optVpnInterfaces.get().getVpnInterface();
+            for(VpnInterface intf : interfaces) {
+                if(intf.getName().equals(interfaceName)) {
+                    return intf;
+                }
+            }
+        }
+        return null;
+    }
+
+    private Interface getInterface(String interfaceName) {
+        Optional<Interface> optInterface = read(LogicalDatastoreType.CONFIGURATION, VpnUtil.getInterfaceIdentifier(interfaceName));
+        if(optInterface.isPresent()) {
+            return optInterface.get();
+        }
+        return null;
+    }
+
+    private String getTunnelInterfaceFlowRef(BigInteger dpnId, short tableId, String ifName) {
+        return new StringBuilder().append(dpnId).append(tableId).append(ifName).toString();
+    }
+
+
+    protected void makeTunnelIngressFlow(BigInteger dpnId, String ifName, int addOrRemoveFlow) {
+        long portNo = 0;
+        String flowName = ifName;
+        String flowRef = getTunnelInterfaceFlowRef(dpnId, VpnConstants.LPORT_INGRESS_TABLE, ifName);
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
+        if (NwConstants.ADD_FLOW == addOrRemoveFlow) {
+            portNo = interfaceManager.getPortForInterface(ifName);
+            matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {
+                dpnId, BigInteger.valueOf(portNo) }));
+            mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {VpnConstants.LFIB_TABLE}));
+        }
+
+        BigInteger COOKIE_VM_INGRESS_TABLE = new BigInteger("8000001", 16);
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, VpnConstants.LPORT_INGRESS_TABLE, flowRef,
+                VpnConstants.DEFAULT_FLOW_PRIORITY, flowName, 0, 0, COOKIE_VM_INGRESS_TABLE, matches, mkInstructions);
+
+        if (NwConstants.ADD_FLOW == addOrRemoveFlow) {
+            mdsalManager.installFlow(flowEntity);
+        } else {
+            mdsalManager.removeFlow(flowEntity);
+        }
+    }
+
+    private class InterfaceListener extends AbstractDataChangeListener<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface>  {
+
+        public InterfaceListener() {
+            super(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
+        }
+
+        @Override
+        protected void remove(InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> identifier,
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface del) {
+            LOG.trace("Operational Interface remove event - {}", del);
+        }
+
+        @Override
+        protected void update(InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> identifier,
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface original, 
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface update) {
+            LOG.trace("Operation Interface update event - Old: {}, New: {}", original, update);
+            String interfaceName = update.getName();
+            Interface intf = getInterface(interfaceName);
+            if (intf != null && intf.getType().equals(Tunnel.class)) {
+                BigInteger dpnId = interfaceManager.getDpnForInterface(interfaceName);
+                if(update.getOperStatus().equals(OperStatus.Up)) {
+                    //Create ingress to LFIB
+                    LOG.debug("Installing Ingress for tunnel interface {}", interfaceName);
+                    makeTunnelIngressFlow(dpnId, interfaceName, NwConstants.ADD_FLOW);
+                } else if(update.getOperStatus().equals(OperStatus.Down)) {
+                    LOG.debug("Removing Ingress flow for tunnel interface {}", interfaceName);
+                    makeTunnelIngressFlow(dpnId, interfaceName, NwConstants.DEL_FLOW);
+                }
+            } else {
+                VpnInterface vpnInterface = getVpnInterface(interfaceName);
+                if(vpnInterface != null) {
+                    if(update.getOperStatus().equals(OperStatus.Up)) {
+                        LOG.debug("Installing VPN related rules for interface {}", interfaceName);
+                        addInterface(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
+                    } else if(update.getOperStatus().equals(OperStatus.Down)) {
+                        LOG.debug("Removing VPN related rules for interface {}", interfaceName);
+                        VpnInterfaceManager.this.remove(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
+                    }
+                } else {
+                    LOG.debug("No VPN Interface associated with interface {} to handle Update Operation", interfaceName);
+                }
+            }
+        }
+
+        @Override
+        protected void add(InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> identifier,
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface add) {
+            LOG.trace("Operational Interface add event - {}", add);
+            String interfaceName = add.getName();
+            Interface intf = getInterface(interfaceName);
+            if (intf != null && intf.getType().equals(Tunnel.class)) {
+                BigInteger dpnId = interfaceManager.getDpnForInterface(interfaceName);
+                if(add.getOperStatus().equals(OperStatus.Up)) {
+                    //Create ingress to LFIB
+                    LOG.debug("Installing Ingress for tunnel interface {}", interfaceName);
+                    makeTunnelIngressFlow(dpnId, interfaceName, NwConstants.ADD_FLOW);
+                }
+            } else {
+                VpnInterface vpnInterface = getVpnInterface(interfaceName);
+                if(vpnInterface != null) {
+                    if(add.getOperStatus().equals(OperStatus.Up)) {
+                        LOG.debug("Installing VPN related rules for interface {}", interfaceName);
+                        addInterface(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
+                    }
+                } else {
+                    LOG.debug("No VPN Interface associated with interface {} to handle add Operation", interfaceName);
+                }
+            }
+        }
+    }
 }