Internal Vlan deletion and Tunnel Deletion cleanup
[ovsdb.git] / neutron / src / main / java / org / opendaylight / ovsdb / neutron / provider / OF10ProviderManager.java
index d36aea97ed2dc82d315602ea370276c5e5b6fb95..cf3743e4ad00a1c70868efd97a63db90bb14c42e 100644 (file)
@@ -1,9 +1,17 @@
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Authors : Madhu Venugopal, Brent Salisbury
+ */
 package org.opendaylight.ovsdb.neutron.provider;
 
 import java.math.BigInteger;
 import java.net.InetAddress;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -12,10 +20,13 @@ import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
 import org.opendaylight.controller.sal.action.ActionType;
 import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.EtherTypes;
 import org.opendaylight.controller.sal.utils.HexEncode;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.controller.switchmanager.ISwitchManager;
+import org.opendaylight.controller.switchmanager.Switch;
 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
 import org.opendaylight.ovsdb.lib.notation.UUID;
@@ -35,7 +46,6 @@ import org.slf4j.LoggerFactory;
 
 class OF10ProviderManager extends ProviderNetworkManager {
     private static final Logger logger = LoggerFactory.getLogger(OF10ProviderManager.class);
-    Map<NodeVlan, FlowConfig> floodEntries = new HashMap<NodeVlan, FlowConfig>();
     private static final int INGRESS_TUNNEL_FLOW_PRIORITY = 100;
     private static final int EGRESS_TUNNEL_FLOW_PRIORITY = 100;
     private static final int FLOOD_TUNNEL_FLOW_PRIORITY = 1;
@@ -53,7 +63,7 @@ class OF10ProviderManager extends ProviderNetworkManager {
         }
 
         if (!InternalNetworkManager.getManager().isInternalNetworkOverlayReady(node)) {
-            logger.error(node+" is not Overlay ready");
+            logger.warn("{} is not Overlay ready. It might be an OpenStack Controller Node", node);
             return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
         }
 
@@ -76,36 +86,52 @@ class OF10ProviderManager extends ProviderNetworkManager {
             return;
         }
         try {
-            String flowName = "TepMatch"+tunnelOFPort+""+internalVlan;
             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
             Set<String> dpids = bridge.getDatapath_id();
             if (dpids == null || dpids.size() ==  0) return;
             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
-            IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
-                    IForwardingRulesManager.class, "default", this);
-            if (frm.getStaticFlow(flowName, ofNode) != null) {
-                logger.debug("Local Ingress Flow exists : {} for Flow {} on {} / {}", flowName, ofNode, node);
-                return;
-            }
-
+            String flowName = "TepMatch"+tunnelOFPort+""+internalVlan;
             FlowConfig flow = new FlowConfig();
             flow.setName(flowName);
             flow.setNode(ofNode);
+            flow.setInstallInHw(true);
             flow.setPriority(INGRESS_TUNNEL_FLOW_PRIORITY+"");
             flow.setIngressPort(tunnelOFPort+"");
             List<String> actions = new ArrayList<String>();
             actions.add(ActionType.SET_VLAN_ID+"="+internalVlan);
             actions.add(ActionType.OUTPUT.toString()+"="+patchPort);
             flow.setActions(actions);
-            Status status = frm.addStaticFlow(flow);
+            Status status = this.addStaticFlow(ofNode, flow);
             logger.debug("Local Ingress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
         } catch (Exception e) {
             logger.error("Failed to initialize Flow Rules for {}", node, e);
         }
     }
 
