BUG-954: Add support for Neutron port/network delete events for OF1.3 04/6604/9
authorHsin-Yi Shen <hshen@redhat.com>
Mon, 5 May 2014 23:55:34 +0000 (19:55 -0400)
committerHsin-Yi Shen <hshen@redhat.com>
Mon, 5 May 2014 23:55:34 +0000 (19:55 -0400)
This commit will enable support for Neutron port delete and network delete events.
It will also enable flow cleanup and tunnel port delete for ovsdb using OF 1.3

Signed-off-by: Hsin-Yi Shen <hshen@redhat.com>
Change-Id: Ic848125d21abc44c796ef2b1675cca9e50630f76

neutron/src/main/java/org/opendaylight/ovsdb/neutron/NetworkHandler.java
neutron/src/main/java/org/opendaylight/ovsdb/neutron/PortHandler.java
neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundEvent.java
neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundHandler.java
neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF10ProviderManager.java
neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF13ProviderManager.java
ovsdb/src/main/java/org/opendaylight/ovsdb/plugin/InventoryService.java
ovsdb/src/main/java/org/opendaylight/ovsdb/plugin/OVSDBInventoryListener.java

index 62880477910e7cbee24ae8056a756961159b66f5..33fce3de65ff94c6b0b29e0e6266aa4c8c59fd2c 100644 (file)
@@ -5,14 +5,24 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  *
- * Authors : Madhu Venugopal, Brent Salisbury
+ * Authors : Madhu Venugopal, Brent Salisbury, Hsin-Yi Shen
  */
 package org.opendaylight.ovsdb.neutron;
 
 import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
 
 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.ovsdb.lib.table.Interface;
+import org.opendaylight.ovsdb.lib.table.internal.Table;
+import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
+import org.opendaylight.ovsdb.plugin.OVSDBInventoryListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -112,6 +122,39 @@ public class NetworkHandler extends BaseHandler
                     result);
             return;
         }
+        /* Is this the last Neutron tenant network */
+        INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
+        List <NeutronNetwork> networks = new ArrayList<NeutronNetwork>();
+        if (neutronNetworkService != null) {
+            networks = neutronNetworkService.getAllNetworks();
+            OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
+            if (networks.isEmpty()) {
+                logger.trace("neutronNetworkDeleted: last tenant network, delete tunnel ports...");
+                IConnectionServiceInternal connectionService = (IConnectionServiceInternal)
+                                        ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
+                List<Node> nodes = connectionService.getNodes();
+
+                for (Node node : nodes) {
+                    try {
+                        ConcurrentMap<String, Table<?>> interfaces = this.ovsdbConfigService.getRows(node, Interface.NAME.getName());
+                        if (interfaces != null) {
+                            for (String intfUUID : interfaces.keySet()) {
+                                Interface intf = (Interface) interfaces.get(intfUUID);
+                                String intfType = intf.getType();
+                                if (intfType.equalsIgnoreCase("vxlan") || intfType.equalsIgnoreCase("gre")) {
+                                    /* delete tunnel ports on this node */
+                                    logger.trace("Delete tunnel intf {}", intf);
+                                    inventoryListener.rowRemoved(node, Interface.NAME.getName(), intfUUID,
+                                                                 intf, null);
+                                }
+                            }
+                        }
+                    } catch (Exception e) {
+                        logger.error("Exception during handlingNeutron network delete");
+                    }
+                }
+            }
+        }
         TenantNetworkManager.getManager().networkDeleted(network.getID());
     }
 }
index d30d01f0a6a62e31ac67dd640e80bf5717d8c7cd..ec21561547ad6960f0f056616646210dc8823dcf 100644 (file)
 package org.opendaylight.ovsdb.neutron;
 
 import java.net.HttpURLConnection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
 
+import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
 import org.opendaylight.controller.networkconfig.neutron.INeutronPortAware;
+import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
 import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.ovsdb.lib.table.Interface;
+import org.opendaylight.ovsdb.lib.table.internal.Table;
+import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
+import org.opendaylight.ovsdb.plugin.OVSDBInventoryListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -118,9 +129,43 @@ public class PortHandler extends BaseHandler
             return;
         }
 
