From 17f49cc8c3b0c8bb2caed8f5199c701ce5899cac Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Tue, 17 Dec 2013 02:32:23 -0800 Subject: [PATCH] Moved all Openflow 1.0 specific flow programming away from InternalNetworkManager to OF10ProviderManager class. Also, handled Switchmanager Node coming up event to take care of initializing the default flows. This is needed to handle timing issues in which the ForwardingRulesManager rejects request to program default flows from ovsdb.neutron if the request is too soon (before the OF node gets registered with other OSGi bundles). Change-Id: Id299c75146e504df63a45b77cc0f6be962c3abb6 Signed-off-by: Madhu Venugopal --- neutron/pom.xml | 6 + .../opendaylight/ovsdb/neutron/Activator.java | 3 +- .../ovsdb/neutron/InternalNetworkManager.java | 94 +-------------- .../ovsdb/neutron/SouthboundHandler.java | 19 ++- .../neutron/provider/OF10ProviderManager.java | 110 +++++++++++++++--- .../neutron/provider/OF13ProviderManager.java | 8 ++ .../provider/ProviderNetworkManager.java | 36 ++++++ 7 files changed, 166 insertions(+), 110 deletions(-) diff --git a/neutron/pom.xml b/neutron/pom.xml index fe00bb5ff..9102c9aae 100644 --- a/neutron/pom.xml +++ b/neutron/pom.xml @@ -31,6 +31,7 @@ org.opendaylight.controller.networkconfig.neutron, org.opendaylight.controller.containermanager, + org.opendaylight.controller.switchmanager, org.opendaylight.controller.forwardingrulesmanager, org.opendaylight.controller.sal.core, org.opendaylight.controller.sal.utils, @@ -58,6 +59,11 @@ 0.4.1-SNAPSHOT networkconfig.neutron + + org.opendaylight.controller + switchmanager + 0.7.0-SNAPSHOT + org.opendaylight.controller forwardingrulesmanager diff --git a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/Activator.java b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/Activator.java index e258346b3..984a335b9 100644 --- a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/Activator.java +++ b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/Activator.java @@ -19,6 +19,7 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD; import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetAware; import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD; import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase; +import org.opendaylight.controller.switchmanager.IInventoryListener; import org.opendaylight.ovsdb.plugin.OVSDBConfigService; import org.opendaylight.ovsdb.plugin.OVSDBInventoryListener; @@ -90,7 +91,7 @@ public class Activator extends ComponentActivatorAbstractBase { } if (imp.equals(SouthboundHandler.class)) { - c.setInterface(OVSDBInventoryListener.class.getName(), null); + c.setInterface(new String[] {OVSDBInventoryListener.class.getName(), IInventoryListener.class.getName()}, null); } c.add(createServiceDependency(). diff --git a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/InternalNetworkManager.java b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/InternalNetworkManager.java index cf6272dff..aced03c4b 100644 --- a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/InternalNetworkManager.java +++ b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/InternalNetworkManager.java @@ -9,17 +9,9 @@ */ package org.opendaylight.ovsdb.neutron; -import java.util.ArrayList; -import java.util.List; import java.util.Map; -import java.util.Set; -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; @@ -30,6 +22,7 @@ import org.opendaylight.ovsdb.lib.table.Bridge; import org.opendaylight.ovsdb.lib.table.Interface; import org.opendaylight.ovsdb.lib.table.Port; import org.opendaylight.ovsdb.lib.table.internal.Table; +import org.opendaylight.ovsdb.neutron.provider.ProviderNetworkManager; import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal; import org.opendaylight.ovsdb.plugin.OVSDBConfigService; import org.opendaylight.ovsdb.plugin.StatusWithUuid; @@ -200,95 +193,12 @@ public class InternalNetworkManager { return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, tunInterface); } - private void initializeOFNormalFlowRules(Node node, String bridgeName) { - String brIntId = this.getInternalBridgeUUID(node, bridgeName); - 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 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); - String flowName = ActionType.HW_PATH.toString(); - FlowConfig flow = new FlowConfig(); - flow.setName("NORMAL"); - flow.setNode(ofNode); - flow.setPriority(NORMAL_PRIORITY+""); - flow.setInstallInHw(true); - List normalAction = new ArrayList(); - normalAction.add(flowName); - flow.setActions(normalAction); - Status status = null; - if (frm.getStaticFlow(flowName, ofNode) == null) { - status = frm.addStaticFlow(flow); - logger.debug("Flow Programming Add Status {} for Flow {} on {} / {}", status, flow, ofNode, node); - } else { - status = frm.modifyStaticFlow(flow); - logger.debug("Flow Programming Modify Status {} for Flow {} on {} / {}", status, flow, ofNode, node); - } - } catch (Exception e) { - logger.error("Failed to initialize Flow Rules for {}", node, e); - } - } - - private void initializeLLDPFlowRules(Node node, String bridgeName) { - String brIntId = this.getInternalBridgeUUID(node, bridgeName); - 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 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); - String flowName = "PuntLLDP"; - List puntAction = new ArrayList(); - puntAction.add(ActionType.CONTROLLER.toString()); - - FlowConfig allowLLDP = new FlowConfig(); - allowLLDP.setInstallInHw(true); - 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 = null; - if (frm.getStaticFlow(flowName, ofNode) == null) { - status = frm.addStaticFlow(allowLLDP); - logger.debug("LLDP Flow Add Status {} for Flow {} on {} / {}", status, allowLLDP, ofNode, node); - } else { - status = frm.modifyStaticFlow(allowLLDP); - logger.debug("LLDP Flow Modify Status {} for Flow {} on {} / {}", status, allowLLDP, ofNode, node); - } - } catch (Exception e) { - logger.error("Failed to initialize Flow Rules for {}", node, e); - } - } - public void prepareInternalNetwork(Node node) { try { this.createInternalNetworkForOverlay(node); } catch (Exception e) { logger.error("Error creating internal network "+node.toString(), e); } - //Install NORMAL flows on all the bridges to make sure that we dont end up punting traffic to the OF Controller - this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName()); - this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getExternalBridgeName()); - this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName()); - this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName()); - this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName()); + ProviderNetworkManager.getManager().initializeFlowRules(node); } } diff --git a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundHandler.java b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundHandler.java index 9f410e5d3..7b3827246 100644 --- a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundHandler.java +++ b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundHandler.java @@ -18,6 +18,10 @@ import java.util.concurrent.LinkedBlockingQueue; import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork; import org.opendaylight.controller.sal.core.Node; +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.core.Property; +import org.opendaylight.controller.sal.core.UpdateType; +import org.opendaylight.controller.switchmanager.IInventoryListener; import org.opendaylight.ovsdb.lib.notation.UUID; import org.opendaylight.ovsdb.lib.table.Interface; import org.opendaylight.ovsdb.lib.table.Open_vSwitch; @@ -28,7 +32,7 @@ import org.opendaylight.ovsdb.plugin.OVSDBInventoryListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class SouthboundHandler extends BaseHandler implements OVSDBInventoryListener { +public class SouthboundHandler extends BaseHandler implements OVSDBInventoryListener, IInventoryListener { static final Logger logger = LoggerFactory.getLogger(SouthboundHandler.class); //private Thread eventThread; private ExecutorService eventHandler; @@ -232,4 +236,17 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList } return null; } + + @Override + public void notifyNode(Node node, UpdateType type, Map propMap) { + if (node.getType().equals(Node.NodeIDType.OPENFLOW) && type.equals(UpdateType.ADDED)) { + logger.debug("OpenFlow node {} added. Initialize Basic flows", node); + ProviderNetworkManager.getManager().initializeOFFlowRules(node); + } + } + + @Override + public void notifyNodeConnector(NodeConnector nodeConnector, UpdateType type, Map propMap) { + //We are not interested in the nodeConnectors at this moment + } } diff --git a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF10ProviderManager.java b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF10ProviderManager.java index f5885bc4d..88f04c316 100644 --- a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF10ProviderManager.java +++ b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF10ProviderManager.java @@ -21,10 +21,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; @@ -85,30 +88,24 @@ 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 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 actions = new ArrayList(); 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); @@ -137,15 +134,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+""); @@ -154,7 +146,7 @@ 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); @@ -443,6 +435,92 @@ class OF10ProviderManager extends ProviderNetworkManager { return new Status(StatusCode.SUCCESS); } + @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) { + 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 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 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); + 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 normalAction = new ArrayList(); + 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 puntAction = new ArrayList(); + 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 class NodeVlan { Node node; int vlan; diff --git a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF13ProviderManager.java b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF13ProviderManager.java index 998915c10..d1e98732c 100644 --- a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF13ProviderManager.java +++ b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF13ProviderManager.java @@ -31,4 +31,12 @@ class OF13ProviderManager extends ProviderNetworkManager { // TODO Auto-generated method stub return null; } + + @Override + public void initializeFlowRules(Node node) { + } + + @Override + public void initializeOFFlowRules(Node openflowNode) { + } } diff --git a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/ProviderNetworkManager.java b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/ProviderNetworkManager.java index 76d64caf0..df5e50a06 100644 --- a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/ProviderNetworkManager.java +++ b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/ProviderNetworkManager.java @@ -9,15 +9,24 @@ */ package org.opendaylight.ovsdb.neutron.provider; +import java.util.Map; + import org.opendaylight.controller.sal.core.Node; +import org.opendaylight.controller.sal.utils.ServiceHelper; import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.ovsdb.lib.table.Bridge; import org.opendaylight.ovsdb.lib.table.Interface; +import org.opendaylight.ovsdb.lib.table.internal.Table; +import org.opendaylight.ovsdb.plugin.OVSDBConfigService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class ProviderNetworkManager { static final Logger logger = LoggerFactory.getLogger(ProviderNetworkManager.class); private static ProviderNetworkManager provider; + protected static final int LLDP_PRIORITY = 1000; + protected static final int NORMAL_PRIORITY = 0; + public static ProviderNetworkManager getManager() { if (provider != null) return provider; @@ -29,7 +38,34 @@ public abstract class ProviderNetworkManager { return provider; } + protected String getInternalBridgeUUID (Node node, String bridgeName) { + try { + OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this); + Map> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName()); + if (bridgeTable == null) return null; + for (String key : bridgeTable.keySet()) { + Bridge bridge = (Bridge)bridgeTable.get(key); + if (bridge.getName().equals(bridgeName)) return key; + } + } catch (Exception e) { + logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e); + } + return null; + } + public abstract boolean hasPerTenantTunneling(); public abstract Status createTunnels(String tunnelType, String tunnelKey); public abstract Status createTunnels(String tunnelType, String tunnelKey, Node source, Interface intf); + /* + * Initialize the Flow rules given the OVSDB node. + * This method provides a set of common functionalities to initialize the Flow rules of an OVSDB node + * that are Openflow Version specific. Hence we have this method in addition to the following + * Openflow Node specific initialization method. + */ + public abstract void initializeFlowRules(Node node); + + /* + * Initialize the Flow rules given the Openflow node + */ + public abstract void initializeOFFlowRules(Node openflowNode); } -- 2.36.6