+    private void removeLocalIngressTunnelBridgeRules(Node node, int tunnelOFPort, int internalVlan, int patchPort) {
+        String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
+        if (brIntId == null) {
+            logger.error("Failed to remove Flow Rules for {}", node);
+            return;
+        }
+        try {
+            OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+            Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
+            Set<String> dpids = bridge.getDatapath_id();
+            if (dpids == null || dpids.size() ==  0) return;
+            Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
+            Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
+            String flowName = "TepMatch"+tunnelOFPort+""+internalVlan;
+
+            Status status = this.deleteStaticFlow(ofNode, flowName);
+            logger.debug("Local Ingress Flow Removal Status {} for Flow {} on {} / {}", status, flowName, ofNode, node);
+        } catch (Exception e) {
+            logger.error("Failed to Remove Flow Rules for {}", node, e);
+        }
+    }
+
     /**
      * Program OF1.0 Flow rules on br-tun on the remote Node on its egress direction towards the overlay network
      * for a VM (with the attachedMac).
@@ -128,15 +154,10 @@ class OF10ProviderManager extends ProviderNetworkManager {
             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
             String flowName = "TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac);
-            IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
-                    IForwardingRulesManager.class, "default", this);
-            if (frm.getStaticFlow(flowName, ofNode) != null) {
-                logger.debug("Remote Egress Flow exists : {} for Flow {} on {} / {}", flowName, ofNode, node);
-                return;
-            }
             FlowConfig flow = new FlowConfig();
             flow.setName(flowName);
             flow.setNode(ofNode);
+            flow.setInstallInHw(true);
             flow.setPriority(EGRESS_TUNNEL_FLOW_PRIORITY+"");
             flow.setDstMac(attachedMac);
             flow.setIngressPort(patchPort+"");
@@ -145,13 +166,35 @@ class OF10ProviderManager extends ProviderNetworkManager {
             actions.add(ActionType.POP_VLAN.toString());
             actions.add(ActionType.OUTPUT.toString()+"="+tunnelOFPort);
             flow.setActions(actions);
-            Status status = frm.addStaticFlow(flow);
+            Status status = this.addStaticFlow(ofNode, flow);
             logger.debug("Remote Egress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
         } catch (Exception e) {
             logger.error("Failed to initialize Flow Rules for {}", node, e);
         }
     }
 
+    private void removeRemoteEgressTunnelBridgeRules(Node node, int patchPort, String attachedMac,
+            int internalVlan, int tunnelOFPort) {
+        String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
+        if (brIntId == null) {
+            logger.error("Failed to initialize Flow Rules for {}", node);
+            return;
+        }
+        try {
+            OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+            Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
+            Set<String> dpids = bridge.getDatapath_id();
+            if (dpids == null || dpids.size() ==  0) return;
+            Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
+            Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
+            String flowName = "TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac);
+            Status status = this.deleteStaticFlow(ofNode, flowName);
+            logger.debug("Remote Egress Flow Removal Status {} for Flow {} on {} / {}", status, flowName, ofNode, node);
+        } catch (Exception e) {
+            logger.error("Failed to Remove Flow Rules for {}", node, e);
+        }
+    }
+
     /**
      * Program OF1.0 Flow rules to flood the broadcast & unknown-unicast traffic over br-tun on the egress direction
      * towards the network on all the overlay tunnels that corresponds to the tenant network.
@@ -172,15 +215,15 @@ class OF10ProviderManager extends ProviderNetworkManager {
             if (dpids == null || dpids.size() ==  0) return;
             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
-            NodeVlan nv = new NodeVlan(ofNode, internalVlan);
-            FlowConfig existingFlowConfig = floodEntries.get(nv);
+            String flowName = "TepFlood"+internalVlan;
             IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
                     IForwardingRulesManager.class, "default", this);
+            FlowConfig existingFlowConfig = frm.getStaticFlow(flowName, ofNode);
             FlowConfig flow = existingFlowConfig;
             Status status = null;
             if (flow == null) {
                 flow = new FlowConfig();
-                flow.setName("TepFlood"+internalVlan);
+                flow.setName(flowName);
                 flow.setNode(ofNode);
                 flow.setPriority(FLOOD_TUNNEL_FLOW_PRIORITY+"");
                 flow.setIngressPort(patchPort+"");
@@ -200,21 +243,52 @@ class OF10ProviderManager extends ProviderNetworkManager {
                     actions.add(outputPort);
                     flow.setActions(actions);
                 } else {
+                    logger.debug("Flood Egress Flow already exists. Skipping modify for Flow {} on {} / {}",
+                                 flow, ofNode, node);
                     return;
                 }
                 status = frm.modifyStaticFlow(flow);
                 logger.debug("Modify Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
                               status, flow, ofNode, node);
             }
-            if (status.isSuccess()) {
-                floodEntries.put(nv, flow);
-            }
-
         } catch (Exception e) {
             logger.error("Failed to initialize Flow Rules for {}", node, e);
         }
     }
 
+    private void removeFloodEgressTunnelBridgeRules(Node node, int patchPort, int internalVlan, int tunnelOFPort) {
+        String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
+        if (brIntId == null) {
+            logger.error("Failed to remove Flow Rules for {}", node);
+            return;
+        }
+        try {
+            OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+            Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
+            Set<String> dpids = bridge.getDatapath_id();
+            if (dpids == null || dpids.size() ==  0) return;
+            Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
+            Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
+            String flowName = "TepFlood"+internalVlan;
+            IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
+                    IForwardingRulesManager.class, "default", this);
+            FlowConfig flow = frm.getStaticFlow(flowName, ofNode);
+            Status status = null;
+            if (flow != null) {
+                status = frm.removeStaticFlow(flowName, ofNode);
+                logger.debug("Remove Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
+                              status, flow, ofNode, node);
+
+            } else {
+                logger.debug("Flood Egress Flow already removed. Skipping removal for Flow {} on {} / {}",
+                             flow, ofNode, node);
+                return;
+            }
+        } catch (Exception e) {
+            logger.error("Failed to remove Flow Rules for {}", node, e);
+        }
+    }
+
     private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
                                      Interface intf, boolean local) {
         String networkId = TenantNetworkManager.getManager().getNetworkIdForSegmentationId(segmentationId);
@@ -222,7 +296,7 @@ class OF10ProviderManager extends ProviderNetworkManager {
             logger.debug("Tenant Network not found with Segmenation-id {}",segmentationId);
             return;
         }
-        int internalVlan = TenantNetworkManager.getManager().getInternalVlan(networkId);
+        int internalVlan = TenantNetworkManager.getManager().getInternalVlan(node, networkId);
         if (internalVlan == 0) {
             logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
             return;
@@ -266,13 +340,13 @@ class OF10ProviderManager extends ProviderNetworkManager {
                     if (tunIntf.getName().equals(this.getTunnelName(tunnelType, segmentationId, dst))) {
                         Set<BigInteger> of_ports = tunIntf.getOfport();
                         if (of_ports == null || of_ports.size() <= 0) {
-                            logger.error("Could NOT Identify Tunnel port {} on {}", tunIntf.getName(), node);
+                            logger.warn("Could not Identify Tunnel port {} on {}. Don't panic. It might get converged soon...", tunIntf.getName(), node);
                             continue;
                         }
                         int tunnelOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
 
                         if (tunnelOFPort == -1) {
-                            logger.error("Could NOT Identify Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
+                            logger.warn("Tunnel Port {} on node {}: OFPort = -1 . Don't panic. It might get converged soon...", tunIntf.getName(), node);
                             return;
                         }
                         logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
@@ -291,8 +365,84 @@ class OF10ProviderManager extends ProviderNetworkManager {
         }
     }
 
+    private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
+            Interface intf, boolean local) {
+        String networkId = TenantNetworkManager.getManager().getNetworkIdForSegmentationId(segmentationId);
+        if (networkId == null) {
+            logger.debug("Tenant Network not found with Segmenation-id {}",segmentationId);
+            return;
+        }
+        int internalVlan = TenantNetworkManager.getManager().getInternalVlan(node,networkId);
+        if (internalVlan == 0) {
+            logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
+            return;
+        }
+        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;
+        }
+        String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
+
+        int patchOFPort = -1;
+        try {
+            OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+            Map<String, Table<?>> intfs = ovsdbTable.getRows(node, Interface.NAME.getName());
+            if (intfs != null) {
+                for (Table<?> row : intfs.values()) {
+                    Interface patchIntf = (Interface)row;
+                    if (patchIntf.getName().equalsIgnoreCase(patchInt)) {
+                        Set<BigInteger> of_ports = patchIntf.getOfport();
+                        if (of_ports == null || of_ports.size() <= 0) {
+                            logger.error("Could NOT Identified Patch port {} on {}", patchInt, node);
+                            continue;
+                        }
+                        patchOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
+                        logger.debug("Identified Patch port {} -> OF ({}) on {}", patchInt, patchOFPort, node);
+                        break;
+                    }
+                }
+                if (patchOFPort == -1) {
+                    logger.error("Cannot identify {} interface on {}", patchInt, node);
+                }
+                for (Table<?> row : intfs.values()) {
+                    Interface tunIntf = (Interface)row;
+                    if (tunIntf.getName().equals(this.getTunnelName(tunnelType, segmentationId, dst))) {
+                        Set<BigInteger> of_ports = tunIntf.getOfport();
+                        if (of_ports == null || of_ports.size() <= 0) {
+                            logger.error("Could NOT Identify Tunnel port {} on {}", tunIntf.getName(), node);
+                            continue;
+                        }
+                        int tunnelOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
+
+                        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, patchOFPort, attachedMac, internalVlan, tunnelOFPort);
+                        }
+                        removeLocalIngressTunnelBridgeRules(node, tunnelOFPort, internalVlan, patchOFPort);
+                        removeFloodEgressTunnelBridgeRules(node, patchOFPort, internalVlan, tunnelOFPort);
+                        return;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("", e);
+        }
+    }
+
     @Override
-    public Status createTunnels(String tunnelType, String tunnelKey, Node srcNode, Interface intf) {
+    public Status handleInterfaceUpdate(String tunnelType, String tunnelKey, Node srcNode, Interface intf) {
         Status status = getTunnelReadinessStatus(srcNode, tunnelKey);
         if (!status.isSuccess()) return status;
 
@@ -316,6 +466,28 @@ class OF10ProviderManager extends ProviderNetworkManager {
         return new Status(StatusCode.SUCCESS);
     }
 
+    @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);
+            }
+            this.removeTunnelRules(tunnelType, tunnelKey, src, dstNode, intf, false);
+            if (status.isSuccess() && isLastInstanceOnNode) {
+                deleteTunnelPort(dstNode, tunnelType, dst, src, tunnelKey);
+            }
+        }
+        return status;
+    }
+
     private String getTunnelName(String tunnelType, String key, InetAddress dst) {
         return tunnelType+"-"+key+"-"+dst.getHostAddress();
     }
@@ -352,6 +524,19 @@ class OF10ProviderManager extends ProviderNetworkManager {
         return false;
     }
 
+    private String getTunnelPortUuid(Node node, String tunnelName, 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(tunnelName)) return portUUID.toString();
+            }
+        }
+        return null;
+    }
+
     private Status addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
         try {
             String bridgeUUID = null;
@@ -424,59 +609,149 @@ class OF10ProviderManager extends ProviderNetworkManager {
         }
     }
 
+    private Status deleteTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
+        try {
+            String bridgeUUID = null;
+            String tunnelBridgeName = AdminConfigManager.getManager().getTunnelBridgeName();
+            OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+            Map<String, 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(tunnelBridgeName)) {
+                        bridgeUUID = uuid;
+                        break;
+                    }
+                }
+            }
+            if (bridgeUUID == null) {
+                logger.debug("Could not find Bridge {} in {}", tunnelBridgeName, node);
+                return new Status(StatusCode.SUCCESS);
+            }
+            String portName = getTunnelName(tunnelType, key, dst);
+            String tunnelPortUUID = this.getTunnelPortUuid(node, portName, bridgeUUID);
+            Status status = ovsdbTable.deleteRow(node, Port.NAME.getName(), tunnelPortUUID);
+            if (!status.isSuccess()) {
+                logger.error("Failed to delete Tunnel port {} in {} status : {}", portName, bridgeUUID, status);
+                return status;
+            }
+
+            logger.debug("Tunnel {} delete status : {}", portName, status);
+            return status;
+        } catch (Exception e) {
+            logger.error("Exception in deleteTunnelPort", e);
+            return new Status(StatusCode.INTERNALERROR);
+        }
+    }
+
     @Override
-    public Status createTunnels(String tunnelType, String tunnelKey) {
+    public Status handleInterfaceUpdate(String tunnelType, String tunnelKey) {
         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
         List<Node> nodes = connectionService.getNodes();
         for (Node srcNode : nodes) {
-            this.createTunnels(tunnelType, tunnelKey, srcNode, null);
+            this.handleInterfaceUpdate(tunnelType, tunnelKey, srcNode, null);
         }
         return new Status(StatusCode.SUCCESS);
     }
 
-    private class NodeVlan {
-        Node node;
-        int vlan;
-        public NodeVlan(Node node, int vlan) {
-            super();
-            this.node = node;
-            this.vlan = vlan;
-        }
-        public Node getNode() {
-            return node;
-        }
-        public int getVlan() {
-            return vlan;
-        }
-        @Override
-        public String toString() {
-            return "NodeVlan [node=" + node + ", vlan=" + vlan + "]";
-        }
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((node == null) ? 0 : node.hashCode());
-            result = prime * result + vlan;
-            return result;
-        }
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj)
-                return true;
-            if (obj == null)
-                return false;
-            if (getClass() != obj.getClass())
-                return false;
-            NodeVlan other = (NodeVlan) obj;
-            if (node == null) {
-                if (other.node != null)
-                    return false;
-            } else if (!node.equals(other.node))
-                return false;
-            if (vlan != other.vlan)
-                return false;
-            return true;
+    @Override
+    public void initializeFlowRules(Node node) {
+        this.initializeFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
+        this.initializeFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
+        this.initializeFlowRules(node, AdminConfigManager.getManager().getExternalBridgeName());
+    }
+
+    private void initializeFlowRules(Node node, String bridgeName) {
+        String brIntId = this.getInternalBridgeUUID(node, bridgeName);
+        if (brIntId == null) {
+            if (bridgeName == AdminConfigManager.getManager().getExternalBridgeName()){
+                logger.debug("Failed to initialize Flow Rules for bridge {} on node {}. Is the Neutron L3 agent running on this node?");
+            }
+            else {
+                logger.debug("Failed to initialize Flow Rules for bridge {} on node {}", bridgeName, node);
+            }
+            return;
+        }
+
+        try {
+            OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+            Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
+            Set<String> dpids = bridge.getDatapath_id();
+            if (dpids == null || dpids.size() ==  0) return;
+            Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
+            Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
+            ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, "default", this);
+            List<Switch> nodes = switchManager.getNetworkDevices();
+            if (nodes == null) {
+                logger.debug("No OF nodes learned yet in {}", node);
+                return;
+            }
+            for (Switch device : nodes) {
+                if (device.getNode().equals(ofNode)) {
+                    logger.debug("Initialize OF Flows on {}", ofNode);
+                    initializeNormalFlowRules(ofNode);
+                    return;
+                }
+            }
+            logger.debug("Could not identify OF node {} for bridge {} in {}", ofNode.toString(), bridgeName, node.toString());
+        } catch (Exception e) {
+            logger.error("Failed to initialize Flow Rules for "+node.toString(), e);
+        }
+    }
+
+    @Override
+    public void initializeOFFlowRules(Node openflowNode) {
+        this.initializeNormalFlowRules(openflowNode);
+        this.initializeLLDPFlowRules(openflowNode);
+    }
+
+    private void initializeNormalFlowRules(Node ofNode) {
+        String flowName = ActionType.HW_PATH.toString();
+        FlowConfig flow = new FlowConfig();
+        flow.setName("NORMAL");
+        flow.setNode(ofNode);
+        flow.setPriority(NORMAL_PRIORITY+"");
+        flow.setInstallInHw(true);
+        List<String> normalAction = new ArrayList<String>();
+        normalAction.add(flowName);
+        flow.setActions(normalAction);
+        Status status = this.addStaticFlow(ofNode, flow);
+        logger.debug("Flow Programming Add Status {} for Flow {} on {}", status, flow, ofNode);
+    }
+
+    private void initializeLLDPFlowRules(Node ofNode) {
+        String flowName = "PuntLLDP";
+        List<String> puntAction = new ArrayList<String>();
+        puntAction.add(ActionType.CONTROLLER.toString());
+
+        FlowConfig allowLLDP = new FlowConfig();
+        allowLLDP.setName(flowName);
+        allowLLDP.setPriority(LLDP_PRIORITY+"");
+        allowLLDP.setNode(ofNode);
+        allowLLDP.setInstallInHw(true);
+        allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue()).toUpperCase());
+        allowLLDP.setActions(puntAction);
+        Status status = this.addStaticFlow(ofNode, allowLLDP);
+        logger.debug("LLDP Flow Add Status {} for Flow {} on {}", status, allowLLDP, ofNode);
+    }
+
+    private Status addStaticFlow (Node ofNode, FlowConfig flowConfig) {
+        IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
+                IForwardingRulesManager.class, "default", this);
+        String flowName = flowConfig.getName();
+        if (frm.getStaticFlow(flowName, ofNode) != null) {
+            logger.debug("Flow already exists {} on {}. Skipping installation.", flowName, ofNode);
+            return new Status(StatusCode.CONFLICT, "Flow with name "+flowName+" exists in node "+ofNode.toString());
         }
+        return frm.addStaticFlow(flowConfig);
     }
-}
+
+    private Status deleteStaticFlow (Node ofNode, String flowName) {
+        IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
+                IForwardingRulesManager.class, "default", this);
+        if (frm.getStaticFlow(flowName, ofNode) == null) {
+            logger.debug("Flow doese not exist {} on {}. Skipping deletion.", flowName, ofNode);
+            return new Status(StatusCode.SUCCESS);
+        }
+        return frm.removeStaticFlow(flowName,ofNode);
+    }}