+        IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
+        INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
+        NeutronNetwork neutronNetwork = neutronNetworkService.getNetwork(port.getNetworkUUID());
+        OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
+        List<Node> nodes = connectionService.getNodes();
+        for (Node node : nodes) {
+            try {
+                ConcurrentMap<String, Table<?>> interfaces = this.ovsdbConfigService.getRows(node, Interface.NAME.getName());
+                if (interfaces != null) {
+                    for (String intfUUID : interfaces.keySet()) {
+                        Interface intf = (Interface) interfaces.get(intfUUID);
+                        Map<String, String> externalIds = intf.getExternal_ids();
+                        if (externalIds == null) {
+                            logger.trace("No external_ids seen in {}", intf);
+                            continue;
+                        }
+                        /* Compare Neutron port uuid */
+                        String neutronPortId = externalIds.get(TenantNetworkManager.EXTERNAL_ID_INTERFACE_ID);
+                        if (neutronPortId == null) {
+                            continue;
+                        }
+                        if (neutronPortId.equalsIgnoreCase(port.getPortUUID())) {
+                            logger.trace("neutronPortDeleted: Delete interface {}", intf.getName());
+                            inventoryListener.rowRemoved(node, Interface.NAME.getName(), intfUUID,
+                                                         intf, neutronNetwork);
+                            break;
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                logger.error("Exception during handlingNeutron network delete");
+            }
+        }
         logger.debug(" PORT delete successful for tenant-id - {}, " +
                      " network-id - {}, port-id - {}",
                      port.getTenantID(), port.getNetworkUUID(),
                      port.getID());
+
     }
 }
index df3b734d8fcaba5e641d10bff8d4073ecb617cc4..70e69c81432d588aec4e7ced72a0acec546572d8 100644 (file)
@@ -21,6 +21,7 @@ public class SouthboundEvent {
     private String tableName;
     private String uuid;
     private Table<?> row;
+    private Object context;
     public SouthboundEvent(Node node, Action action) {
         super();
         this.type = Type.NODE;
@@ -36,6 +37,16 @@ public class SouthboundEvent {
         this.uuid = uuid;
         this.row = row;
     }
+    public SouthboundEvent(Node node, String tableName, String uuid, Table<?> row, Object context, Action action) {
+        super();
+        this.type = Type.ROW;
+        this.action = action;
+        this.node = node;
+        this.tableName = tableName;
+        this.uuid = uuid;
+        this.row = row;
+        this.context = context;
+    }
     public Type getType() {
         return type;
     }
@@ -54,10 +65,13 @@ public class SouthboundEvent {
     public Table<?> getRow() {
         return row;
     }
+    public Object getContext() {
+        return context;
+    }
     @Override
     public String toString() {
         return "SouthboundEvent [type=" + type + ", action=" + action + ", node=" + node + ", tableName=" + tableName
-                + ", uuid=" + uuid + ", row=" + row + "]";
+                + ", uuid=" + uuid + ", row=" + row + ", context=" + context.toString() + "]";
     }
     @Override
     public int hashCode() {
index dc8267bcc02832efbd8c0e6adb685e614a6db3c7..2efdb2b16c3b5c4ef760fabde3d35235d2ab07c6 100644 (file)
@@ -70,7 +70,7 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList
                         break;
                     case ROW:
                         try {
-                            processRowUpdate(ev.getNode(), ev.getTableName(), ev.getUuid(), ev.getRow(), ev.getAction());
+                            processRowUpdate(ev.getNode(), ev.getTableName(), ev.getUuid(), ev.getRow(), ev.getContext(), ev.getAction());
                         } catch (Exception e) {
                             logger.error("Exception caught in ProcessRowUpdate for node " + ev.getNode(), e);
                         }
@@ -134,14 +134,20 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList
                 logger.trace("IGNORING Port Update : "+newRow.toString());
                 return false;
             }
+        } else if (newRow.getTableName().equals(Open_vSwitch.NAME)) {
+    /* print the row for now */
+            Open_vSwitch oldOpenvSwitch = (Open_vSwitch) oldRow;
+            if (oldOpenvSwitch.getOther_config()== null) {
+                /* we are only interested in other_config field change */
+                return false;
+            }
         }
-
         return true;
     }
 
     @Override
-    public void rowRemoved(Node node, String tableName, String uuid, Table<?> row) {
-        this.enqueueEvent(new SouthboundEvent(node, tableName, uuid, row, SouthboundEvent.Action.DELETE));
+    public void rowRemoved(Node node, String tableName, String uuid, Table<?> row, Object context) {
+        this.enqueueEvent(new SouthboundEvent(node, tableName, uuid, row, context, SouthboundEvent.Action.DELETE));
     }
 
     private void enqueueEvent (SouthboundEvent event) {
@@ -160,12 +166,23 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList
     }
 
     private void processRowUpdate(Node node, String tableName, String uuid, Table<?> row,
-                                  SouthboundEvent.Action action) {
+                                  Object context, SouthboundEvent.Action action) {
         if (action == SouthboundEvent.Action.DELETE) {
             if (Interface.NAME.getName().equalsIgnoreCase(tableName)) {
+                logger.debug("processRowUpdate: {} Deleted node: {}, uuid: {}, row: {}", tableName,node, uuid, row);
                 Interface deletedIntf = (Interface)row;
-                NeutronNetwork network = TenantNetworkManager.getManager().getTenantNetworkForInterface(deletedIntf);
-                if (network != null && !network.getRouterExternal()) {
+                NeutronNetwork network = null;
+                if (context == null) {
+                    network = TenantNetworkManager.getManager().getTenantNetworkForInterface(deletedIntf);
+                } else {
+                    network = (NeutronNetwork)context;
+                }
+                logger.info("Delete interface " + deletedIntf.getName());
+                if (deletedIntf.getType().equalsIgnoreCase("vxlan") ||
+                    deletedIntf.getType().equalsIgnoreCase("gre")) {
+                    /* delete tunnel interfaces */
+                    this.handleInterfaceDelete(node, uuid, deletedIntf, false, null);
+                } else if (network != null && !network.getRouterExternal()) {
                     try {
                         ConcurrentMap<String, Table<?>> interfaces = this.ovsdbConfigService.getRows(node, Interface.NAME.getName());
                         if (interfaces != null) {
@@ -176,7 +193,7 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList
                                 NeutronNetwork neutronNetwork = TenantNetworkManager.getManager().getTenantNetworkForInterface(intf);
                                 if (neutronNetwork != null && neutronNetwork.equals(network)) isLastInstanceOnNode = false;
                             }
-                            this.handleInterfaceDelete(node, uuid, deletedIntf, isLastInstanceOnNode);
+                            this.handleInterfaceDelete(node, uuid, deletedIntf, isLastInstanceOnNode, network);
                         }
                     } catch (Exception e) {
                         logger.error("Error fetching Interface Rows for node " + node, e);
@@ -243,18 +260,23 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList
                     network.getProviderSegmentationID(), node, intf);
         }
     }
-    private void handleInterfaceDelete (Node node, String uuid, Interface intf, boolean isLastInstanceOnNode) {
-        if (AdminConfigManager.getManager().getTunnelEndPoint(node) == null) {
-            logger.error("Tunnel end-point configuration missing. Please configure it in Open_vSwitch Table");
-            return;
-        }
-        NeutronNetwork network = TenantNetworkManager.getManager().getTenantNetworkForInterface(intf);
-        if (network != null) {
-            if (isLastInstanceOnNode) {
+    private void handleInterfaceDelete (Node node, String uuid, Interface intf, boolean isLastInstanceOnNode,
+                                        NeutronNetwork network) {
+        if (intf.getType().equalsIgnoreCase("vxlan") || intf.getType().equalsIgnoreCase("gre")) {
+            /* delete tunnel interfaces */
+            logger.debug("handlerInterfaceDelete: intf {}", intf);
+            ProviderNetworkManager.getManager().handleInterfaceDelete(intf.getType(),
+                                                null, node, intf, isLastInstanceOnNode);
+        } else if (network != null) {
+            if (AdminConfigManager.getManager().getTunnelEndPoint(node) == null) {
+                logger.error("Tunnel end-point configuration missing. Please configure it in Open_vSwitch Table");
+                return;
+            }
+            if (isLastInstanceOnNode & ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
                 TenantNetworkManager.getManager().reclaimTennantNetworkInternalVlan(node, uuid, network);
             }
             ProviderNetworkManager.getManager().handleInterfaceDelete(network.getProviderNetworkType(),
-                    network.getProviderSegmentationID(), node, intf, isLastInstanceOnNode);
+                                              network.getProviderSegmentationID(), node, intf, isLastInstanceOnNode);
         }
     }
 
index cf3743e4ad00a1c70868efd97a63db90bb14c42e..7131677c526018200f8dcf6bb5eaa5ca7bf980fe 100644 (file)
@@ -469,20 +469,36 @@ class OF10ProviderManager extends ProviderNetworkManager {
     @Override
     public Status handleInterfaceDelete(String tunnelType, String tunnelKey, Node srcNode, Interface intf, boolean isLastInstanceOnNode) {
         Status status = new Status(StatusCode.SUCCESS);
-
-        IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
-        List<Node> nodes = connectionService.getNodes();
-        nodes.remove(srcNode);
-        for (Node dstNode : nodes) {
-            InetAddress src = AdminConfigManager.getManager().getTunnelEndPoint(srcNode);
-            InetAddress dst = AdminConfigManager.getManager().getTunnelEndPoint(dstNode);
-            this.removeTunnelRules(tunnelType, tunnelKey, dst, srcNode, intf, true);
-            if (isLastInstanceOnNode) {
-                status = deleteTunnelPort(srcNode, tunnelType, src, dst, tunnelKey);
+        logger.debug("handleInterfaceDelete: networkType: {}, segmentationId: {}, srcNode: {}, intf:{}",
+                     tunnelType, tunnelKey, srcNode,
+                     intf.getName(), isLastInstanceOnNode);
+        if (intf.getType().equalsIgnoreCase("vxlan") || intf.getType().equalsIgnoreCase("gre")) {
+            /* Delete tunnel port */
+            try {
+                OvsDBMap<String, String> options = intf.getOptions();
+                InetAddress src = InetAddress.getByName(options.get("local_ip"));
+                InetAddress dst = InetAddress.getByName(options.get("remote_ip"));
+                String key = options.get("key");
+                status = deleteTunnelPort(srcNode, intf.getType(), src, dst, key);
+            } catch (Exception e) {
+                logger.error(e.getMessage(), e);
             }
-            this.removeTunnelRules(tunnelType, tunnelKey, src, dstNode, intf, false);
-            if (status.isSuccess() && isLastInstanceOnNode) {
-                deleteTunnelPort(dstNode, tunnelType, dst, src, tunnelKey);
+        } else {
+            /* delete all other interfaces */
+            IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
+            List<Node> nodes = connectionService.getNodes();
+            nodes.remove(srcNode);
+            for (Node dstNode : nodes) {
+                InetAddress src = AdminConfigManager.getManager().getTunnelEndPoint(srcNode);
+                InetAddress dst = AdminConfigManager.getManager().getTunnelEndPoint(dstNode);
+                this.removeTunnelRules(tunnelType, tunnelKey, dst, srcNode, intf, true);
+                if (isLastInstanceOnNode) {
+                    status = deleteTunnelPort(srcNode, tunnelType, src, dst, tunnelKey);
+                }
+                this.removeTunnelRules(tunnelType, tunnelKey, src, dstNode, intf, false);
+                if (status.isSuccess() && isLastInstanceOnNode) {
+                    deleteTunnelPort(dstNode, tunnelType, dst, src, tunnelKey);
+                }
             }
         }
         return status;
index 08ab0ce3c6afc8597c53de86383e1df920e87bfa..1f864e0d78b84208172c32f7fdadb54c1e6b3605 100644 (file)
@@ -167,6 +167,19 @@ class OF13ProviderManager extends ProviderNetworkManager {
         return false;
     }
 
+    private String getPortUuid(Node node, String name, String bridgeUUID) throws Exception {
+        OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+        Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
+        if (bridge != null) {
+            Set<UUID> ports = bridge.getPorts();
+            for (UUID portUUID : ports) {
+                Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID.toString());
+                if (port != null && port.getName().equalsIgnoreCase(name)) return portUUID.toString();
+            }
+        }
+        return null;
+    }
+
     private Status addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst) {
         try {
             String bridgeUUID = null;
@@ -239,6 +252,51 @@ class OF13ProviderManager extends ProviderNetworkManager {
         }
     }
 
+    /* delete port from ovsdb port table */
+    private Status deletePort(Node node, String bridgeName, String portName) {
+        try {
+            String bridgeUUID = null;
+            OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+            Map<String, org.opendaylight.ovsdb.lib.table.internal.Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
+            if (bridgeTable != null) {
+                for (String uuid : bridgeTable.keySet()) {
+                    Bridge bridge = (Bridge)bridgeTable.get(uuid);
+                    if (bridge.getName().equals(bridgeName)) {
+                        bridgeUUID = uuid;
+                        break;
+                    }
+                }
+            }
+            if (bridgeUUID == null) {
+                logger.debug("Could not find Bridge {} in {}", bridgeName, node);
+                return new Status(StatusCode.SUCCESS);
+            }
+
+            String portUUID = this.getPortUuid(node, portName, bridgeUUID);
+            Status status = new Status(StatusCode.SUCCESS);
+            if (portUUID != null) {
+               status = ovsdbTable.deleteRow(node, Port.NAME.getName(), portUUID);
+               if (!status.isSuccess()) {
+                   logger.error("Failed to delete port {} in {} status : {}", portName, bridgeUUID,
+                                status);
+                   return status;
+               }
+               logger.debug("Port {} delete status : {}", portName, status);
+            }
+            return status;
+        } catch (Exception e) {
+            logger.error("Exception in deletePort", e);
+            return new Status(StatusCode.INTERNALERROR);
+        }
+    }
+
+    private Status deleteTunnelPort(Node node, String tunnelType, InetAddress src, InetAddress dst) {
+        String tunnelBridgeName = AdminConfigManager.getManager().getIntegrationBridgeName();
+        String portName = getTunnelName(tunnelType, dst);
+        Status status = deletePort(node, tunnelBridgeName, portName);
+        return status;
+    }
+
     private void programLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
          /*
          * Table(0) Rule #3
@@ -247,7 +305,7 @@ class OF13ProviderManager extends ProviderNetworkManager {
          * Action:Action: Set Tunnel ID and GOTO Local Table (5)
          */
 
-         writeLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac);
+         handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, true);
 
         /*
          * Table(0) Rule #4
@@ -256,7 +314,7 @@ class OF13ProviderManager extends ProviderNetworkManager {
          * Action: Drop w/ a low priority
          */
 
-         writeDropSrcIface(dpid, localPort);
+         handleDropSrcIface(dpid, localPort, true);
 
          /*
           * Table(2) Rule #1
@@ -266,7 +324,7 @@ class OF13ProviderManager extends ProviderNetworkManager {
           * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
           */
 
-          writeLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac);
+         handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, true);
 
          /*
           * Table(2) Rule #2
@@ -276,7 +334,7 @@ class OF13ProviderManager extends ProviderNetworkManager {
           * actions=output:2,3,4,5
           */
 
-          writeLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort);
+          handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
 
           /*
            * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
@@ -290,7 +348,7 @@ class OF13ProviderManager extends ProviderNetworkManager {
            * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
            */
 
-           writeTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId);
+           handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, true);
 
           /*
            * Table(2) Rule #3
@@ -300,7 +358,47 @@ class OF13ProviderManager extends ProviderNetworkManager {
            * table=2,priority=8192,tun_id=0x5 actions=drop
            */
 
-           writeLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId);
+           handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, true);
+    }
+
+    private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
+        /*
+         ** Table(0) Rule #3
+         ** ----------------
+         ** Match: VM sMac and Local Ingress Port
+         ** Action:Action: Set Tunnel ID and GOTO Local Table (5)
+         **/
+
+        handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
+
+        /*
+         ** Table(0) Rule #4
+         ** ----------------
+         ** Match: Drop any remaining Ingress Local VM Packets
+         ** Action: Drop w/ a low priority
+         **/
+
+        handleDropSrcIface(dpid, localPort, false);
+
+        /*
+         ** Table(2) Rule #1
+         ** ----------------
+         ** Match: Match TunID and Destination DL/dMAC Addr
+         ** Action: Output Port
+         ** table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
+         **/
+
+        handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
+
+        /*
+         ** Table(2) Rule #2
+         ** ----------------
+         ** Match: Tunnel ID and dMAC (::::FF:FF)
+         ** table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         ** actions=output:2,3,4,5
+         **/
+
+        handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
     }
 
     private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
