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 <mavenugo@gmail.com>
<Import-Package>
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,
<version>0.4.1-SNAPSHOT</version>
<artifactId>networkconfig.neutron</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>switchmanager</artifactId>
+ <version>0.7.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>forwardingrulesmanager</artifactId>
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;
}
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().
*/
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;
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;
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<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);
- 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 = 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<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);
- String flowName = "PuntLLDP";
- List<String> puntAction = new ArrayList<String>();
- 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);
}
}
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;
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;
}
return null;
}
+
+ @Override
+ public void notifyNode(Node node, UpdateType type, Map<String, Property> 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<String, Property> propMap) {
+ //We are not interested in the nodeConnectors at this moment
+ }
}
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;
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);
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+"");
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);
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<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);
+ 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 class NodeVlan {
Node node;
int vlan;
// TODO Auto-generated method stub
return null;
}
+
+ @Override
+ public void initializeFlowRules(Node node) {
+ }
+
+ @Override
+ public void initializeOFFlowRules(Node openflowNode) {
+ }
}
*/
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;
return provider;
}
+ protected String getInternalBridgeUUID (Node node, String bridgeName) {
+ try {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ Map<String, Table<?>> 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);
}