@@ -308,10 +406,10 @@ class OF13ProviderManager extends ProviderNetworkManager {
          * Table(0) Rule #2
          * ----------------
          * Match: Ingress Port, Tunnel ID
-         * Action: GOTO Local Table (10)
+         * Action: GOTO Local Table (20)
          */
 
-         writeTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort);
+         handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
 
          /*
           * Table(1) Rule #2
@@ -323,7 +421,7 @@ class OF13ProviderManager extends ProviderNetworkManager {
           * actions=output:10,output:11,goto_table:2
           */
 
-         writeTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort);
+         handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
 
     }
 
@@ -338,7 +436,69 @@ class OF13ProviderManager extends ProviderNetworkManager {
          * actions=output:11,goto_table:2
          */
 
-        writeTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac);
+        handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, true);
+    }
+
+    private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
+        /*
+         ** Table(1) Rule #1
+         ** ----------------
+         ** Match: Drop any remaining Ingress Local VM Packets
+         ** Action: Drop w/ a low priority
+         ** -------------------------------------------
+         ** table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
+         ** actions=output:11,goto_table:2
+         **/
+
+       handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
+    }
+
+    /* Remove tunnel rules if last node in this tenant network */
+    private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) {
+        /*
+         ** TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
+         **/
+        /*
+         ** Table(1) Rule #3
+         ** ----------------
+         ** Match: Any remaining Ingress Local VM Packets
+         ** Action: Drop w/ a low priority
+         ** -------------------------------------------
+         ** table=1,priority=8192,tun_id=0x5 actions=goto_table:2
+         **/
+
+        handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, false);
+
+        /*
+         ** Table(2) Rule #3
+         ** ----------------
+         ** Match: Any Remaining Flows w/a TunID
+         ** Action: Drop w/ a low priority
+         ** table=2,priority=8192,tun_id=0x5 actions=drop
+         **/
+
+        handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
+
+       /*
+        ** Table(0) Rule #2
+        ** ----------------
+        ** Match: Ingress Port, Tunnel ID
+        ** Action: GOTO Local Table (10)
+        **/
+
+       handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
+
+       /*
+        ** Table(1) Rule #2
+        ** ----------------
+        ** Match: Match Tunnel ID and L2 ::::FF:FF Flooding
+        ** Action: Flood to selected destination TEPs
+        ** -------------------------------------------
+        ** table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+        ** actions=output:10,output:11,goto_table:2
+        **/
+
+       handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
     }
 
     private Long getIntegrationBridgeOFDPID (Node node) {
@@ -393,6 +553,45 @@ class OF13ProviderManager extends ProviderNetworkManager {
         }
     }
 
+    private void removeLocalRules (String networkType, String segmentationId, Node node, Interface intf) {
+        try {
+            Long dpid = this.getIntegrationBridgeOFDPID(node);
+            if (dpid == 0L) {
+                logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
+                return;
+            }
+
+            Set<BigInteger> of_ports = intf.getOfport();
+            if (of_ports == null || of_ports.size() <= 0) {
+                logger.error("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
+                return;
+            }
+            long localPort = ((BigInteger)of_ports.toArray()[0]).longValue();
+
+            Map<String, String> externalIds = intf.getExternal_ids();
+            if (externalIds == null) {
+                logger.error("No external_ids seen in {}", intf);
+                return;
+            }
+
+            String attachedMac = externalIds.get(TenantNetworkManager.EXTERNAL_ID_VM_MAC);
+            if (attachedMac == null) {
+                logger.error("No AttachedMac seen in {}", intf);
+                return;
+            }
+
+            /* Program local rules based on network type */
+            if (networkType.equalsIgnoreCase("gre") ||
+              networkType.equalsIgnoreCase("vxlan")) {
+                logger.debug("Remove local bridge rules for interface {}", intf.getName());
+                removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
+            }
+        } catch (Exception e) {
+            logger.error("Exception in removing Local Rules for "+intf+" on "+node, e);
+        }
+    }
+
+
     private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
             Interface intf, boolean local) {
         try {
@@ -444,7 +643,73 @@ class OF13ProviderManager extends ProviderNetworkManager {
                         if (!local) {
                             programRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort);
                         }
-                        programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort);
+                        logger.trace("program local ingress tunnel rules: node" + node.getNodeIDString() + " intf " + intf.getName());
+                        if (local) {
+                            programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort);
+                        }
+                        return;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("", e);
+        }
+    }
+
+    private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
+            Interface intf, boolean local, boolean isLastInstanceOnNode) {
+        try {
+
+            Long dpid = this.getIntegrationBridgeOFDPID(node);
+            if (dpid == 0L) {
+                logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
+                return;
+            }
+            OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+
+            Set<BigInteger> of_ports = intf.getOfport();
+            if (of_ports == null || of_ports.size() <= 0) {
+                logger.error("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
+                return;
+            }
+            long localPort = ((BigInteger)of_ports.toArray()[0]).longValue();
+
+            Map<String, String> externalIds = intf.getExternal_ids();
+            if (externalIds == null) {
+                logger.error("No external_ids seen in {}", intf);
+                return;
+            }
+
+            String attachedMac = externalIds.get(TenantNetworkManager.EXTERNAL_ID_VM_MAC);
+            if (attachedMac == null) {
+                logger.error("No AttachedMac seen in {}", intf);
+                return;
+            }
+
+            Map<String, org.opendaylight.ovsdb.lib.table.internal.Table<?>> intfs = ovsdbTable.getRows(node, Interface.NAME.getName());
+            if (intfs != null) {
+                for (org.opendaylight.ovsdb.lib.table.internal.Table<?> row : intfs.values()) {
+                    Interface tunIntf = (Interface)row;
+                    if (tunIntf.getName().equals(this.getTunnelName(tunnelType, dst))) {
+                        of_ports = tunIntf.getOfport();
+                        if (of_ports == null || of_ports.size() <= 0) {
+                            logger.error("Could NOT Identify Tunnel port {} on {}", tunIntf.getName(), node);
+                            continue;
+                        }
+                        long tunnelOFPort = ((BigInteger)of_ports.toArray()[0]).longValue();
+
+                        if (tunnelOFPort == -1) {
+                            logger.error("Could NOT Identify Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
+                            return;
+                        }
+                        logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
+
+                        if (!local) {
+                            removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort);
+                        }
+                        if (local && isLastInstanceOnNode) {
+                            removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort);
+                        }
                         return;
                     }
                 }
@@ -532,10 +797,44 @@ class OF13ProviderManager extends ProviderNetworkManager {
     }
 
     @Override
-    public Status handleInterfaceDelete(String tunnelType, String tunnelKey, Node source, Interface intf,
+    public Status handleInterfaceDelete(String tunnelType, String tunnelKey, Node srcNode, Interface intf,
             boolean isLastInstanceOnNode) {
-        // TODO Auto-generated method stub
-        return null;
+        Status status = new Status(StatusCode.SUCCESS);
+        IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
+        List<Node> nodes = connectionService.getNodes();
+        nodes.remove(srcNode);
+
+        logger.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
+        if (intf.getType().equalsIgnoreCase("vxlan") || intf.getType().equalsIgnoreCase("gre")) {
+        /* Delete tunnel port */
+            try {
+                OvsDBMap<String, String> options = intf.getOptions();
+                InetAddress src = InetAddress.getByName(options.get("local_ip"));
+                InetAddress dst = InetAddress.getByName(options.get("remote_ip"));
+                status = deleteTunnelPort(srcNode, intf.getType(), src, dst);
+            } catch (Exception e) {
+                logger.error(e.getMessage(), e);
+             }
+        } else {
+            /* delete all other interfaces */
+            this.removeLocalRules(tunnelType, tunnelKey,
+                                  srcNode, intf);
+
+            if (tunnelType.equalsIgnoreCase("gre")
+                 || tunnelType.equalsIgnoreCase("vxlan")) {
+                for (Node dstNode : nodes) {
+                    InetAddress src = AdminConfigManager.getManager().getTunnelEndPoint(srcNode);
+                    InetAddress dst = AdminConfigManager.getManager().getTunnelEndPoint(dstNode);
+                    logger.info("Remove tunnel rules for interface " + intf.getName() + " on srcNode" + srcNode.getNodeIDString());
+                    this.removeTunnelRules(tunnelType, tunnelKey,
+                                           dst, srcNode, intf, true, isLastInstanceOnNode);
+                    logger.info("Remove tunnel rules for interface " + intf.getName() + " on dstNode" + dstNode.getNodeIDString());
+                    this.removeTunnelRules(tunnelType, tunnelKey,
+                                           src, dstNode, intf, false, isLastInstanceOnNode);
+                }
+            }
+        }
+        return status;
     }
 
     @Override
@@ -623,7 +922,8 @@ class OF13ProviderManager extends ProviderNetworkManager {
      * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
      */
 
-    private void writeTunnelIn(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId,  Long ofPort) {
+    private void handleTunnelIn(Long dpidLong, Short writeTable, Short goToTableId,
+                                String segmentationId,  Long ofPort, boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -636,24 +936,26 @@ class OF13ProviderManager extends ProviderNetworkManager {
         flowBuilder.setMatch(createTunnelIDMatch(matchBuilder, tunnelId).build());
         flowBuilder.setMatch(createInPortMatch(matchBuilder, dpidLong, ofPort).build());
 
-        // Create the OF Actions and Instructions
-        InstructionBuilder ib = new InstructionBuilder();
-        InstructionsBuilder isb = new InstructionsBuilder();
+        if (write) {
+            // Create the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
 
-        // Instructions List Stores Individual Instructions
-        List<Instruction> instructions = new ArrayList<Instruction>();
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = new ArrayList<Instruction>();
 
-        // Call the InstructionBuilder Methods Containing Actions
-        createGotoTableInstructions(ib, goToTableId);
-        ib.setOrder(0);
-        ib.setKey(new InstructionKey(0));
-        instructions.add(ib.build());
+            // Call the InstructionBuilder Methods Containing Actions
+            createGotoTableInstructions(ib, goToTableId);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
 
-        // Add InstructionBuilder to the Instruction(s)Builder List
-        isb.setInstruction(instructions);
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
 
-        // Add InstructionsBuilder to FlowBuilder
-        flowBuilder.setInstructions(isb.build());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+        }
 
         String flowId = "TunnelIn_"+segmentationId+"_"+ofPort;
         // Add Flow Attributes
@@ -666,7 +968,12 @@ class OF13ProviderManager extends ProviderNetworkManager {
         flowBuilder.setFlowName(flowId);
         flowBuilder.setHardTimeout(0);
         flowBuilder.setIdleTimeout(0);
-        writeFlow(flowBuilder, nodeBuilder);
+
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
     }
 
    /*
@@ -677,7 +984,8 @@ class OF13ProviderManager extends ProviderNetworkManager {
     * actions=set_field:5->tun_id,goto_table=1"
     */
 
-    private void writeLocalInPort(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId, Long inPort, String attachedMac) {
+    private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
+                                   String segmentationId, Long inPort, String attachedMac, boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -702,31 +1010,35 @@ class OF13ProviderManager extends ProviderNetworkManager {
         flowBuilder.setHardTimeout(0);
         flowBuilder.setIdleTimeout(0);
 
-        // Instantiate the Builders for the OF Actions and Instructions
-        InstructionBuilder ib = new InstructionBuilder();
-        InstructionsBuilder isb = new InstructionsBuilder();
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
 
-        // Instructions List Stores Individual Instructions
-        List<Instruction> instructions = new ArrayList<Instruction>();
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = new ArrayList<Instruction>();
 
-        // GOTO Instuctions Need to be added first to the List
-        createGotoTableInstructions(ib, goToTableId);
-        ib.setOrder(0);
-        ib.setKey(new InstructionKey(0));
-        instructions.add(ib.build());
-        // TODO Broken SetTunID
-        createSetTunnelIdInstructions(ib, new BigInteger(segmentationId));
-        ib.setOrder(1);
-        ib.setKey(new InstructionKey(1));
-        instructions.add(ib.build());
+            // GOTO Instuctions Need to be added first to the List
+            createGotoTableInstructions(ib, goToTableId);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+            // TODO Broken SetTunID
+            createSetTunnelIdInstructions(ib, new BigInteger(segmentationId));
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructions.add(ib.build());
 
-        // Add InstructionBuilder to the Instruction(s)Builder List
-        isb.setInstruction(instructions);
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
 
-        // Add InstructionsBuilder to FlowBuilder
-        flowBuilder.setInstructions(isb.build());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
 
-        writeFlow(flowBuilder, nodeBuilder);
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
     }
 
     /*
@@ -737,7 +1049,7 @@ class OF13ProviderManager extends ProviderNetworkManager {
      * table=0,priority=16384,in_port=1 actions=drop"
      */
 
-    private void writeDropSrcIface(Long dpidLong, Long inPort) {
+    private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -748,24 +1060,26 @@ class OF13ProviderManager extends ProviderNetworkManager {
         // Create the OF Match using MatchBuilder
         flowBuilder.setMatch(createInPortMatch(matchBuilder, dpidLong, inPort).build());
 
-        // Instantiate the Builders for the OF Actions and Instructions
-        InstructionBuilder ib = new InstructionBuilder();
-        InstructionsBuilder isb = new InstructionsBuilder();
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
 
-        // Instructions List Stores Individual Instructions
-        List<Instruction> instructions = new ArrayList<Instruction>();
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = new ArrayList<Instruction>();
 
-        // Call the InstructionBuilder Methods Containing Actions
-        createDropInstructions(ib);
-        ib.setOrder(0);
-        ib.setKey(new InstructionKey(0));
-        instructions.add(ib.build());
+            // Call the InstructionBuilder Methods Containing Actions
+            createDropInstructions(ib);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
 
-        // Add InstructionBuilder to the Instruction(s)Builder List
-        isb.setInstruction(instructions);
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
 
-        // Add InstructionsBuilder to FlowBuilder
-        flowBuilder.setInstructions(isb.build());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+        }
 
         String flowId = "DropFilter_"+inPort;
         // Add Flow Attributes
@@ -779,7 +1093,11 @@ class OF13ProviderManager extends ProviderNetworkManager {
         flowBuilder.setPriority(8192);
         flowBuilder.setHardTimeout(0);
         flowBuilder.setIdleTimeout(0);
-        writeFlow(flowBuilder, nodeBuilder);
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
     }
 
    /*
@@ -790,7 +1108,8 @@ class OF13ProviderManager extends ProviderNetworkManager {
     * actions=output:10,goto_table:2"
     */
 
-    private void writeTunnelOut(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId , Long OFPortOut, String attachedMac) {
+    private void handleTunnelOut(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId,
+                                 Long OFPortOut, String attachedMac, boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -813,31 +1132,36 @@ class OF13ProviderManager extends ProviderNetworkManager {
         flowBuilder.setFlowName(flowId);
         flowBuilder.setHardTimeout(0);
         flowBuilder.setIdleTimeout(0);
-        // Instantiate the Builders for the OF Actions and Instructions
-        InstructionBuilder ib = new InstructionBuilder();
-        InstructionsBuilder isb = new InstructionsBuilder();
 
-        // Instructions List Stores Individual Instructions
-        List<Instruction> instructions = new ArrayList<Instruction>();
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
 
-        // GOTO Instuctions
-        createGotoTableInstructions(ib, goToTableId);
-        ib.setOrder(0);
-        ib.setKey(new InstructionKey(0));
-        instructions.add(ib.build());
-        // Set the Output Port/Iface
-        createOutputPortInstructions(ib, dpidLong, OFPortOut);
-        ib.setOrder(1);
-        ib.setKey(new InstructionKey(1));
-        instructions.add(ib.build());
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = new ArrayList<Instruction>();
 
-        // Add InstructionBuilder to the Instruction(s)Builder List
-        isb.setInstruction(instructions);
+            // GOTO Instuctions
+            createGotoTableInstructions(ib, goToTableId);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+            // Set the Output Port/Iface
+            createOutputPortInstructions(ib, dpidLong, OFPortOut);
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructions.add(ib.build());
 
-        // Add InstructionsBuilder to FlowBuilder
-        flowBuilder.setInstructions(isb.build());
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
 
-        writeFlow(flowBuilder, nodeBuilder);
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
     }
 
        /*
@@ -848,7 +1172,8 @@ class OF13ProviderManager extends ProviderNetworkManager {
     * actions=output:10,output:11,goto_table:2
     */
 
-    private void writeTunnelFloodOut(Long dpidLong, Short writeTable, Short localTable, String segmentationId,  Long OFPortOut) {
+    private void handleTunnelFloodOut(Long dpidLong, Short writeTable, Short localTable,
+                                      String segmentationId,  Long OFPortOut, boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -887,24 +1212,45 @@ class OF13ProviderManager extends ProviderNetworkManager {
                 existingInstructions = ins.getInstruction();
             }
         }
-        // GOTO Instuction
-        createGotoTableInstructions(ib, localTable);
-        ib.setOrder(0);
-        ib.setKey(new InstructionKey(0));
-        instructions.add(ib.build());
-        // Set the Output Port/Iface
-        createOutputPortInstructions(ib, dpidLong, OFPortOut, existingInstructions);
-        ib.setOrder(1);
-        ib.setKey(new InstructionKey(1));
-        instructions.add(ib.build());
 
-        // Add InstructionBuilder to the Instruction(s)Builder List
-        isb.setInstruction(instructions);
+        if (write) {
+            // GOTO Instuction
+            createGotoTableInstructions(ib, localTable);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+            // Set the Output Port/Iface
+            createOutputPortInstructions(ib, dpidLong, OFPortOut, existingInstructions);
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            /* remove port from action list */
+            boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong,OFPortOut, existingInstructions);
+            if (flowRemove) {
+                /* if all port are removed, remove the flow too. */
+                removeFlow(flowBuilder, nodeBuilder);
+            } else {
+                /* Install instruction with new output port list*/
+                ib.setOrder(0);
+                ib.setKey(new InstructionKey(0));
+                instructions.add(ib.build());
 
-        // Add InstructionsBuilder to FlowBuilder
-        flowBuilder.setInstructions(isb.build());
+                // Add InstructionBuilder to the Instruction(s)Builder List
+                isb.setInstruction(instructions);
 
-        writeFlow(flowBuilder, nodeBuilder);
+                // Add InstructionsBuilder to FlowBuilder
+                flowBuilder.setInstructions(isb.build());
+            }
+        }
     }
 
    /*
@@ -914,7 +1260,7 @@ class OF13ProviderManager extends ProviderNetworkManager {
     * table=2,priority=8192,tun_id=0x5 actions=drop
     */
 
-    private void writeTunnelMiss(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId) {
+    private void handleTunnelMiss(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId, boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -925,24 +1271,26 @@ class OF13ProviderManager extends ProviderNetworkManager {
         // Create Match(es) and Set them in the FlowBuilder Object
         flowBuilder.setMatch(createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
 
-        // Create the OF Actions and Instructions
-        InstructionBuilder ib = new InstructionBuilder();
-        InstructionsBuilder isb = new InstructionsBuilder();
+        if (write) {
+            // Create the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
 
-        // Instructions List Stores Individual Instructions
-        List<Instruction> instructions = new ArrayList<Instruction>();
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = new ArrayList<Instruction>();
 
-        // Call the InstructionBuilder Methods Containing Actions
-        createGotoTableInstructions(ib, goToTableId);
-        ib.setOrder(0);
-        ib.setKey(new InstructionKey(0));
-        instructions.add(ib.build());
+            // Call the InstructionBuilder Methods Containing Actions
+            createGotoTableInstructions(ib, goToTableId);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
 
-        // Add InstructionBuilder to the Instruction(s)Builder List
-        isb.setInstruction(instructions);
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
 
-        // Add InstructionsBuilder to FlowBuilder
-        flowBuilder.setInstructions(isb.build());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+        }
 
         String flowId = "TunnelMiss_"+segmentationId;
         // Add Flow Attributes
@@ -956,7 +1304,11 @@ class OF13ProviderManager extends ProviderNetworkManager {
         flowBuilder.setFlowName(flowId);
         flowBuilder.setHardTimeout(0);
         flowBuilder.setIdleTimeout(0);
-        writeFlow(flowBuilder, nodeBuilder);
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
     }
 
     /*
@@ -966,7 +1318,8 @@ class OF13ProviderManager extends ProviderNetworkManager {
      * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
      */
 
-    private void writeLocalUcastOut(Long dpidLong, Short writeTable, String segmentationId, Long localPort, String attachedMac) {
+    private void handleLocalUcastOut(Long dpidLong, Short writeTable, String segmentationId, Long localPort,
+                                     String attachedMac, boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -990,25 +1343,29 @@ class OF13ProviderManager extends ProviderNetworkManager {
         flowBuilder.setHardTimeout(0);
         flowBuilder.setIdleTimeout(0);
 
-        // Instantiate the Builders for the OF Actions and Instructions
-        InstructionBuilder ib = new InstructionBuilder();
-        InstructionsBuilder isb = new InstructionsBuilder();
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
 
-        // Instructions List Stores Individual Instructions
-        List<Instruction> instructions = new ArrayList<Instruction>();
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = new ArrayList<Instruction>();
 
-        // Set the Output Port/Iface
-        createOutputPortInstructions(ib, dpidLong, localPort);
-        ib.setOrder(0);
-        ib.setKey(new InstructionKey(0));
-        instructions.add(ib.build());
+            // Set the Output Port/Iface
+            createOutputPortInstructions(ib, dpidLong, localPort);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
 
-        // Add InstructionBuilder to the Instruction(s)Builder List
-        isb.setInstruction(instructions);
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
 
-        // Add InstructionsBuilder to FlowBuilder
-        flowBuilder.setInstructions(isb.build());
-        writeFlow(flowBuilder, nodeBuilder);
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
     }
 
     /*
@@ -1018,7 +1375,8 @@ class OF13ProviderManager extends ProviderNetworkManager {
      * actions=output:2,3,4,5
      */
 
-    private void writeLocalBcastOut(Long dpidLong, Short writeTable, String segmentationId, Long localPort) {
+    private void handleLocalBcastOut(Long dpidLong, Short writeTable, String segmentationId,
+                                     Long localPort, boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -1055,19 +1413,41 @@ class OF13ProviderManager extends ProviderNetworkManager {
             }
         }
 
-        // Broken OutPort TODO: localPort needs to be a list of Ports)
-        createOutputPortInstructions(ib, dpidLong, localPort, existingInstructions);
-        ib.setOrder(0);
-        ib.setKey(new InstructionKey(0));
-        instructions.add(ib.build());
+        if (write) {
+            // Create output port list
+            createOutputPortInstructions(ib, dpidLong, localPort, existingInstructions);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
 
-        // Add InstructionBuilder to the Instruction(s)Builder List
-        isb.setInstruction(instructions);
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
 
-        // Add InstructionsBuilder to FlowBuilder
-        flowBuilder.setInstructions(isb.build());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
 
-        writeFlow(flowBuilder, nodeBuilder);
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong,
+                                       localPort, existingInstructions);
+            if (flowRemove) {
+                   /* if all ports are removed, remove flow */
+                 removeFlow(flowBuilder, nodeBuilder);
+               } else {
+                /* Install instruction with new output port list*/
+                   ib.setOrder(0);
+                   ib.setKey(new InstructionKey(0));
+                 instructions.add(ib.build());
+
+                // Add InstructionBuilder to the Instruction(s)Builder List
+                isb.setInstruction(instructions);
+
+                // Add InstructionsBuilder to FlowBuilder
+                   flowBuilder.setInstructions(isb.build());
+
+                   writeFlow(flowBuilder, nodeBuilder);
+            }
+        }
     }
 
     /*
@@ -1077,7 +1457,8 @@ class OF13ProviderManager extends ProviderNetworkManager {
      * table=2,priority=8192,tun_id=0x5 actions=drop
      */
 
-    private void writeLocalTableMiss(Long dpidLong, Short writeTable, String segmentationId) {
+    private void handleLocalTableMiss(Long dpidLong, Short writeTable, String segmentationId,
+                                      boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -1088,24 +1469,26 @@ class OF13ProviderManager extends ProviderNetworkManager {
         // Create Match(es) and Set them in the FlowBuilder Object
         flowBuilder.setMatch(createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
 
-        // Create the OF Actions and Instructions
-        InstructionBuilder ib = new InstructionBuilder();
-        InstructionsBuilder isb = new InstructionsBuilder();
+        if (write) {
+            // Create the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
 
-        // Instructions List Stores Individual Instructions
-        List<Instruction> instructions = new ArrayList<Instruction>();
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = new ArrayList<Instruction>();
 
-        // Call the InstructionBuilder Methods Containing Actions
-        createDropInstructions(ib);
-        ib.setOrder(0);
-        ib.setKey(new InstructionKey(0));
-        instructions.add(ib.build());
+            // Call the InstructionBuilder Methods Containing Actions
+            createDropInstructions(ib);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
 
-        // Add InstructionBuilder to the Instruction(s)Builder List
-        isb.setInstruction(instructions);
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
 
-        // Add InstructionsBuilder to FlowBuilder
-        flowBuilder.setInstructions(isb.build());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+        }
 
         String flowId = "LocalTableMiss_"+segmentationId;
         // Add Flow Attributes
@@ -1119,7 +1502,11 @@ class OF13ProviderManager extends ProviderNetworkManager {
         flowBuilder.setFlowName(flowId);
         flowBuilder.setHardTimeout(0);
         flowBuilder.setIdleTimeout(0);
-        writeFlow(flowBuilder, nodeBuilder);
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
     }
 
     private Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
@@ -1175,6 +1562,41 @@ class OF13ProviderManager extends ProviderNetworkManager {
         }
     }
 
+    private void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        IMDSALConsumer mdsalConsumer = (IMDSALConsumer) ServiceHelper.getInstance(IMDSALConsumer.class, "default", this);
+        if (mdsalConsumer == null) {
+            logger.error("ERROR finding MDSAL Service.");
+            return;
+        }
+
+        dataBrokerService = mdsalConsumer.getDataBrokerService();
+
+        if (dataBrokerService == null) {
+            logger.error("ERROR finding reference for DataBrokerService. Please check out the MD-SALsupport on the Controller.");
+            return;
+        }
+        DataModification<InstanceIdentifier<?>, DataObject> modification = dataBrokerService.beginTransaction();
+        InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class)
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
+                .rev130819.nodes.Node.class, nodeBuilder.getKey())
+                .augmentation(FlowCapableNode.class).child(Table.class,
+                new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
+        //modification.removeOperationalData(nodeBuilderToInstanceId(nodeBuilder));
+        modification.removeOperationalData(path1);
+        //modification.removeConfigurationData(nodeBuilderToInstanceId(nodeBuilder));
+        modification.removeConfigurationData(path1);
+        Future<RpcResult<TransactionStatus>> commitFuture = modification.commit();
+        try {
+            RpcResult<TransactionStatus> result = commitFuture.get();
+            TransactionStatus status = result.getResult();
+            logger.debug("Transaction Status "+status.toString()+" for Flow "+flowBuilder.getFlowName());
+        } catch (InterruptedException e) {
+            logger.error(e.getMessage(), e);
+        } catch (ExecutionException e) {
+            logger.error(e.getMessage(), e);
+        }
+    }
+
     /**
      * Create Ingress Port Match dpidLong, inPort
      *
@@ -1529,6 +1951,60 @@ class OF13ProviderManager extends ProviderNetworkManager {
         return ib;
     }
 
+    /**
+    * Remove Output Port from Instruction
+    *
+    * @param ib Map InstructionBuilder without any instructions
+    * @param dpidLong Long the datapath ID of a switch/node
+    * @param port Long representing a port on a switch/node
+    * @return ib InstructionBuilder Map with instructions
+    */
+    protected static boolean removeOutputPortFromInstructions(InstructionBuilder ib,
+                                   Long dpidLong, Long port , List<Instruction> instructions) {
+
+        NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port);
+        logger.debug("createOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
+
+        List<Action> actionList = new ArrayList<Action>();
+        ActionBuilder ab = new ActionBuilder();
+
+        List<Action> existingActions = null;
+        if (instructions != null) {
+            for (Instruction in : instructions) {
+                if (in.getInstruction() instanceof ApplyActionsCase) {
+                    existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+                    actionList.addAll(existingActions);
+                    break;
+                }
+            }
+        }
+
+        int numOutputPort = 0;
+        for (Action action : actionList) {
+            if (action.getAction() instanceof OutputActionCase) {
+                numOutputPort++;
+                OutputActionCase opAction = (OutputActionCase)action.getAction();
+                if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
+                    /* Find the output port in action list and remove */
+                    actionList.remove(action);
+                    numOutputPort--;
+                    break;
+                }
+            }
+        }
+
+        /* Put new action list in Apply Action instruction */
+        if (numOutputPort > 0) {
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            return false;
+        } else {
+            /* if all output port are removed. Return true to indicate flow remove */
+            return true;
+        }
+    }
+
     /**
      * Create Set Vlan ID Instruction
      *
index e195f1a825059d9313d5ccfe9ee192da23d930c7..a1bac127bc6ef6cf3ff19530f56d85584dbe0348 100644 (file)
@@ -199,7 +199,7 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
                     }
                 } else if (oldRow != null) {
                     if (inventoryListener != null) {
-                        inventoryListener.rowRemoved(n, name.getName(), uuid, oldRow);
+                        inventoryListener.rowRemoved(n, name.getName(), uuid, oldRow, null);
                     }
                     db.removeRow(name.getName(), uuid);
                 }
index 3dec8a53116bb9c6a6dc9198d368cbac055a412c..e0bdc1e4c135399d3a0cc3927d988a8e3e9edcb5 100644 (file)
@@ -17,5 +17,5 @@ public interface OVSDBInventoryListener {
     public void nodeRemoved(Node node);
     public void rowAdded(Node node, String tableName, String uuid, Table<?> row);
     public void rowUpdated(Node node, String tableName, String uuid, Table<?> old, Table<?> row);
-    public void rowRemoved(Node node, String tableName, String uuid, Table<?> row);
+    public void rowRemoved(Node node, String tableName, String uuid, Table<?> row, Object context);
 }