Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
diff --git a/of/api/pom.xml b/of/api/pom.xml
index 8f123e1..050fedd 100644
--- a/of/api/pom.xml
+++ b/of/api/pom.xml
@@ -63,7 +63,7 @@
<configuration>
<instructions>
<Export-Package>
- org.projectfloodlight.openflow.*
+ org.onlab.onos.of.*,org.projectfloodlight.openflow.*
</Export-Package>
</instructions>
</configuration>
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/DeleteMe.java b/of/api/src/main/java/org/onlab/onos/of/controller/DeleteMe.java
deleted file mode 100644
index 1db6eae..0000000
--- a/of/api/src/main/java/org/onlab/onos/of/controller/DeleteMe.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.onlab.onos.of.controller;
-
-/**
- * Created by tom on 8/21/14.
- */
-public interface DeleteMe {
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/Dpid.java b/of/api/src/main/java/org/onlab/onos/of/controller/Dpid.java
similarity index 96%
rename from of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/Dpid.java
rename to of/api/src/main/java/org/onlab/onos/of/controller/Dpid.java
index dec8424..02a957e 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/Dpid.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/Dpid.java
@@ -1,4 +1,4 @@
-package org.onlab.onos.of.controller.impl.util;
+package org.onlab.onos.of.controller;
import org.projectfloodlight.openflow.util.HexString;
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowController.java b/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowController.java
new file mode 100644
index 0000000..5aec885
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowController.java
@@ -0,0 +1,100 @@
+package org.onlab.onos.of.controller;
+
+import org.projectfloodlight.openflow.protocol.OFMessage;
+
+/**
+ * Abstraction of an OpenFlow controller. Serves as a one stop
+ * shop for obtaining OpenFlow devices and (un)register listeners
+ * on OpenFlow events
+ */
+public interface OpenFlowController {
+
+ /**
+ * Returns all switches known to this OF controller.
+ * @return Iterable of dpid elements
+ */
+ public Iterable<OpenFlowSwitch> getSwitches();
+
+ /**
+ * Returns all master switches known to this OF controller.
+ * @return Iterable of dpid elements
+ */
+ public Iterable<OpenFlowSwitch> getMasterSwitches();
+
+ /**
+ * Returns all equal switches known to this OF controller.
+ * @return Iterable of dpid elements
+ */
+ public Iterable<OpenFlowSwitch> getEqualSwitches();
+
+
+ /**
+ * Returns the actual switch for the given Dpid.
+ * @param dpid the switch to fetch
+ * @return the interface to this switch
+ */
+ public OpenFlowSwitch getSwitch(Dpid dpid);
+
+ /**
+ * Returns the actual master switch for the given Dpid, if one exists.
+ * @param dpid the switch to fetch
+ * @return the interface to this switch
+ */
+ public OpenFlowSwitch getMasterSwitch(Dpid dpid);
+
+ /**
+ * Returns the actual equal switch for the given Dpid, if one exists.
+ * @param dpid the switch to fetch
+ * @return the interface to this switch
+ */
+ public OpenFlowSwitch getEqualSwitch(Dpid dpid);
+
+ /**
+ * Register a listener for meta events that occur to OF
+ * devices.
+ * @param listener the listener to notify
+ */
+ public void addListener(OpenFlowSwitchListener listener);
+
+ /**
+ * Unregister a listener.
+ *
+ * @param listener the listener to unregister
+ */
+ public void removeListener(OpenFlowSwitchListener listener);
+
+ /**
+ * Register a listener for packet events.
+ * @param priority the importance of this listener, lower values are more important
+ * @param listener the listener to notify
+ */
+ public void addPacketListener(int priority, PacketListener listener);
+
+ /**
+ * Unregister a listener.
+ *
+ * @param listener the listener to unregister
+ */
+ public void removePacketListener(PacketListener listener);
+
+ /**
+ * Send a message to a particular switch.
+ * @param dpid the switch to send to.
+ * @param msg the message to send
+ */
+ public void write(Dpid dpid, OFMessage msg);
+
+ /**
+ * Process a message and notify the appropriate listeners.
+ *
+ * @param msg the message to process.
+ */
+ public void processPacket(OFMessage msg);
+
+ /**
+ * Sets the role for a given switch.
+ * @param role the desired role
+ * @param dpid the switch to set the role for.
+ */
+ public void setRole(Dpid dpid, RoleState role);
+}
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitch.java b/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitch.java
new file mode 100644
index 0000000..e6f52bd
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitch.java
@@ -0,0 +1,23 @@
+package org.onlab.onos.of.controller;
+
+import org.projectfloodlight.openflow.protocol.OFMessage;
+
+/**
+ * Abstract model of an OpenFlow Switch.
+ *
+ */
+public interface OpenFlowSwitch {
+
+ /**
+ * Writes the message to this switch.
+ *
+ * @param msg the message to write
+ */
+ public void write(OFMessage msg);
+
+ /**
+ * Handle a message from the switch.
+ * @param fromSwitch the message to handle
+ */
+ public void handleMessage(OFMessage fromSwitch);
+}
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitchEvent.java b/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitchEvent.java
new file mode 100644
index 0000000..281d505
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitchEvent.java
@@ -0,0 +1,17 @@
+package org.onlab.onos.of.controller;
+
+/**
+ * Meta events that can happen at a switch.
+ *
+ */
+public enum OpenFlowSwitchEvent {
+ /**
+ * The switch connected.
+ */
+ SWITCH_CONNECTED,
+
+ /**
+ * The switch disconnected.
+ */
+ SWITCH_DISCONNECTED
+}
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitchListener.java b/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitchListener.java
new file mode 100644
index 0000000..7ccba6d
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitchListener.java
@@ -0,0 +1,20 @@
+package org.onlab.onos.of.controller;
+
+/**
+ * Allows for providers interested in Switch events to be notified.
+ */
+public interface OpenFlowSwitchListener {
+
+ /**
+ * Notify that the switch was added.
+ * @param dpid the switch where the event occurred
+ */
+ public void switchAdded(Dpid dpid);
+
+ /**
+ * Notify that the switch was removed.
+ * @param dpid the switch where the event occurred.
+ */
+ public void switchRemoved(Dpid dpid);
+
+}
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/PacketContext.java b/of/api/src/main/java/org/onlab/onos/of/controller/PacketContext.java
new file mode 100644
index 0000000..bc06e93
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/PacketContext.java
@@ -0,0 +1,50 @@
+package org.onlab.onos.of.controller;
+
+import org.projectfloodlight.openflow.types.OFPort;
+
+/**
+ * A representation of a packet context which allows any provider
+ * to view the packet in event but may block the response to the
+ * event if blocked has been called.
+ */
+public interface PacketContext {
+
+ //TODO: may want to support sending packet out other switches than
+ // the one it came in on.
+ /**
+ * Blocks further responses (ie. send() calls) on this
+ * packet in event.
+ */
+ public void block();
+
+ /**
+ * Provided build has been called send the packet
+ * out the switch it came in on.
+ */
+ public void send();
+
+ /**
+ * Build the packet out in response to this packet in event.
+ * @param outPort the out port to send to packet out of.
+ */
+ public void build(OFPort outPort);
+
+ /**
+ * Build the packet out in response to this packet in event.
+ * @param ethFrame the actual packet to send out.
+ * @param outPort the out port to send to packet out of.
+ */
+ public void build(Object ethFrame, OFPort outPort);
+
+ /**
+ * Provided a handle onto the parsed payload.
+ * @return the parsed form of the payload.
+ */
+ public Object parsed();
+
+ /**
+ * Provide the dpid of the switch where the packet in arrived.
+ * @return the dpid of the switch.
+ */
+ public Dpid dpid();
+}
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/PacketListener.java b/of/api/src/main/java/org/onlab/onos/of/controller/PacketListener.java
new file mode 100644
index 0000000..5c6d73f
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/PacketListener.java
@@ -0,0 +1,13 @@
+package org.onlab.onos.of.controller;
+
+/**
+ * Notifies providers about Packet in events.
+ */
+public interface PacketListener {
+
+ /**
+ * Handle the packet.
+ * @param pktCtx the packet context ({@link }
+ */
+ public void handlePacket(PacketContext pktCtx);
+}
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/RoleState.java b/of/api/src/main/java/org/onlab/onos/of/controller/RoleState.java
new file mode 100644
index 0000000..527a91c
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/RoleState.java
@@ -0,0 +1,23 @@
+package org.onlab.onos.of.controller;
+
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+
+/**
+ * The role of the controller as it pertains to a particular switch.
+ * Note that this definition of the role enum is different from the
+ * OF1.3 definition. It is maintained here to be backward compatible to
+ * earlier versions of the controller code. This enum is translated
+ * to the OF1.3 enum, before role messages are sent to the switch.
+ * See sendRoleRequestMessage method in OFSwitchImpl
+ */
+public enum RoleState {
+ EQUAL(OFControllerRole.ROLE_EQUAL),
+ MASTER(OFControllerRole.ROLE_MASTER),
+ SLAVE(OFControllerRole.ROLE_SLAVE);
+
+ private RoleState(OFControllerRole nxRole) {
+ nxRole.ordinal();
+ }
+
+}
+
diff --git a/of/ctl/pom.xml b/of/ctl/pom.xml
index 5c090cb..88bdcd9 100644
--- a/of/ctl/pom.xml
+++ b/of/ctl/pom.xml
@@ -38,6 +38,10 @@
</properties>
<dependencies>
+ <dependency>
+ <groupId>org.onlab.onos</groupId>
+ <artifactId>onos-of-api</artifactId>
+ </dependency>
<!-- ONOS's direct dependencies -->
<dependency>
<groupId>org.apache.felix</groupId>
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/IOFSwitch.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/IOFSwitch.java
deleted file mode 100644
index afa3703..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/IOFSwitch.java
+++ /dev/null
@@ -1,584 +0,0 @@
-/**
- * Copyright 2011, Big Switch Networks, Inc.
- * Originally created by David Erickson, Stanford University
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- **/
-
-package org.onlab.onos.of.controller.impl;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Future;
-
-import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService;
-import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService.CounterException;
-import org.onlab.onos.of.controller.impl.util.OrderedCollection;
-
-import org.jboss.netty.channel.Channel;
-import org.projectfloodlight.openflow.protocol.OFActionType;
-import org.projectfloodlight.openflow.protocol.OFCapabilities;
-import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFPortStatus;
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.projectfloodlight.openflow.types.U64;
-
-
-public interface IOFSwitch {
-
- /**
- * OF1.3 switches should support role-request messages as in the 1.3 spec.
- * OF1.0 switches may or may not support the Nicira role request extensions.
- * To indicate the support, this property should be set by the associated
- * OF1.0 switch driver in the net.onrc.onos.core.drivermanager package.
- * The property will be ignored for OF1.3 switches.
- */
- public static final String SWITCH_SUPPORTS_NX_ROLE = "supportsNxRole";
-
-
- //************************
- // Channel related
- //************************
-
- /**
- * Disconnects the switch by closing the TCP connection. Results in a call
- * to the channel handler's channelDisconnected method for cleanup
- * @throws IOException
- */
- public void disconnectSwitch();
-
- /**
- * Writes to the OFMessage to the output stream.
- *
- * @param m
- * @throws IOException
- */
- public void write(OFMessage m) throws IOException;
-
- /**
- * Writes the list of messages to the output stream.
- *
- * @param msglist
- * @throws IOException
- */
- public void write(List<OFMessage> msglist) throws IOException;
-
- /**
- * Gets the date the switch connected to this controller.
- *
- * @return the date
- */
- public Date getConnectedSince();
-
- /**
- * Gets the next available transaction id.
- *
- * @return the next transaction ID
- */
- public int getNextTransactionId();
-
- /**
- * Checks if the switch is still connected.
- * Only call while holding processMessageLock
- *
- * @return whether the switch is still disconnected
- */
- public boolean isConnected();
-
- /**
- * Sets whether the switch is connected.
- * Only call while holding modifySwitchLock
- *
- * @param connected whether the switch is connected
- */
- public void setConnected(boolean connected);
-
- /**
- * Flushes all flows queued for this switch in the current thread.
- * NOTE: The contract is limited to the current thread
- */
- public void flush();
-
- /**
- * Sets the Netty Channel this switch instance is associated with.
- * <p>
- * Called immediately after instantiation
- *
- * @param channel the channel
- */
- public void setChannel(Channel channel);
-
- //************************
- // Switch features related
- //************************
-
- /**
- * Gets the datapathId of the switch.
- *
- * @return the switch buffers
- */
- public long getId();
-
- /**
- * Gets a string version of the ID for this switch.
- *
- * @return string version of the ID
- */
- public String getStringId();
-
- /**
- * Gets the number of buffers.
- *
- * @return the number of buffers
- */
- public int getNumBuffers();
-
- public Set<OFCapabilities> getCapabilities();
-
- public byte getNumTables();
-
- /**
- * Returns an OFDescStatsReply message object. Use the methods contained
- * to retrieve switch descriptions for Manufacturer, Hw/Sw version etc.
- */
- public OFDescStatsReply getSwitchDescription();
-
- /**
- * Cancel features reply with a specific transaction ID.
- * @param transactionId the transaction ID
- */
- public void cancelFeaturesReply(int transactionId);
-
- /**
- * Gets the OFActionType set.
- * <p>
- * getActions has relevance only for an OpenFlow 1.0 switch.
- * For OF1.3, each table can support different actions
- *
- * @return the action set
- */
- public Set<OFActionType> getActions();
-
- public void setOFVersion(OFVersion ofv);
-
- public OFVersion getOFVersion();
-
-
- //************************
- // Switch port related
- //************************
-
- /**
- * the type of change that happened to an open flow port.
- */
- public enum PortChangeType {
- /** Either a new port has been added by the switch, or we are
- * adding a port we just deleted (via a prior notification) due to
- * a change in the portNumber-portName mapping.
- */
- ADD,
- /** some other feature of the port has changed (eg. speed)*/
- OTHER_UPDATE,
- /** Either a port has been deleted by the switch, or we are deleting
- * a port whose portNumber-portName mapping has changed. Note that in
- * the latter case, a subsequent notification will be sent out to add a
- * port with the new portNumber-portName mapping.
- */
- DELETE,
- /** Port is up (i.e. enabled). Presumably an earlier notification had
- * indicated that it was down. To be UP implies that the port is
- * administratively considered UP (see ofp_port_config) AND the port
- * link is up AND the port is no longer blocked (see ofp_port_state).
- */
- UP,
- /** Port is down (i.e. disabled). Presumably an earlier notification had
- * indicated that it was up, or the port was always up.
- * To be DOWN implies that the port has been either
- * administratively brought down (see ofp_port_config) OR the port
- * link is down OR the port is blocked (see ofp_port_state).
- */
- DOWN,
- }
-
- /**
- * Describes a change of an open flow port.
- */
- public static class PortChangeEvent {
- public final OFPortDesc port;
- public final PortChangeType type;
- /**
- * @param port
- * @param type
- */
- public PortChangeEvent(OFPortDesc port,
- PortChangeType type) {
- this.port = port;
- this.type = type;
- }
- /* (non-Javadoc)
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((port == null) ? 0 : port.hashCode());
- result = prime * result + ((type == null) ? 0 : type.hashCode());
- return result;
- }
- /* (non-Javadoc)
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- PortChangeEvent other = (PortChangeEvent) obj;
- if (port == null) {
- if (other.port != null) {
- return false;
- }
- } else if (!port.equals(other.port)) {
- return false;
- }
- if (type != other.type) {
- return false;
- }
- return true;
- }
- /* (non-Javadoc)
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return "[" + type + " " + port.toString() + "]";
- }
- }
-
-
- /**
- * Get list of all enabled ports. This will typically be different from
- * the list of ports in the OFFeaturesReply, since that one is a static
- * snapshot of the ports at the time the switch connected to the controller
- * whereas this port list also reflects the port status messages that have
- * been received.
- *
- * @return Unmodifiable list of ports not backed by the underlying collection
- */
- public Collection<OFPortDesc> getEnabledPorts();
-
- /**
- * Get list of the port numbers of all enabled ports. This will typically
- * be different from the list of ports in the OFFeaturesReply, since that
- * one is a static snapshot of the ports at the time the switch connected
- * to the controller whereas this port list also reflects the port status
- * messages that have been received.
- *
- * @return Unmodifiable list of ports not backed by the underlying collection
- */
- public Collection<Integer> getEnabledPortNumbers();
-
- /**
- * Retrieve the port object by the port number. The port object
- * is the one that reflects the port status updates that have been
- * received, not the one from the features reply.
- *
- * @param portNumber
- * @return port object
- */
- public OFPortDesc getPort(int portNumber);
-
- /**
- * Retrieve the port object by the port name. The port object
- * is the one that reflects the port status updates that have been
- * received, not the one from the features reply.
- *
- * @param portName
- * @return port object
- */
- public OFPortDesc getPort(String portName);
-
- /**
- * Add or modify a switch port. This is called by the core controller
- * code in response to a OFPortStatus message.
- *
- * OFPPR_MODIFY and OFPPR_ADD will be treated as equivalent. The OpenFlow
- * spec is not clear on whether portNames are portNumbers are considered
- * authoritative identifiers. We treat portNames <-> portNumber mappings
- * as fixed. If they change, we delete all previous conflicting ports and
- * add all new ports.
- *
- * @param ps the port status message
- * @return the ordered Collection of changes "applied" to the old ports
- * of the switch according to the PortStatus message. A single PortStatus
- * message can result in multiple changes.
- * If portName <-> portNumber mappings have
- * changed, the iteration order ensures that delete events for old
- * conflicting appear before before events adding new ports
- */
- public OrderedCollection<PortChangeEvent> processOFPortStatus(OFPortStatus ps);
-
- /**
- * Get list of all ports. This will typically be different from
- * the list of ports in the OFFeaturesReply, since that one is a static
- * snapshot of the ports at the time the switch connected to the controller
- * whereas this port list also reflects the port status messages that have
- * been received.
- *
- * @return Unmodifiable list of ports
- */
- public Collection<OFPortDesc> getPorts();
-
- /**
- * @param portName
- * @return Whether a port is enabled per latest port status message
- * (not configured down nor link down nor in spanning tree blocking state)
- */
- public boolean portEnabled(int portName);
-
- /**
- * @param portName
- * @return Whether a port is enabled per latest port status message
- * (not configured down nor link down nor in spanning tree blocking state)
- */
- public boolean portEnabled(String portName);
-
- /**
- * Compute the changes that would be required to replace the old ports
- * of this switch with the new ports.
- * @param ports new ports to set
- * @return the ordered collection of changes "applied" to the old ports
- * of the switch in order to set them to the new set.
- * If portName <-> portNumber mappings have
- * changed, the iteration order ensures that delete events for old
- * conflicting appear before before events adding new ports
- */
- public OrderedCollection<PortChangeEvent>
- comparePorts(Collection<OFPortDesc> ports);
-
- /**
- * Replace the ports of this switch with the given ports.
- * @param ports new ports to set
- * @return the ordered collection of changes "applied" to the old ports
- * of the switch in order to set them to the new set.
- * If portName <-> portNumber mappings have
- * changed, the iteration order ensures that delete events for old
- * conflicting appear before before events adding new ports
- */
- public OrderedCollection<PortChangeEvent>
- setPorts(Collection<OFPortDesc> ports);
-
- //*******************************************
- // IOFSwitch object attributes
- //************************
-
- /**
- * Gets attributes of this switch.
- *
- * @return attributes of the switch
- */
- public Map<Object, Object> getAttributes();
-
- /**
- * Checks if a specific switch property exists for this switch.
- *
- * @param name name of property
- * @return value for name
- */
- boolean hasAttribute(String name);
-
- /**
- * Gets properties for switch specific behavior.
- *
- * @param name name of property
- * @return 'value' for 'name', or null if no entry for 'name' exists
- */
- Object getAttribute(String name);
-
- /**
- * Sets properties for switch specific behavior.
- *
- * @param name name of property
- * @param value value for name
- */
- void setAttribute(String name, Object value);
-
- /**
- * Removes properties for switch specific behavior.
- *
- * @param name name of property
- * @return current value for name or null (if not present)
- */
- Object removeAttribute(String name);
-
- //************************
- // Switch statistics
- //************************
-
- /**
- * Delivers the statistics future reply.
- *
- * @param reply the reply to deliver
- */
- public void deliverStatisticsReply(OFMessage reply);
-
- /**
- * Cancels the statistics reply with the given transaction ID.
- *
- * @param transactionId the transaction ID
- */
- public void cancelStatisticsReply(int transactionId);
-
- /**
- * Cancels all statistics replies.
- */
- public void cancelAllStatisticsReplies();
-
- /**
- * Gets a Future object that can be used to retrieve the asynchronous.
- * OFStatisticsReply when it is available.
- *
- * @param request statistics request
- * @return Future object wrapping OFStatisticsReply
- * @throws IOException
- */
- public Future<List<OFStatsReply>> getStatistics(OFStatsRequest<?> request)
- throws IOException;
-
- //************************
- // Switch other utilities
- //************************
-
- /**
- * Clears all flowmods on this switch.
- */
- public void clearAllFlowMods();
-
- /**
- * Gets the current role of this controller for this IOFSwitch.
- */
- public Role getRole();
-
- /**
- * Sets this controller's Role for this IOFSwitch to role.
- *
- * @param role
- */
- public void setRole(Role role);
-
- /**
- * Gets the next generation ID.
- * <p>
- * Note: relevant for role request messages in OF1.3
- *
- * @return next generation ID
- */
- public U64 getNextGenerationId();
-
-
- /**
- * Set debug counter service for per-switch counters.
- * Called immediately after instantiation.
- * @param debugCounter
- * @throws CounterException
- */
- public void setDebugCounterService(IDebugCounterService debugCounter)
- throws CounterException;
-
- /**
- * Start this switch driver's sub handshake. This might be a no-op but
- * this method must be called at least once for the switch to be become
- * ready.
- * This method must only be called from the I/O thread
- * @throws IOException
- * @throws org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeAlreadyStarted
- * if the sub-handshake has
- * already been started
- */
- public void startDriverHandshake() throws IOException;
-
- /**
- * Check if the sub-handshake for this switch driver has been completed.
- * This method can only be called after startDriverHandshake()
- *
- * This methods must only be called from the I/O thread
- * @return true if the sub-handshake has been completed. False otherwise
- * @throws org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeNotStarted
- * if startDriverHandshake() has
- * not been called yet.
- */
- public boolean isDriverHandshakeComplete();
-
- /**
- * Pass the given OFMessage to the driver as part of this driver's
- * sub-handshake. Must not be called after the handshake has been completed
- * This methods must only be called from the I/O thread
- * @param m The message that the driver should process
- * @throws org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeCompleted
- * if isDriverHandshake() returns
- * false before this method call
- * @throws org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeNotStarted
- * if startDriverHandshake() has
- * not been called yet.
- */
- public void processDriverHandshakeMessage(OFMessage m);
-
- /**
- * Set the flow table full flag in the switch.
- * XXX S Rethink this for multiple tables
- */
- public void setTableFull(boolean isFull);
-
- /**
- * Save the features reply for this switch.
- *
- * @param featuresReply
- */
- public void setFeaturesReply(OFFeaturesReply featuresReply);
-
- /**
- * Save the portset for this switch.
- *
- * @param portDescReply
- */
- public void setPortDescReply(OFPortDescStatsReply portDescReply);
-
- //************************
- // Message handling
- //************************
- /**
- * Handle the message coming from the dataplane.
- *
- * @param m the actual message
- */
- public void handleMessage(OFMessage m);
-
-
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/Role.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/Role.java
deleted file mode 100644
index 081ea10..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/Role.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.onlab.onos.of.controller.impl;
-
-import org.projectfloodlight.openflow.protocol.OFControllerRole;
-
-/**
- * The role of the controller as it pertains to a particular switch.
- * Note that this definition of the role enum is different from the
- * OF1.3 definition. It is maintained here to be backward compatible to
- * earlier versions of the controller code. This enum is translated
- * to the OF1.3 enum, before role messages are sent to the switch.
- * See sendRoleRequestMessage method in OFSwitchImpl
- */
-public enum Role {
- EQUAL(OFControllerRole.ROLE_EQUAL),
- MASTER(OFControllerRole.ROLE_MASTER),
- SLAVE(OFControllerRole.ROLE_SLAVE);
-
- private Role(OFControllerRole nxRole) {
- nxRole.ordinal();
- }
- /*
- private static Map<Integer,Role> nxRoleToEnum
- = new HashMap<Integer,Role>();
- static {
- for(Role r: Role.values())
- nxRoleToEnum.put(r.toNxRole(), r);
- }
- public int toNxRole() {
- return nxRole;
- }
- // Return the enum representing the given nxRole or null if no
- // such role exists
- public static Role fromNxRole(int nxRole) {
- return nxRoleToEnum.get(nxRole);
- }*/
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/DebugCounter.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/DebugCounter.java
deleted file mode 100644
index f88a43e..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/DebugCounter.java
+++ /dev/null
@@ -1,727 +0,0 @@
-package org.onlab.onos.of.controller.impl.debugcounter;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-import com.google.common.collect.Sets;
-
-
-
-/**
- * This class implements a central store for all counters used for debugging the
- * system. For counters based on traffic-type, see ICounterStoreService.
- *
- */
-//CHECKSTYLE:OFF
-public class DebugCounter implements IDebugCounterService {
- protected static final Logger log = LoggerFactory.getLogger(DebugCounter.class);
-
- /**
- * registered counters need a counter id.
- */
- protected AtomicInteger counterIdCounter = new AtomicInteger();
-
- /**
- * The counter value.
- */
- protected static class MutableLong {
- long value = 0;
- public void increment() { value += 1; }
- public void increment(long incr) { value += incr; }
- public long get() { return value; }
- public void set(long val) { value = val; }
- }
-
- /**
- * protected class to store counter information.
- */
- public static class CounterInfo {
- String moduleCounterHierarchy;
- String counterDesc;
- CounterType ctype;
- String moduleName;
- String counterHierarchy;
- int counterId;
- boolean enabled;
- String[] metaData;
-
- public CounterInfo(int counterId, boolean enabled,
- String moduleName, String counterHierarchy,
- String desc, CounterType ctype, String... metaData) {
- this.moduleCounterHierarchy = moduleName + "/" + counterHierarchy;
- this.moduleName = moduleName;
- this.counterHierarchy = counterHierarchy;
- this.counterDesc = desc;
- this.ctype = ctype;
- this.counterId = counterId;
- this.enabled = enabled;
- this.metaData = metaData;
- }
-
- public String getModuleCounterHierarchy() { return moduleCounterHierarchy; }
- public String getCounterDesc() { return counterDesc; }
- public CounterType getCtype() { return ctype; }
- public String getModuleName() { return moduleName; }
- public String getCounterHierarchy() { return counterHierarchy; }
- public int getCounterId() { return counterId; }
- public boolean isEnabled() { return enabled; }
- public String[] getMetaData() { return this.metaData.clone(); }
- }
-
- //******************
- // Global stores
- //******************
-
- /**
- * Counter info for a debug counter.
- */
- public static class DebugCounterInfo {
- CounterInfo cinfo;
- AtomicLong cvalue;
-
- public DebugCounterInfo(CounterInfo cinfo) {
- this.cinfo = cinfo;
- this.cvalue = new AtomicLong();
- }
- public CounterInfo getCounterInfo() {
- return cinfo;
- }
- public Long getCounterValue() {
- return cvalue.get();
- }
- }
-
- /**
- * Global debug-counter storage across all threads. These are
- * updated from the local per thread counters by the flush counters method.
- */
- private static final DebugCounterInfo[] ALLCOUNTERS =
- new DebugCounterInfo[MAX_COUNTERS];
-
-
- /**
- * per module counters, indexed by the module name and storing three levels
- * of Counter information in the form of CounterIndexStore.
- */
- protected ConcurrentHashMap<String, ConcurrentHashMap<String, CounterIndexStore>>
- moduleCounters = new ConcurrentHashMap<String,
- ConcurrentHashMap<String,
- CounterIndexStore>>();
-
- protected static class CounterIndexStore {
- int index;
- Map<String, CounterIndexStore> nextLevel;
-
- public CounterIndexStore(int index, Map<String, CounterIndexStore> cis) {
- this.index = index;
- this.nextLevel = cis;
- }
- }
-
- /**
- * fast global cache for counter ids that are currently active.
- */
- protected Set<Integer> currentCounters = Collections.newSetFromMap(
- new ConcurrentHashMap<Integer, Boolean>());
-
- //******************
- // Thread local stores
- //******************
-
- /**
- * Thread local storage of counter info.
- */
- protected static class LocalCounterInfo {
- boolean enabled;
- MutableLong cvalue;
-
- public LocalCounterInfo(boolean enabled) {
- this.enabled = enabled;
- this.cvalue = new MutableLong();
- }
- }
-
- /**
- * Thread local debug counters used for maintaining counters local to a thread.
- */
- protected final ThreadLocal<LocalCounterInfo[]> threadlocalCounters =
- new ThreadLocal<LocalCounterInfo[]>() {
- @Override
- protected LocalCounterInfo[] initialValue() {
- return new LocalCounterInfo[MAX_COUNTERS];
- }
- };
-
- /**
- * Thread local cache for counter ids that are currently active.
- */
- protected final ThreadLocal<Set<Integer>> threadlocalCurrentCounters =
- new ThreadLocal<Set<Integer>>() {
- @Override
- protected Set<Integer> initialValue() {
- return new HashSet<Integer>();
- }
- };
-
- //*******************************
- // IDebugCounter
- //*******************************
-
- protected class CounterImpl implements IDebugCounter {
- private final int counterId;
-
- public CounterImpl(int counterId) {
- this.counterId = counterId;
- }
-
- @Override
- public void updateCounterWithFlush() {
- if (!validCounterId()) {
- return;
- }
- updateCounter(counterId, 1, true);
- }
-
- @Override
- public void updateCounterNoFlush() {
- if (!validCounterId()) {
- return;
- }
- updateCounter(counterId, 1, false);
- }
-
- @Override
- public void updateCounterWithFlush(int incr) {
- if (!validCounterId()) {
- return;
- }
- updateCounter(counterId, incr, true);
- }
-
- @Override
- public void updateCounterNoFlush(int incr) {
- if (!validCounterId()) {
- return;
- }
- updateCounter(counterId, incr, false);
- }
-
- @Override
- public long getCounterValue() {
- if (!validCounterId()) {
- return -1;
- }
- return ALLCOUNTERS[counterId].cvalue.get();
- }
-
- /**
- * Checks if this is a valid counter.
- * @return true if the counter id is valid
- */
- private boolean validCounterId() {
- if (counterId < 0 || counterId >= MAX_COUNTERS) {
- log.error("Invalid counterId invoked");
- return false;
- }
- return true;
- }
-
- }
-
- //*******************************
- // IDebugCounterService
- //*******************************
-
- @Override
- public IDebugCounter registerCounter(String moduleName, String counterHierarchy,
- String counterDescription, CounterType counterType,
- String... metaData)
- throws CounterException {
- // check if counter already exists
- if (!moduleCounters.containsKey(moduleName)) {
- moduleCounters.putIfAbsent(moduleName,
- new ConcurrentHashMap<String, CounterIndexStore>());
- }
- RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
- if (rci.allLevelsFound) {
- // counter exists
- log.info("Counter exists for {}/{} -- resetting counters", moduleName,
- counterHierarchy);
- resetCounterHierarchy(moduleName, counterHierarchy);
- return new CounterImpl(rci.ctrIds[rci.foundUptoLevel - 1]);
- }
- // check for validity of counter
- if (rci.levels.length > MAX_HIERARCHY) {
- String err = "Registry of counterHierarchy " + counterHierarchy +
- " exceeds max hierachy " + MAX_HIERARCHY + ".. aborting";
- throw new MaxHierarchyRegistered(err);
- }
- if (rci.foundUptoLevel < rci.levels.length - 1) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i <= rci.foundUptoLevel; i++) {
- sb.append(rci.levels[i]);
- }
- String needToRegister = sb.toString();
- String err = "Attempting to register hierarchical counterHierarchy " +
- counterHierarchy + " but parts of hierarchy missing. " +
- "Please register " + needToRegister + " first";
- throw new MissingHierarchicalLevel(err);
- }
-
- // get a new counter id
- int counterId = counterIdCounter.getAndIncrement();
- if (counterId >= MAX_COUNTERS) {
- throw new MaxCountersRegistered("max counters reached");
- }
- // create storage for counter
- boolean enabled = (counterType == CounterType.ALWAYS_COUNT) ? true : false;
- CounterInfo ci = new CounterInfo(counterId, enabled, moduleName,
- counterHierarchy, counterDescription,
- counterType, metaData);
- ALLCOUNTERS[counterId] = new DebugCounterInfo(ci);
-
- // account for the new counter in the module counter hierarchy
- addToModuleCounterHierarchy(moduleName, counterId, rci);
-
- // finally add to active counters
- if (enabled) {
- currentCounters.add(counterId);
- }
- return new CounterImpl(counterId);
- }
-
- private void updateCounter(int counterId, int incr, boolean flushNow) {
- if (counterId < 0 || counterId >= MAX_COUNTERS) {
- return;
- }
-
- LocalCounterInfo[] thiscounters = this.threadlocalCounters.get();
- if (thiscounters[counterId] == null) {
- // seeing this counter for the first time in this thread - create local
- // store by consulting global store
- DebugCounterInfo dc = ALLCOUNTERS[counterId];
- if (dc != null) {
- thiscounters[counterId] = new LocalCounterInfo(dc.cinfo.enabled);
- if (dc.cinfo.enabled) {
- Set<Integer> thisset = this.threadlocalCurrentCounters.get();
- thisset.add(counterId);
- }
- } else {
- log.error("updateCounter seen locally for counter {} but no global"
- + "storage exists for it yet .. not updating", counterId);
- return;
- }
- }
-
- // update local store if enabled locally for updating
- LocalCounterInfo lc = thiscounters[counterId];
- if (lc.enabled) {
- lc.cvalue.increment(incr);
- if (flushNow) {
- DebugCounterInfo dc = ALLCOUNTERS[counterId];
- if (dc.cinfo.enabled) {
- // globally enabled - flush now
- dc.cvalue.addAndGet(lc.cvalue.get());
- lc.cvalue.set(0);
- } else {
- // global counter is disabled - don't flush, disable locally
- lc.enabled = false;
- Set<Integer> thisset = this.threadlocalCurrentCounters.get();
- thisset.remove(counterId);
- }
- }
- }
- }
-
- @Override
- public void flushCounters() {
- LocalCounterInfo[] thiscounters = this.threadlocalCounters.get();
- Set<Integer> thisset = this.threadlocalCurrentCounters.get();
- ArrayList<Integer> temp = new ArrayList<Integer>();
-
- for (int counterId : thisset) {
- LocalCounterInfo lc = thiscounters[counterId];
- if (lc.cvalue.get() > 0) {
- DebugCounterInfo dc = ALLCOUNTERS[counterId];
- if (dc.cinfo.enabled) {
- // globally enabled - flush now
- dc.cvalue.addAndGet(lc.cvalue.get());
- lc.cvalue.set(0);
- } else {
- // global counter is disabled - don't flush, disable locally
- lc.enabled = false;
- temp.add(counterId);
- }
- }
- }
- for (int cId : temp) {
- thisset.remove(cId);
- }
-
- // At this point it is possible that the thread-local set does not
- // include a counter that has been enabled and is present in the global set.
- // We need to sync thread-local currently enabled set of counterIds with
- // the global set.
- Sets.SetView<Integer> sv = Sets.difference(currentCounters, thisset);
- for (int counterId : sv) {
- if (thiscounters[counterId] != null) {
- thiscounters[counterId].enabled = true;
- thisset.add(counterId);
- }
- }
- }
-
- @Override
- public void resetCounterHierarchy(String moduleName, String counterHierarchy) {
- RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
- if (!rci.allLevelsFound) {
- String missing = rci.levels[rci.foundUptoLevel];
- log.error("Cannot reset counter hierarchy - missing counter {}", missing);
- return;
- }
- // reset at this level
- ALLCOUNTERS[rci.ctrIds[rci.foundUptoLevel - 1]].cvalue.set(0);
- // reset all levels below
- ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
- for (int index : resetIds) {
- ALLCOUNTERS[index].cvalue.set(0);
- }
- }
-
- @Override
- public void resetAllCounters() {
- RetCtrInfo rci = new RetCtrInfo();
- rci.levels = "".split("/");
- for (String moduleName : moduleCounters.keySet()) {
- ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
- for (int index : resetIds) {
- ALLCOUNTERS[index].cvalue.set(0);
- }
- }
- }
-
- @Override
- public void resetAllModuleCounters(String moduleName) {
- Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
- RetCtrInfo rci = new RetCtrInfo();
- rci.levels = "".split("/");
-
- if (target != null) {
- ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
- for (int index : resetIds) {
- ALLCOUNTERS[index].cvalue.set(0);
- }
- } else {
- if (log.isDebugEnabled()) {
- log.debug("No module found with name {}", moduleName);
- }
- }
- }
-
- @Override
- public void enableCtrOnDemand(String moduleName, String counterHierarchy) {
- RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
- if (!rci.allLevelsFound) {
- String missing = rci.levels[rci.foundUptoLevel];
- log.error("Cannot enable counter - counter not found {}", missing);
- return;
- }
- // enable specific counter
- DebugCounterInfo dc = ALLCOUNTERS[rci.ctrIds[rci.foundUptoLevel - 1]];
- dc.cinfo.enabled = true;
- currentCounters.add(dc.cinfo.counterId);
- }
-
- @Override
- public void disableCtrOnDemand(String moduleName, String counterHierarchy) {
- RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
- if (!rci.allLevelsFound) {
- String missing = rci.levels[rci.foundUptoLevel];
- log.error("Cannot disable counter - counter not found {}", missing);
- return;
- }
- // disable specific counter
- DebugCounterInfo dc = ALLCOUNTERS[rci.ctrIds[rci.foundUptoLevel - 1]];
- if (dc.cinfo.ctype == CounterType.COUNT_ON_DEMAND) {
- dc.cinfo.enabled = false;
- dc.cvalue.set(0);
- currentCounters.remove(dc.cinfo.counterId);
- }
- }
-
- @Override
- public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
- String counterHierarchy) {
- RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
- if (!rci.allLevelsFound) {
- String missing = rci.levels[rci.foundUptoLevel];
- log.error("Cannot fetch counter - counter not found {}", missing);
- return Collections.emptyList();
- }
- ArrayList<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
- // get counter and all below it
- DebugCounterInfo dc = ALLCOUNTERS[rci.ctrIds[rci.foundUptoLevel - 1]];
- dcilist.add(dc);
- ArrayList<Integer> belowIds = getHierarchyBelow(moduleName, rci);
- for (int index : belowIds) {
- dcilist.add(ALLCOUNTERS[index]);
- }
- return dcilist;
- }
-
- @Override
- public List<DebugCounterInfo> getAllCounterValues() {
- List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
- RetCtrInfo rci = new RetCtrInfo();
- rci.levels = "".split("/");
-
- for (String moduleName : moduleCounters.keySet()) {
- ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
- for (int index : resetIds) {
- dcilist.add(ALLCOUNTERS[index]);
- }
- }
- return dcilist;
- }
-
- @Override
- public List<DebugCounterInfo> getModuleCounterValues(String moduleName) {
- List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
- RetCtrInfo rci = new RetCtrInfo();
- rci.levels = "".split("/");
-
- if (moduleCounters.containsKey(moduleName)) {
- ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
- for (int index : resetIds) {
- dcilist.add(ALLCOUNTERS[index]);
- }
- }
- return dcilist;
- }
-
- @Override
- public boolean containsModuleCounterHierarchy(String moduleName,
- String counterHierarchy) {
- if (!moduleCounters.containsKey(moduleName)) {
- return false;
- }
- RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
- return rci.allLevelsFound;
- }
-
- @Override
- public boolean containsModuleName(String moduleName) {
- return (moduleCounters.containsKey(moduleName)) ? true : false;
- }
-
- @Override
- public List<String> getModuleList() {
- List<String> retval = new ArrayList<String>();
- retval.addAll(moduleCounters.keySet());
- return retval;
- }
-
- @Override
- public List<String> getModuleCounterList(String moduleName) {
- if (!moduleCounters.containsKey(moduleName)) {
- return Collections.emptyList();
- }
-
- List<String> retval = new ArrayList<String>();
- RetCtrInfo rci = new RetCtrInfo();
- rci.levels = "".split("/");
-
- ArrayList<Integer> cids = getHierarchyBelow(moduleName, rci);
- for (int index : cids) {
- retval.add(ALLCOUNTERS[index].cinfo.counterHierarchy);
- }
- return retval;
- }
-
- //*******************************
- // Internal Methods
- //*******************************
-
- protected class RetCtrInfo {
- boolean allLevelsFound; // counter indices found all the way down the hierarchy
- boolean hierarchical; // true if counterHierarchy is hierarchical
- int foundUptoLevel;
- int[] ctrIds;
- String[] levels;
-
- public RetCtrInfo() {
- ctrIds = new int[MAX_HIERARCHY];
- for (int i = 0; i < MAX_HIERARCHY; i++) {
- ctrIds[i] = -1;
- }
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + getOuterType().hashCode();
- result = prime * result + (allLevelsFound ? 1231 : 1237);
- result = prime * result + Arrays.hashCode(ctrIds);
- result = prime * result + foundUptoLevel;
- result = prime * result + (hierarchical ? 1231 : 1237);
- result = prime * result + Arrays.hashCode(levels);
- return result;
- }
-
- @Override
- public boolean equals(Object oth) {
- if (!(oth instanceof RetCtrInfo)) {
- return false;
- }
- RetCtrInfo other = (RetCtrInfo) oth;
- if (other.allLevelsFound != this.allLevelsFound) {
- return false;
- }
- if (other.hierarchical != this.hierarchical) {
- return false;
- }
- if (other.foundUptoLevel != this.foundUptoLevel) {
- return false;
- }
- if (!Arrays.equals(other.ctrIds, this.ctrIds)) {
- return false;
- }
- if (!Arrays.equals(other.levels, this.levels)) {
- return false;
- }
- return true;
- }
-
- private DebugCounter getOuterType() {
- return DebugCounter.this;
- }
-
-
-
- }
-
- protected RetCtrInfo getCounterId(String moduleName, String counterHierarchy) {
- RetCtrInfo rci = new RetCtrInfo();
- Map<String, CounterIndexStore> templevel = moduleCounters.get(moduleName);
- rci.levels = counterHierarchy.split("/");
- if (rci.levels.length > 1) {
- rci.hierarchical = true;
- }
- if (templevel == null) {
- log.error("moduleName {} does not exist in debugCounters", moduleName);
- return rci;
- }
-
- /*
- if (rci.levels.length > MAX_HIERARCHY) {
- // chop off all array elems greater that MAX_HIERARCHY
- String[] temp = new String[MAX_HIERARCHY];
- System.arraycopy(rci.levels, 0, temp, 0, MAX_HIERARCHY);
- rci.levels = temp;
- }
- */
- for (int i = 0; i < rci.levels.length; i++) {
- if (templevel != null) {
- CounterIndexStore cis = templevel.get(rci.levels[i]);
- if (cis == null) {
- // could not find counterHierarchy part at this level
- break;
- } else {
- rci.ctrIds[i] = cis.index;
- templevel = cis.nextLevel;
- rci.foundUptoLevel++;
- if (i == rci.levels.length - 1) {
- rci.allLevelsFound = true;
- }
- }
- } else {
- // there are no more levels, which means that some part of the
- // counterHierarchy has no corresponding map
- break;
- }
- }
- return rci;
- }
-
- protected void addToModuleCounterHierarchy(String moduleName, int counterId,
- RetCtrInfo rci) {
- Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
- if (target == null) {
- return;
- }
- CounterIndexStore cis = null;
-
- for (int i = 0; i < rci.foundUptoLevel; i++) {
- cis = target.get(rci.levels[i]);
- target = cis.nextLevel;
- }
- if (cis != null) {
- if (cis.nextLevel == null) {
- cis.nextLevel = new ConcurrentHashMap<String, CounterIndexStore>();
- }
- cis.nextLevel.put(rci.levels[rci.foundUptoLevel],
- new CounterIndexStore(counterId, null));
- } else {
- target.put(rci.levels[rci.foundUptoLevel],
- new CounterIndexStore(counterId, null));
- }
- }
-
- // given a partial hierarchical counter, return the rest of the hierarchy
- protected ArrayList<Integer> getHierarchyBelow(String moduleName, RetCtrInfo rci) {
- Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
- CounterIndexStore cis = null;
- ArrayList<Integer> retval = new ArrayList<Integer>();
- if (target == null) {
- return retval;
- }
-
- // get to the level given
- for (int i = 0; i < rci.foundUptoLevel; i++) {
- cis = target.get(rci.levels[i]);
- target = cis.nextLevel;
- }
-
- if (target == null || rci.foundUptoLevel == MAX_HIERARCHY) {
- // no more levels
- return retval;
- } else {
- // recursively get all ids
- getIdsAtLevel(target, retval, rci.foundUptoLevel + 1);
- }
-
- return retval;
- }
-
- protected void getIdsAtLevel(Map<String, CounterIndexStore> hcy,
- ArrayList<Integer> retval, int level) {
- if (level > MAX_HIERARCHY) {
- return;
- }
- if (hcy == null || retval == null) {
- return;
- }
-
- // Can return the counter names as well but for now ids are enough.
- for (CounterIndexStore cistemp : hcy.values()) {
- retval.add(cistemp.index); // value at this level
- if (cistemp.nextLevel != null) {
- getIdsAtLevel(cistemp.nextLevel, retval, level + 1);
- }
- }
- }
-
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/IDebugCounter.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/IDebugCounter.java
deleted file mode 100644
index 2dc0c0a..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/IDebugCounter.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.onlab.onos.of.controller.impl.debugcounter;
-
-public interface IDebugCounter {
- /**
- * Increments the counter by 1 thread-locally, and immediately flushes to
- * the global counter storage. This method should be used for counters that
- * are updated outside the OF message processing pipeline.
- */
- void updateCounterWithFlush();
-
- /**
- * Increments the counter by 1 thread-locally. Flushing to the global
- * counter storage is delayed (happens with flushCounters() in IDebugCounterService),
- * resulting in higher performance. This method should be used for counters
- * updated in the OF message processing pipeline.
- */
- void updateCounterNoFlush();
-
- /**
- * Increments the counter thread-locally by the 'incr' specified, and immediately
- * flushes to the global counter storage. This method should be used for counters
- * that are updated outside the OF message processing pipeline.
- */
- void updateCounterWithFlush(int incr);
-
- /**
- * Increments the counter thread-locally by the 'incr' specified. Flushing to the global
- * counter storage is delayed (happens with flushCounters() in IDebugCounterService),
- * resulting in higher performance. This method should be used for counters
- * updated in the OF message processing pipeline.
- */
- void updateCounterNoFlush(int incr);
-
- /**
- * Retrieve the value of the counter from the global counter store.
- */
- long getCounterValue();
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/IDebugCounterService.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/IDebugCounterService.java
deleted file mode 100644
index 216ee74..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/IDebugCounterService.java
+++ /dev/null
@@ -1,262 +0,0 @@
-package org.onlab.onos.of.controller.impl.debugcounter;
-
-
-
-import java.util.List;
-
-import org.onlab.onos.of.controller.impl.debugcounter.DebugCounter.DebugCounterInfo;
-
-//CHECKSTYLE:OFF
-public interface IDebugCounterService {
-
- /**
- * Different counter types. Counters that are meant to be counted-on-demand
- * need to be separately enabled/disabled.
- */
- public enum CounterType {
- ALWAYS_COUNT,
- COUNT_ON_DEMAND
- }
-
- /**
- * Debug Counter Qualifiers.
- */
- public static final String CTR_MDATA_WARN = "warn";
- public static final String CTR_MDATA_ERROR = "error";
- public static final String CTR_MDATA_DROP = "drop";
-
- /**
- * A limit on the maximum number of counters that can be created.
- */
- public static final int MAX_COUNTERS = 5000;
-
- /**
- * Exception thrown when MAX_COUNTERS have been registered.
- */
- public class MaxCountersRegistered extends CounterException {
- private static final long serialVersionUID = 3173747663719376745L;
- String errormsg;
- public MaxCountersRegistered(String errormsg) {
- this.errormsg = errormsg;
- }
- @Override
- public String getMessage() {
- return this.errormsg;
- }
- }
- /**
- * Exception thrown when MAX_HIERARCHY has been reached.
- */
- public class MaxHierarchyRegistered extends CounterException {
- private static final long serialVersionUID = 967431358683523871L;
- private String errormsg;
- public MaxHierarchyRegistered(String errormsg) {
- this.errormsg = errormsg;
- }
- @Override
- public String getMessage() {
- return this.errormsg;
- }
- }
- /**
- * Exception thrown when attempting to register a hierarchical counter
- * where higher levels of the hierarchy have not been pre-registered.
- */
- public class MissingHierarchicalLevel extends CounterException {
- private static final long serialVersionUID = 517315311533995739L;
- private String errormsg;
- public MissingHierarchicalLevel(String errormsg) {
- this.errormsg = errormsg;
- }
- @Override
- public String getMessage() {
- return this.errormsg;
- }
- }
-
- public class CounterException extends Exception {
- private static final long serialVersionUID = 2219781500857866035L;
- }
-
- /**
- * maximum levels of hierarchy.
- * Example of moduleName/counterHierarchy:
- * switch/00:00:00:00:01:02:03:04/pktin/drops where
- * moduleName ==> "switch" and
- * counterHierarchy of 3 ==> "00:00:00:00:01:02:03:04/pktin/drops"
- */
- public static final int MAX_HIERARCHY = 3;
-
- /**
- * All modules that wish to have the DebugCounterService count for them, must
- * register their counters by making this call (typically from that module's
- * 'startUp' method). The counter can then be updated, displayed, reset etc.
- * using the registered moduleName and counterHierarchy.
- *
- * @param moduleName the name of the module which is registering the
- * counter eg. linkdiscovery or controller or switch
- * @param counterHierarchy the hierarchical counter name specifying all
- * the hierarchical levels that come above it.
- * For example: to register a drop counter for
- * packet-ins from a switch, the counterHierarchy
- * can be "00:00:00:00:01:02:03:04/pktin/drops"
- * It is necessary that counters in hierarchical levels
- * above have already been pre-registered - in this
- * example: "00:00:00:00:01:02:03:04/pktin" and
- * "00:00:00:00:01:02:03:04"
- * @param counterDescription a descriptive string that gives more information
- * of what the counter is measuring. For example,
- * "Measures the number of incoming packets seen by
- * this module".
- * @param counterType One of CounterType. On-demand counter types
- * need to be explicitly enabled/disabled using other
- * methods in this API -- i.e. registering them is
- * not enough to start counting.
- * @param metaData variable arguments that qualify a counter
- * eg. warn, error etc.
- * @return IDebugCounter with update methods that can be
- * used to update a counter.
- * @throws MaxCountersRegistered
- * @throws MaxHierarchyRegistered
- * @throws MissingHierarchicalLevel
- */
- public IDebugCounter registerCounter(String moduleName, String counterHierarchy,
- String counterDescription, CounterType counterType,
- String... metaData)
- throws CounterException;
-
- /**
- * Flush all thread-local counter values (from the current thread)
- * to the global counter store. This method is not intended for use by any
- * module. It's typical usage is from core and it is meant
- * to flush those counters that are updated in the packet-processing pipeline,
- * typically with the 'updateCounterNoFlush" methods in IDebugCounter.
- */
- public void flushCounters();
-
- /**
- * Resets the value of counters in the hierarchy to zero. Note that the reset
- * applies to the level of counter hierarchy specified AND ALL LEVELS BELOW it
- * in the hierarchy.
- * For example: If a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops"
- * specifying a reset hierarchy: "00:00:00:00:01:02:03:04"
- * will reset all counters for the switch dpid specified;
- * while specifying a reset hierarchy: ""00:00:00:00:01:02:03:04/pktin"
- * will reset the pktin counter and all levels below it (like drops)
- * for the switch dpid specified.
- */
- void resetCounterHierarchy(String moduleName, String counterHierarchy);
-
- /**
- * Resets the values of all counters in the system.
- */
- public void resetAllCounters();
-
- /**
- * Resets the values of all counters belonging
- * to a module with the given 'moduleName'.
- */
- public void resetAllModuleCounters(String moduleName);
-
- /**
- * This method applies only to CounterType.COUNT_ON_DEMAND. It is used to
- * enable counting on the counter. Note that this step is necessary to start
- * counting for these counter types - merely registering the counter is not
- * enough (as is the case for CounterType.ALWAYS_COUNT). Newly
- * enabled counters start from an initial value of zero.
- *
- * Enabling a counter in a counterHierarchy enables only THAT counter. It
- * does not enable any other part of the counterHierarchy. For example, if
- * a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops", where the
- * 'pktin' and 'drops' counters are CounterType.COUNT_ON_DEMAND, then enabling
- * the 'pktin' counter by specifying the counterHierarchy as
- * "00:00:00:00:01:02:03:04/pktin" does NOT enable the 'drops' counter.
- */
- public void enableCtrOnDemand(String moduleName, String counterHierarchy);
-
- /**
- * This method applies only to CounterType.COUNT_ON_DEMAND. It is used to
- * enable counting on the counter. Note that disabling a counter results in a loss
- * of the counter value. When re-enabled the counter will restart from zero.
- *
- * Disabling a counter in a counterHierarchy disables only THAT counter. It
- * does not disable any other part of the counterHierarchy. For example, if
- * a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops", where the
- * 'pktin' and 'drops' counters are CounterType.COUNT_ON_DEMAND, then disabling
- * the 'pktin' counter by specifying the counterHierarchy as
- * "00:00:00:00:01:02:03:04/pktin" does NOT disable the 'drops' counter.
- */
- public void disableCtrOnDemand(String moduleName, String counterHierarchy);
-
- /**
- * Get counter value and associated information for the specified counterHierarchy.
- * Note that information on the level of counter hierarchy specified
- * AND ALL LEVELS BELOW it in the hierarchy will be returned.
- *
- * For example,
- * if a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops", then
- * specifying a counterHierarchy of "00:00:00:00:01:02:03:04/pktin" in the
- * get call will return information on the 'pktin' as well as the 'drops'
- * counters for the switch dpid specified.
- *
- * @return A list of DebugCounterInfo or an empty list if the counter
- * could not be found
- */
- public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
- String counterHierarchy);
-
- /**
- * Get counter values and associated information for all counters in the
- * system.
- *
- * @return the list of values/info or an empty list
- */
- public List<DebugCounterInfo> getAllCounterValues();
-
- /**
- * Get counter values and associated information for all counters associated
- * with a module.
- *
- * @param moduleName
- * @return the list of values/info or an empty list
- */
- public List<DebugCounterInfo> getModuleCounterValues(String moduleName);
-
- /**
- * Convenience method to figure out if the the given 'counterHierarchy' corresponds
- * to a registered counterHierarchy for 'moduleName'. Note that the counter may or
- * may not be enabled for counting, but if it is registered the method will
- * return true.
- *
- * @param moduleName
- * @param counterHierarchy
- * @return false if moduleCounterHierarchy is not a registered counter
- */
- public boolean containsModuleCounterHierarchy(String moduleName,
- String counterHierarchy);
-
- /**
- * Convenience method to figure out if the the given 'moduleName' corresponds
- * to a registered moduleName or not. Note that the module may or may not have
- * a counter enabled for counting, but if it is registered the method will
- * return true.
- *
- * @param moduleName
- * @return false if moduleName is not a registered counter
- */
- public boolean containsModuleName(String moduleName);
-
- /**
- * Returns a list of moduleNames registered for debug counters or an empty
- * list if no counters have been registered in the system.
- */
- public List<String> getModuleList();
-
- /**
- * Returns a list of all counters registered for a specific moduleName
- * or a empty list.
- */
- public List<String> getModuleCounterList(String moduleName);
-
-
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/NullDebugCounter.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/NullDebugCounter.java
deleted file mode 100644
index ae476ea..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/NullDebugCounter.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package org.onlab.onos.of.controller.impl.debugcounter;
-
-import java.util.Collections;
-import java.util.List;
-
-import org.onlab.onos.of.controller.impl.debugcounter.DebugCounter.DebugCounterInfo;
-
-//CHECKSTYLE:OFF
-public class NullDebugCounter implements IDebugCounterService {
-
- @Override
- public void flushCounters() {
-
- }
-
- @Override
- public void resetAllCounters() {
-
- }
-
- @Override
- public void resetAllModuleCounters(String moduleName) {
-
- }
-
-
- @Override
- public void resetCounterHierarchy(String moduleName, String counterHierarchy) {
-
- }
-
- @Override
- public void enableCtrOnDemand(String moduleName, String counterHierarchy) {
-
- }
-
- @Override
- public void disableCtrOnDemand(String moduleName, String counterHierarchy) {
-
- }
-
- @Override
- public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
- String counterHierarchy) {
- return Collections.emptyList();
- }
-
- @Override
- public List<DebugCounterInfo> getAllCounterValues() {
- return Collections.emptyList();
- }
-
- @Override
- public List<DebugCounterInfo> getModuleCounterValues(String moduleName) {
- return Collections.emptyList();
- }
-
- @Override
- public boolean containsModuleCounterHierarchy(String moduleName,
- String counterHierarchy) {
- return false;
- }
-
- @Override
- public boolean containsModuleName(String moduleName) {
- return false;
- }
-
- @Override
- public
- IDebugCounter
- registerCounter(String moduleName, String counterHierarchy,
- String counterDescription,
- CounterType counterType, String... metaData)
- throws MaxCountersRegistered {
- return new NullCounterImpl();
- }
-
- @Override
- public List<String> getModuleList() {
- return Collections.emptyList();
- }
-
- @Override
- public List<String> getModuleCounterList(String moduleName) {
- return Collections.emptyList();
- }
-
- public static class NullCounterImpl implements IDebugCounter {
-
- @Override
- public void updateCounterWithFlush() {
-
- }
-
- @Override
- public void updateCounterNoFlush() {
-
- }
-
- @Override
- public void updateCounterWithFlush(int incr) {
- }
-
- @Override
- public void updateCounterNoFlush(int incr) {
-
- }
-
- @Override
- public long getCounterValue() {
- return -1;
- }
-
- }
-
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/AbstractOpenFlowSwitch.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/AbstractOpenFlowSwitch.java
new file mode 100644
index 0000000..7f4830d
--- /dev/null
+++ b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/AbstractOpenFlowSwitch.java
@@ -0,0 +1,279 @@
+/**
+ * Copyright 2011, Big Switch Networks, Inc.
+ * Originally created by David Erickson, Stanford University
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ **/
+
+package org.onlab.onos.of.controller.impl.internal;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.jboss.netty.channel.Channel;
+import org.onlab.onos.of.controller.Dpid;
+import org.onlab.onos.of.controller.OpenFlowSwitch;
+import org.onlab.onos.of.controller.RoleState;
+import org.onlab.onos.of.controller.impl.internal.OpenFlowControllerImpl.OpenFlowSwitchAgent;
+import org.onlab.onos.of.controller.impl.internal.RoleManager.RoleRecvStatus;
+import org.onlab.onos.of.controller.impl.internal.RoleManager.RoleReplyInfo;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFExperimenter;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFRoleReply;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
+
+ private static Logger log =
+ LoggerFactory.getLogger(AbstractOpenFlowSwitch.class);
+
+ private Channel channel;
+ private boolean connected;
+ private Dpid dpid;
+ private OpenFlowSwitchAgent agent;
+
+ private OFVersion ofVersion;
+
+ protected OFPortDescStatsReply ports;
+
+ protected boolean tableFull;
+
+ private final RoleManager roleMan = new RoleManager(this);
+
+ protected AbstractOpenFlowSwitch(long dpid) {
+ this.dpid = new Dpid(dpid);
+ }
+
+ //************************
+ // Channel related
+ //************************
+
+ /**
+ * Disconnects the switch by closing the TCP connection. Results in a call
+ * to the channel handler's channelDisconnected method for cleanup
+ * @throws IOException
+ */
+ public final void disconnectSwitch() {
+ this.channel.close();
+ }
+
+ /**
+ * Writes to the OFMessage to the output stream.
+ *
+ * @param m the message to be written
+ */
+ public abstract void write(OFMessage m);
+
+ /**
+ * Writes to the OFMessage list to the output stream.
+ *
+ * @param msgs the messages to be written
+ */
+ public abstract void write(List<OFMessage> msgs);
+
+
+ /**
+ * Checks if the switch is still connected.
+ * Only call while holding processMessageLock
+ *
+ * @return whether the switch is still disconnected
+ */
+ public final boolean isConnected() {
+ return this.connected;
+ }
+
+ /**
+ * Sets whether the switch is connected.
+ * Only call while holding modifySwitchLock
+ *
+ * @param connected whether the switch is connected
+ */
+ final void setConnected(boolean connected) {
+ this.connected = connected;
+ };
+
+ /**
+ * Sets the Netty Channel this switch instance is associated with.
+ * <p>
+ * Called immediately after instantiation
+ *
+ * @param channel the channel
+ */
+ public final void setChannel(Channel channel) {
+ this.channel = channel;
+ };
+
+ //************************
+ // Switch features related
+ //************************
+
+ /**
+ * Gets the datapathId of the switch.
+ *
+ * @return the switch buffers
+ */
+ public final long getId() {
+ return this.dpid.value();
+ };
+
+ /**
+ * Gets a string version of the ID for this switch.
+ *
+ * @return string version of the ID
+ */
+ public final String getStringId() {
+ return this.dpid.toString();
+ }
+
+ public final void setOFVersion(OFVersion ofV) {
+ this.ofVersion = ofV;
+ }
+
+ void setTableFull(boolean full) {
+ this.tableFull = full;
+ }
+
+ public abstract void setFeaturesReply(OFFeaturesReply featuresReply);
+
+ /**
+ * Let peoeple know if you support Nicira style role requests.
+ *
+ * @return support Nicira roles or not.
+ */
+ public abstract Boolean supportNxRole();
+
+ //************************
+ // Message handling
+ //************************
+ /**
+ * Handle the message coming from the dataplane.
+ *
+ * @param m the actual message
+ */
+ public final void handleMessage(OFMessage m) {
+ this.agent.processMessage(m);
+ }
+
+ public abstract RoleState getRole();
+
+ final boolean addConnectedSwitch() {
+ return this.agent.addConnectedSwitch(this.getId(), this);
+ }
+
+ final boolean addActivatedMasterSwitch() {
+ return this.agent.addActivatedMasterSwitch(this.getId(), this);
+ }
+
+ final boolean addActivatedEqualSwitch() {
+ return this.agent.addActivatedEqualSwitch(this.getId(), this);
+ }
+
+ final void transitionToEqualSwitch() {
+ this.agent.transitionToEqualSwitch(this.getId());
+ }
+
+ final void transitionToMasterSwitch() {
+ this.agent.transitionToMasterSwitch(this.getId());
+ }
+
+ final void removeConnectedSwitch() {
+ this.agent.removeConnectedSwitch(this.getId());
+ }
+
+ protected OFFactory factory() {
+ return OFFactories.getFactory(ofVersion);
+ }
+
+ public void setPortDescReply(OFPortDescStatsReply portDescReply) {
+ this.ports = portDescReply;
+ }
+
+ public abstract void startDriverHandshake();
+
+ public abstract boolean isDriverHandshakeComplete();
+
+ public abstract void processDriverHandshakeMessage(OFMessage m);
+
+ public void setRole(RoleState role) {
+ try {
+ this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE);
+ } catch (IOException e) {
+ log.error("Unable to write to switch {}.", this.dpid);
+ }
+ }
+
+ // Role Handling
+
+ void handleRole(OFMessage m) throws SwitchStateException {
+ RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
+ RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
+ if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+ if (rri.getRole() == RoleState.MASTER) {
+ this.transitionToMasterSwitch();
+ } else if (rri.getRole() == RoleState.EQUAL ||
+ rri.getRole() == RoleState.MASTER) {
+ this.transitionToEqualSwitch();
+ }
+ }
+ }
+
+ void handleNiciraRole(OFMessage m) throws SwitchStateException {
+ RoleState role = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
+ if (role == null) {
+ // The message wasn't really a Nicira role reply. We just
+ // dispatch it to the OFMessage listeners in this case.
+ this.handleMessage(m);
+ }
+
+ RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
+ new RoleReplyInfo(role, null, m.getXid()));
+ if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+ if (role == RoleState.MASTER) {
+ this.transitionToMasterSwitch();
+ } else if (role == RoleState.EQUAL ||
+ role == RoleState.SLAVE) {
+ this.transitionToEqualSwitch();
+ }
+ }
+ }
+
+ boolean handleRoleError(OFErrorMsg error) {
+ try {
+ return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
+ } catch (SwitchStateException e) {
+ this.disconnectSwitch();
+ }
+ return true;
+ }
+
+ void reassertRole() {
+ if (this.getRole() == RoleState.MASTER) {
+ this.setRole(RoleState.MASTER);
+ }
+ }
+
+ void setAgent(OpenFlowSwitchAgent ag) {
+ this.agent = ag;
+ }
+
+
+
+}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/Controller.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/Controller.java
index 1f0b36d..6ae3abb 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/Controller.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/Controller.java
@@ -20,47 +20,22 @@
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
-import org.onlab.onos.of.controller.impl.IOFSwitchManager;
-import org.onlab.onos.of.controller.impl.Role;
-import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
-import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
-import org.onlab.onos.of.controller.impl.debugcounter.DebugCounter;
-import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounter;
-import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService;
-import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService.CounterException;
-import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService.CounterType;
-import org.onlab.onos.of.controller.impl.internal.OFChannelHandler.RoleRecvStatus;
-import org.onlab.onos.of.controller.impl.registry.IControllerRegistry;
-import org.onlab.onos.of.controller.impl.registry.RegistryException;
-import org.onlab.onos.of.controller.impl.registry.IControllerRegistry.ControlChangeCallback;
-import org.onlab.onos.of.controller.impl.util.Dpid;
-import org.onlab.onos.of.controller.impl.util.DummySwitchForTesting;
-import org.onlab.onos.of.controller.impl.util.InstanceId;
-import org.onlab.onos.of.controller.impl.IOFSwitch;
-import org.onlab.onos.of.controller.impl.IOFSwitch.PortChangeType;
-
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
+import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
+import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
+import org.onlab.onos.of.controller.impl.internal.OpenFlowControllerImpl.OpenFlowSwitchAgent;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.projectfloodlight.openflow.util.HexString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -69,7 +44,6 @@
* The main controller class. Handles all setup and network listeners
* - Distributed ownership control of switch through IControllerRegistryService
*/
-@Component(immediate = true)
public class Controller {
protected static final Logger log = LoggerFactory.getLogger(Controller.class);
@@ -78,189 +52,33 @@
protected static final OFFactory FACTORY13 = OFFactories.getFactory(OFVersion.OF_13);
protected static final OFFactory FACTORY10 = OFFactories.getFactory(OFVersion.OF_10);
- // connectedSwitches cache contains all connected switch's channelHandlers
- // including ones where this controller is a master/equal/slave controller
- // as well as ones that have not been activated yet
- protected ConcurrentHashMap<Long, OFChannelHandler> connectedSwitches;
- // These caches contains only those switches that are active
- protected ConcurrentHashMap<Long, IOFSwitch> activeMasterSwitches;
- protected ConcurrentHashMap<Long, IOFSwitch> activeEqualSwitches;
- // lock to synchronize on, when manipulating multiple caches above
- private Object multiCacheLock;
+
// The controllerNodeIPsCache maps Controller IDs to their IP address.
// It's only used by handleControllerNodeIPsChanged
protected HashMap<String, String> controllerNodeIPsCache;
- // Module dependencies
-
- protected IControllerRegistry registryService;
- protected IDebugCounterService debugCounters;
-
private IOFSwitchManager switchManager;
+ private ChannelGroup cg;
+
// Configuration options
protected int openFlowPort = 6633;
protected int workerThreads = 0;
- // defined counters
- private Counters counters;
-
// Start time of the controller
protected long systemStartTime;
// Flag to always flush flow table on switch reconnect (HA or otherwise)
protected boolean alwaysClearFlowsOnSwAdd = false;
- private InstanceId instanceId;
+ private OpenFlowSwitchAgent agent;
// Perf. related configuration
protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
protected static final int BATCH_MAX_SIZE = 100;
protected static final boolean ALWAYS_DECODE_ETH = true;
- protected boolean addConnectedSwitch(long dpid, OFChannelHandler h) {
- if (connectedSwitches.get(dpid) != null) {
- log.error("Trying to add connectedSwitch but found a previous "
- + "value for dpid: {}", dpid);
- return false;
- } else {
- log.error("Added switch {}", dpid);
- connectedSwitches.put(dpid, h);
- return true;
- }
- }
-
- private boolean validActivation(long dpid) {
- if (connectedSwitches.get(dpid) == null) {
- log.error("Trying to activate switch but is not in "
- + "connected switches: dpid {}. Aborting ..",
- HexString.toHexString(dpid));
- return false;
- }
- if (activeMasterSwitches.get(dpid) != null ||
- activeEqualSwitches.get(dpid) != null) {
- log.error("Trying to activate switch but it is already "
- + "activated: dpid {}. Found in activeMaster: {} "
- + "Found in activeEqual: {}. Aborting ..", new Object[] {
- HexString.toHexString(dpid),
- (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
- (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
- counters.switchWithSameDpidActivated.updateCounterWithFlush();
- return false;
- }
- return true;
- }
-
- /**
- * Called when a switch is activated, with this controller's role as MASTER.
- */
- protected boolean addActivatedMasterSwitch(long dpid, IOFSwitch sw) {
- synchronized (multiCacheLock) {
- if (!validActivation(dpid)) {
- return false;
- }
- activeMasterSwitches.put(dpid, sw);
- }
- //update counters and events
- counters.switchActivated.updateCounterWithFlush();
-
- return true;
- }
-
- /**
- * Called when a switch is activated, with this controller's role as EQUAL.
- */
- protected boolean addActivatedEqualSwitch(long dpid, IOFSwitch sw) {
- synchronized (multiCacheLock) {
- if (!validActivation(dpid)) {
- return false;
- }
- activeEqualSwitches.put(dpid, sw);
- }
- //update counters and events
- counters.switchActivated.updateCounterWithFlush();
- return true;
- }
-
- /**
- * Called when this controller's role for a switch transitions from equal
- * to master. For 1.0 switches, we internally refer to the role 'slave' as
- * 'equal' - so this transition is equivalent to 'addActivatedMasterSwitch'.
- */
- protected void transitionToMasterSwitch(long dpid) {
- synchronized (multiCacheLock) {
- IOFSwitch sw = activeEqualSwitches.remove(dpid);
- if (sw == null) {
- log.error("Transition to master called on sw {}, but switch "
- + "was not found in controller-cache", dpid);
- return;
- }
- activeMasterSwitches.put(dpid, sw);
- }
- }
-
-
- /**
- * Called when this controller's role for a switch transitions to equal.
- * For 1.0 switches, we internally refer to the role 'slave' as
- * 'equal'.
- */
- protected void transitionToEqualSwitch(long dpid) {
- synchronized (multiCacheLock) {
- IOFSwitch sw = activeMasterSwitches.remove(dpid);
- if (sw == null) {
- log.error("Transition to equal called on sw {}, but switch "
- + "was not found in controller-cache", dpid);
- return;
- }
- activeEqualSwitches.put(dpid, sw);
- }
-
- }
-
- /**
- * Clear all state in controller switch maps for a switch that has
- * disconnected from the local controller. Also release control for
- * that switch from the global repository. Notify switch listeners.
- */
- protected void removeConnectedSwitch(long dpid) {
- releaseRegistryControl(dpid);
- connectedSwitches.remove(dpid);
- IOFSwitch sw = activeMasterSwitches.remove(dpid);
- if (sw == null) {
- sw = activeEqualSwitches.remove(dpid);
- }
- if (sw != null) {
- sw.cancelAllStatisticsReplies();
- sw.setConnected(false); // do we need this?
- }
- counters.switchDisconnected.updateCounterWithFlush();
-
- }
-
- /**
- * Indicates that ports on the given switch have changed. Enqueue a
- * switch update.
- * @param dpid
- * @param port
- * @param changeType
- */
- protected void notifyPortChanged(long dpid, OFPortDesc port,
- PortChangeType changeType) {
- if (port == null || changeType == null) {
- String msg = String.format("Switch port or changetType must not "
- + "be null in port change notification");
- throw new NullPointerException(msg);
- }
- if (connectedSwitches.get(dpid) == null || getSwitch(dpid) == null) {
- log.warn("Port change update on switch {} not connected or activated "
- + "... Aborting.", HexString.toHexString(dpid));
- return;
- }
-
- }
-
// ***************
// Getters/Setters
// ***************
@@ -268,180 +86,8 @@
public synchronized void setIOFSwitchManager(IOFSwitchManager swManager) {
this.switchManager = swManager;
- this.registryService = swManager.getRegistry();
}
-
- public void setDebugCounter(IDebugCounterService dcs) {
- this.debugCounters = dcs;
- }
-
- IDebugCounterService getDebugCounter() {
- return this.debugCounters;
- }
-
- // **********************
- // Role Handling
- // **********************
-
- /**
- * created by ONOS - works with registry service.
- */
- protected class RoleChangeCallback implements ControlChangeCallback {
- @Override
- public void controlChanged(long dpidLong, boolean hasControl) {
- Dpid dpid = new Dpid(dpidLong);
- log.info("Role change callback for switch {}, hasControl {}",
- dpid, hasControl);
-
- Role role = null;
-
- /*
- * issue #229
- * Cannot rely on sw.getRole() as it can be behind due to pending
- * role changes in the queue. Just submit it and late the
- * RoleChanger handle duplicates.
- */
-
- if (hasControl) {
- role = Role.MASTER;
- } else {
- role = Role.EQUAL; // treat the same as Role.SLAVE
- }
-
- OFChannelHandler swCh = connectedSwitches.get(dpid.value());
- if (swCh == null) {
- log.warn("Switch {} not found in connected switches", dpid);
- return;
- }
-
- log.debug("Sending role request {} msg to {}", role, dpid);
- swCh.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE);
- }
- }
-
- /**
- * Submit request to the registry service for mastership of the
- * switch.
- * @param dpid this datapath to get role for
- */
- public synchronized void submitRegistryRequest(long dpid) {
- if (registryService == null) {
- /*
- * If we have no registry then simply assign
- * mastership to this controller.
- */
- new RoleChangeCallback().controlChanged(dpid, true);
- return;
- }
- OFChannelHandler h = connectedSwitches.get(dpid);
- if (h == null) {
- log.error("Trying to request registry control for switch {} "
- + "not in connected switches. Aborting.. ",
- HexString.toHexString(dpid));
- connectedSwitches.get(dpid).disconnectSwitch();
- return;
- }
- //Request control of the switch from the global registry
- try {
- h.controlRequested = Boolean.TRUE;
- registryService.requestControl(dpid, new RoleChangeCallback());
- } catch (RegistryException e) {
- log.debug("Registry error: {}", e.getMessage());
- h.controlRequested = Boolean.FALSE;
- }
- if (!h.controlRequested) { // XXX what is being attempted here?
- // yield to allow other thread(s) to release control
- // TODO AAS: this is awful and needs to be fixed
- Thread.yield();
- // safer to bounce the switch to reconnect here than proceeding further
- // XXX S why? can't we just try again a little later?
- log.debug("Closing sw:{} because we weren't able to request control " +
- "successfully" + dpid);
- connectedSwitches.get(dpid).disconnectSwitch();
- }
- }
-
- /**
- * Relinquish role for the switch.
- * @param dpidLong the controlled datapath
- */
- public synchronized void releaseRegistryControl(long dpidLong) {
- OFChannelHandler h = connectedSwitches.get(dpidLong);
- if (h == null) {
- log.error("Trying to release registry control for switch {} "
- + "not in connected switches. Aborting.. ",
- HexString.toHexString(dpidLong));
- return;
- }
- if (registryService != null && h.controlRequested) {
- //TODO the above is not good for testing need to change controlrequest to method call.
- registryService.releaseControl(dpidLong);
- }
- }
-
-
- // FIXME: remove this method
- public Map<Long, IOFSwitch> getSwitches() {
- return getMasterSwitches();
- }
-
- // FIXME: remove this method
- public Map<Long, IOFSwitch> getMasterSwitches() {
- return Collections.unmodifiableMap(activeMasterSwitches);
- }
-
-
-
- public Set<Long> getAllSwitchDpids() {
- Set<Long> dpids = new HashSet<Long>();
- dpids.addAll(activeMasterSwitches.keySet());
- dpids.addAll(activeEqualSwitches.keySet());
- return dpids;
- }
-
-
- public Set<Long> getAllMasterSwitchDpids() {
- Set<Long> dpids = new HashSet<Long>();
- dpids.addAll(activeMasterSwitches.keySet());
- return dpids;
- }
-
-
- public Set<Long> getAllEqualSwitchDpids() {
- Set<Long> dpids = new HashSet<Long>();
- dpids.addAll(activeEqualSwitches.keySet());
- return dpids;
- }
-
-
- public IOFSwitch getSwitch(long dpid) {
- IOFSwitch sw = null;
- sw = activeMasterSwitches.get(dpid);
- if (sw != null) {
- return sw;
- }
- sw = activeEqualSwitches.get(dpid);
- if (sw != null) {
- return sw;
- }
- return sw;
- }
-
-
- public IOFSwitch getMasterSwitch(long dpid) {
- return activeMasterSwitches.get(dpid);
- }
-
-
- public IOFSwitch getEqualSwitch(long dpid) {
- return activeEqualSwitches.get(dpid);
- }
-
-
-
-
-
public OFFactory getOFMessageFactory10() {
return FACTORY10;
}
@@ -469,12 +115,6 @@
return (this.systemStartTime);
}
-
- public InstanceId getInstanceId() {
- return instanceId;
- }
-
-
// **************
// Initialization
// **************
@@ -509,7 +149,7 @@
new OpenflowPipelineFactory(this, null);
bootstrap.setPipelineFactory(pfact);
InetSocketAddress sa = new InetSocketAddress(openFlowPort);
- final ChannelGroup cg = new DefaultChannelGroup();
+ cg = new DefaultChannelGroup();
cg.add(bootstrap.bind(sa));
log.info("Listening for switch connections on {}", sa);
@@ -544,20 +184,6 @@
this.workerThreads = Integer.parseInt(threads);
}
log.debug("Number of worker threads set to {}", this.workerThreads);
- String controllerId = configParams.get("controllerid");
- if (controllerId != null) {
- this.instanceId = new InstanceId(controllerId);
- } else {
- //Try to get the hostname of the machine and use that for controller ID
- try {
- String hostname = java.net.InetAddress.getLocalHost().getHostName();
- this.instanceId = new InstanceId(hostname);
- } catch (UnknownHostException e) {
- log.warn("Can't get hostname, using the default");
- }
- }
-
- log.debug("ControllerId set to {}", this.instanceId);
}
@@ -567,16 +193,11 @@
public void init(Map<String, String> configParams) {
// These data structures are initialized here because other
// module's startUp() might be called before ours
- this.activeMasterSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
- this.activeEqualSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
- this.connectedSwitches = new ConcurrentHashMap<Long, OFChannelHandler>();
this.controllerNodeIPsCache = new HashMap<String, String>();
setConfigParams(configParams);
this.systemStartTime = System.currentTimeMillis();
- this.setDebugCounter(new DebugCounter());
- this.counters = new Counters();
- this.multiCacheLock = new Object();
+
}
@@ -589,215 +210,10 @@
"that the system database has failed to start. " +
LogMessageDoc.CHECK_CONTROLLER)
public synchronized void startupComponents() {
- try {
- if (registryService != null) {
- registryService.registerController(instanceId.toString());
- }
- } catch (RegistryException e) {
- log.warn("Registry service error: {}", e.getMessage());
- }
-
- // register counters and events
- try {
- this.counters.createCounters(debugCounters);
- } catch (CounterException e) {
- log.warn("Counters unavailable: {}", e.getMessage());
- }
+ //TODO do something maybe
}
// **************
- // debugCounter registrations
- // **************
-
- public static class Counters {
- public static final String PREFIX = "controller";
- public IDebugCounter switchActivated;
- public IDebugCounter switchWithSameDpidActivated; // warn
- public IDebugCounter switchDisconnected;
- public IDebugCounter messageReceived;
- public IDebugCounter switchDisconnectReadTimeout;
- public IDebugCounter switchDisconnectHandshakeTimeout;
- public IDebugCounter switchDisconnectIOError;
- public IDebugCounter switchDisconnectParseError;
- public IDebugCounter switchDisconnectSwitchStateException;
- public IDebugCounter rejectedExecutionException;
- public IDebugCounter switchDisconnectOtherException;
- public IDebugCounter switchConnected;
- public IDebugCounter unhandledMessage;
- public IDebugCounter packetInWhileSwitchIsSlave;
- public IDebugCounter epermErrorWhileSwitchIsMaster;
- public IDebugCounter roleReplyTimeout;
- public IDebugCounter roleReplyReceived; // expected RoleReply received
- public IDebugCounter roleReplyErrorUnsupported;
- public IDebugCounter switchCounterRegistrationFailed;
-
- void createCounters(IDebugCounterService debugCounters) throws CounterException {
-
- switchActivated =
- debugCounters.registerCounter(
- PREFIX, "switch-activated",
- "A switch connected to this controller is now " +
- "in MASTER role",
- CounterType.ALWAYS_COUNT);
-
- switchWithSameDpidActivated = // warn
- debugCounters.registerCounter(
- PREFIX, "switch-with-same-dpid-activated",
- "A switch with the same DPID as another switch " +
- "connected to the controller. This can be " +
- "caused by multiple switches configured with " +
- "the same DPID or by a switch reconnecting very " +
- "quickly.",
- CounterType.COUNT_ON_DEMAND,
- IDebugCounterService.CTR_MDATA_WARN);
-
- switchDisconnected =
- debugCounters.registerCounter(
- PREFIX, "switch-disconnected",
- "FIXME: switch has disconnected",
- CounterType.ALWAYS_COUNT);
-
- //------------------------
- // channel handler counters. Factor them out ??
- messageReceived =
- debugCounters.registerCounter(
- PREFIX, "message-received",
- "Number of OpenFlow messages received. Some of " +
- "these might be throttled",
- CounterType.ALWAYS_COUNT);
-
- switchDisconnectReadTimeout =
- debugCounters.registerCounter(
- PREFIX, "switch-disconnect-read-timeout",
- "Number of times a switch was disconnected due " +
- "due the switch failing to send OpenFlow " +
- "messages or responding to OpenFlow ECHOs",
- CounterType.ALWAYS_COUNT,
- IDebugCounterService.CTR_MDATA_ERROR);
- switchDisconnectHandshakeTimeout =
- debugCounters.registerCounter(
- PREFIX, "switch-disconnect-handshake-timeout",
- "Number of times a switch was disconnected " +
- "because it failed to complete the handshake " +
- "in time.",
- CounterType.ALWAYS_COUNT,
- IDebugCounterService.CTR_MDATA_ERROR);
- switchDisconnectIOError =
- debugCounters.registerCounter(
- PREFIX, "switch-disconnect-io-error",
- "Number of times a switch was disconnected " +
- "due to IO errors on the switch connection.",
- CounterType.ALWAYS_COUNT,
- IDebugCounterService.CTR_MDATA_ERROR);
- switchDisconnectParseError =
- debugCounters.registerCounter(
- PREFIX, "switch-disconnect-parse-error",
- "Number of times a switch was disconnected " +
- "because it sent an invalid packet that could " +
- "not be parsed",
- CounterType.ALWAYS_COUNT,
- IDebugCounterService.CTR_MDATA_ERROR);
-
- switchDisconnectSwitchStateException =
- debugCounters.registerCounter(
- PREFIX, "switch-disconnect-switch-state-exception",
- "Number of times a switch was disconnected " +
- "because it sent messages that were invalid " +
- "given the switch connection's state.",
- CounterType.ALWAYS_COUNT,
- IDebugCounterService.CTR_MDATA_ERROR);
- rejectedExecutionException =
- debugCounters.registerCounter(
- PREFIX, "rejected-execution-exception",
- "TODO",
- CounterType.ALWAYS_COUNT,
- IDebugCounterService.CTR_MDATA_ERROR);
-
- switchDisconnectOtherException =
- debugCounters.registerCounter(
- PREFIX, "switch-disconnect-other-exception",
- "Number of times a switch was disconnected " +
- "due to an exceptional situation not covered " +
- "by other counters",
- CounterType.ALWAYS_COUNT,
- IDebugCounterService.CTR_MDATA_ERROR);
-
- switchConnected =
- debugCounters.registerCounter(
- PREFIX, "switch-connected",
- "Number of times a new switch connection was " +
- "established",
- CounterType.ALWAYS_COUNT);
-
- unhandledMessage =
- debugCounters.registerCounter(
- PREFIX, "unhandled-message",
- "Number of times an OpenFlow message was " +
- "received that the controller ignored because " +
- "it was inapproriate given the switch " +
- "connection's state.",
- CounterType.ALWAYS_COUNT,
- IDebugCounterService.CTR_MDATA_WARN);
- // might be less than warning
-
- packetInWhileSwitchIsSlave =
- debugCounters.registerCounter(
- PREFIX, "packet-in-while-switch-is-slave",
- "Number of times a packet in was received " +
- "from a switch that was in SLAVE role. " +
- "Possibly inidicates inconsistent roles.",
- CounterType.ALWAYS_COUNT);
- epermErrorWhileSwitchIsMaster =
- debugCounters.registerCounter(
- PREFIX, "eperm-error-while-switch-is-master",
- "Number of times a permission error was " +
- "received while the switch was in MASTER role. " +
- "Possibly inidicates inconsistent roles.",
- CounterType.ALWAYS_COUNT,
- IDebugCounterService.CTR_MDATA_WARN);
-
- roleReplyTimeout =
- debugCounters.registerCounter(
- PREFIX, "role-reply-timeout",
- "Number of times a role request message did not " +
- "receive the expected reply from a switch",
- CounterType.ALWAYS_COUNT,
- IDebugCounterService.CTR_MDATA_WARN);
-
- roleReplyReceived = // expected RoleReply received
- debugCounters.registerCounter(
- PREFIX, "role-reply-received",
- "Number of times the controller received the " +
- "expected role reply message from a switch",
- CounterType.ALWAYS_COUNT);
-
- roleReplyErrorUnsupported =
- debugCounters.registerCounter(
- PREFIX, "role-reply-error-unsupported",
- "Number of times the controller received an " +
- "error from a switch in response to a role " +
- "request indicating that the switch does not " +
- "support roles.",
- CounterType.ALWAYS_COUNT);
-
- switchCounterRegistrationFailed =
- debugCounters.registerCounter(PREFIX,
- "switch-counter-registration-failed",
- "Number of times the controller failed to " +
- "register per-switch debug counters",
- CounterType.ALWAYS_COUNT,
- IDebugCounterService.CTR_MDATA_WARN);
-
-
- }
- }
-
- public Counters getCounters() {
- return this.counters;
- }
-
-
- // **************
// Utility methods
// **************
@@ -820,20 +236,24 @@
* @param desc
* @return switch instance
*/
- protected IOFSwitch getOFSwitchInstance(OFDescStatsReply desc, OFVersion ofv) {
- if (switchManager == null) {
- return new DummySwitchForTesting();
- }
- return switchManager.getSwitchImpl(desc.getMfrDesc(), desc.getHwDesc(),
+ protected AbstractOpenFlowSwitch getOFSwitchInstance(OFDescStatsReply desc, OFVersion ofv) {
+ AbstractOpenFlowSwitch sw = switchManager.getSwitchImpl(desc.getMfrDesc(), desc.getHwDesc(),
desc.getSwDesc(), ofv);
+ sw.setAgent(agent);
+ return sw;
}
- @Activate
- public void activate() {
+ public void start(OpenFlowSwitchAgent ag) {
log.info("Initialising OpenFlow Lib and IO");
+ this.agent = ag;
this.init(new HashMap<String, String>());
this.startupComponents();
this.run();
}
+
+ public void stop() {
+ cg.close();
+ }
+
}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/IOFSwitchManager.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/IOFSwitchManager.java
similarity index 61%
rename from of/ctl/src/main/java/org/onlab/onos/of/controller/impl/IOFSwitchManager.java
rename to of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/IOFSwitchManager.java
index 0acb321..4b2f7c3 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/IOFSwitchManager.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/IOFSwitchManager.java
@@ -1,8 +1,7 @@
-package org.onlab.onos.of.controller.impl;
+package org.onlab.onos.of.controller.impl.internal;
import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.onlab.onos.of.controller.impl.registry.IControllerRegistry;
/**
* Interface to passed to controller class in order to allow
@@ -22,12 +21,6 @@
* @param ofv openflow version
* @return A switch of type IOFSwitch.
*/
- public IOFSwitch getSwitchImpl(String mfr, String hwDesc, String swDesc, OFVersion ofv);
-
- /**
- * Returns the mastership registry used during controller-switch role election.
- * @return the registry
- */
- public IControllerRegistry getRegistry();
+ public AbstractOpenFlowSwitch getSwitchImpl(String mfr, String hwDesc, String swDesc, OFVersion ofv);
}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandler.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandler.java
index 667a051..5db1fc3 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandler.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandler.java
@@ -4,21 +4,11 @@
import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.RejectedExecutionException;
-import org.onlab.onos.of.controller.impl.IOFSwitch;
-import org.onlab.onos.of.controller.impl.IOFSwitch.PortChangeEvent;
-import org.onlab.onos.of.controller.impl.Role;
-import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
-import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
-import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService.CounterException;
-import org.onlab.onos.of.controller.impl.internal.Controller.Counters;
-import org.onlab.onos.of.controller.impl.internal.OFChannelHandler.ChannelState.RoleReplyInfo;
-
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
@@ -27,12 +17,14 @@
import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
import org.jboss.netty.handler.timeout.IdleStateEvent;
import org.jboss.netty.handler.timeout.ReadTimeoutException;
+import org.onlab.onos.of.controller.RoleState;
+import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
+import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
import org.projectfloodlight.openflow.protocol.OFBarrierReply;
import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
-import org.projectfloodlight.openflow.protocol.OFControllerRole;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFDescStatsRequest;
import org.projectfloodlight.openflow.protocol.OFEchoReply;
@@ -49,15 +41,12 @@
import org.projectfloodlight.openflow.protocol.OFHello;
import org.projectfloodlight.openflow.protocol.OFHelloElem;
import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
-import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFPortDescStatsRequest;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply;
import org.projectfloodlight.openflow.protocol.OFRoleReply;
-import org.projectfloodlight.openflow.protocol.OFRoleRequest;
import org.projectfloodlight.openflow.protocol.OFSetConfig;
import org.projectfloodlight.openflow.protocol.OFStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
@@ -66,11 +55,10 @@
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
-import org.projectfloodlight.openflow.protocol.errormsg.OFRoleRequestFailedErrorMsg;
import org.projectfloodlight.openflow.types.U32;
-import org.projectfloodlight.openflow.types.U64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
/**
* Channel handler deals with the switch connection and dispatches
* switch messages to the appropriate locations.
@@ -79,18 +67,13 @@
private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
private static final long DEFAULT_ROLE_TIMEOUT_MS = 2 * 1000; // 10 sec
private final Controller controller;
- private final Counters counters;
- private IOFSwitch sw;
+ private AbstractOpenFlowSwitch sw;
private long thisdpid; // channelHandler cached value of connected switch id
private Channel channel;
// State needs to be volatile because the HandshakeTimeoutHandler
// needs to check if the handshake is complete
private volatile ChannelState state;
- // All role messaging is handled by the roleChanger. The channel state machine
- // coordinates between the roleChanger and the controller-global-registry-service
- // to determine controller roles per switch.
- private RoleChanger roleChanger;
// Used to coordinate between the controller and the cleanup thread(?)
// for access to the global registry on a per switch basis.
volatile Boolean controlRequested;
@@ -125,8 +108,6 @@
*/
OFChannelHandler(Controller controller) {
this.controller = controller;
- this.counters = controller.getCounters();
- this.roleChanger = new RoleChanger(DEFAULT_ROLE_TIMEOUT_MS);
this.state = ChannelState.INIT;
this.pendingPortStatusMsg = new CopyOnWriteArrayList<OFPortStatus>();
factory13 = controller.getOFMessageFactory13();
@@ -135,392 +116,14 @@
duplicateDpidFound = Boolean.FALSE;
}
- //*******************
- // Role Handling
- //*******************
- /**
- * When we remove a pending role request we use this enum to indicate how we
- * arrived at the decision. When we send a role request to the switch, we
- * also use this enum to indicate what we expect back from the switch, so the
- * role changer can match the reply to our expectation.
- */
- public enum RoleRecvStatus {
- /** The switch returned an error indicating that roles are not.
- * supported*/
- UNSUPPORTED,
- /** The request timed out. */
- NO_REPLY,
- /** The reply was old, there is a newer request pending. */
- OLD_REPLY,
- /**
- * The reply's role matched the role that this controller set in the
- * request message - invoked either initially at startup or to reassert
- * current role.
- */
- MATCHED_CURRENT_ROLE,
- /**
- * The reply's role matched the role that this controller set in the
- * request message - this is the result of a callback from the
- * global registry, followed by a role request sent to the switch.
- */
- MATCHED_SET_ROLE,
- /**
- * The reply's role was a response to the query made by this controller.
- */
- REPLY_QUERY,
- /** We received a role reply message from the switch
- * but the expectation was unclear, or there was no expectation.
- */
- OTHER_EXPECTATION,
- }
-
- /**
- * Forwards to RoleChanger. See there.
- * @param role
- */
- public void sendRoleRequest(Role role, RoleRecvStatus expectation) {
- try {
- roleChanger.sendRoleRequest(role, expectation);
- } catch (IOException e) {
- log.error("Disconnecting switch {} due to IO Error: {}",
- getSwitchInfoString(), e.getMessage());
- channel.close();
- }
- }
// XXX S consider if necessary
public void disconnectSwitch() {
sw.disconnectSwitch();
}
- /**
- * A utility class to handle role requests and replies for this channel.
- * After a role request is submitted the role changer keeps track of the
- * pending request, collects the reply (if any) and times out the request
- * if necessary.
- *
- * To simplify role handling we only keep track of the /last/ pending
- * role reply send to the switch. If multiple requests are pending and
- * we receive replies for earlier requests we ignore them. However, this
- * way of handling pending requests implies that we could wait forever if
- * a new request is submitted before the timeout triggers. If necessary
- * we could work around that though.
- */
- private class RoleChanger {
- // indicates that a request is currently pending
- // needs to be volatile to allow correct double-check idiom
- private volatile boolean requestPending;
- // the transaction Id of the pending request
- private int pendingXid;
- // the role that's pending
- private Role pendingRole;
- // system time in MS when we send the request
- private long roleSubmitTime;
- // the timeout to use
- private final long roleTimeoutMs;
- // the expectation set by the caller for the returned role
- private RoleRecvStatus expectation;
- public RoleChanger(long roleTimeoutMs) {
- this.requestPending = false;
- this.roleSubmitTime = 0;
- this.pendingXid = -1;
- this.pendingRole = null;
- this.roleTimeoutMs = roleTimeoutMs;
- this.expectation = RoleRecvStatus.MATCHED_CURRENT_ROLE;
- }
-
- /**
- * Send NX role request message to the switch requesting the specified
- * role.
- *
- * @param sw switch to send the role request message to
- * @param role role to request
- */
- private int sendNxRoleRequest(Role role) throws IOException {
- // Convert the role enum to the appropriate role to send
- OFNiciraControllerRole roleToSend = OFNiciraControllerRole.ROLE_OTHER;
- switch (role) {
- case MASTER:
- roleToSend = OFNiciraControllerRole.ROLE_MASTER;
- break;
- case SLAVE:
- case EQUAL:
- default:
- // ensuring that the only two roles sent to 1.0 switches with
- // Nicira role support, are MASTER and SLAVE
- roleToSend = OFNiciraControllerRole.ROLE_SLAVE;
- log.warn("Sending Nx Role.SLAVE to switch {}.", sw);
- }
- int xid = sw.getNextTransactionId();
- OFExperimenter roleRequest = factory10
- .buildNiciraControllerRoleRequest()
- .setXid(xid)
- .setRole(roleToSend)
- .build();
- sw.write(Collections.<OFMessage>singletonList(roleRequest));
- return xid;
- }
-
- private int sendOF13RoleRequest(Role role) throws IOException {
- // Convert the role enum to the appropriate role to send
- OFControllerRole roleToSend = OFControllerRole.ROLE_NOCHANGE;
- switch (role) {
- case EQUAL:
- roleToSend = OFControllerRole.ROLE_EQUAL;
- break;
- case MASTER:
- roleToSend = OFControllerRole.ROLE_MASTER;
- break;
- case SLAVE:
- roleToSend = OFControllerRole.ROLE_SLAVE;
- break;
- default:
- log.warn("Sending default role.noChange to switch {}."
- + " Should only be used for queries.", sw);
- }
-
- int xid = sw.getNextTransactionId();
- OFRoleRequest rrm = factory13
- .buildRoleRequest()
- .setRole(roleToSend)
- .setXid(xid)
- .setGenerationId(sw.getNextGenerationId())
- .build();
- sw.write(rrm);
- return xid;
- }
-
- /**
- * Send a role request with the given role to the switch and update
- * the pending request and timestamp.
- * Sends an OFPT_ROLE_REQUEST to an OF1.3 switch, OR
- * Sends an NX_ROLE_REQUEST to an OF1.0 switch if configured to support it
- * in the IOFSwitch driver. If not supported, this method sends nothing
- * and returns 'false'. The caller should take appropriate action.
- *
- * One other optimization we do here is that for OF1.0 switches with
- * Nicira role message support, we force the Role.EQUAL to become
- * Role.SLAVE, as there is no defined behavior for the Nicira role OTHER.
- * We cannot expect it to behave like SLAVE. We don't have this problem with
- * OF1.3 switches, because Role.EQUAL is well defined and we can simulate
- * SLAVE behavior by using ASYNC messages.
- *
- * @param role
- * @throws IOException
- * @returns false if and only if the switch does not support role-request
- * messages, according to the switch driver; true otherwise.
- */
- synchronized boolean sendRoleRequest(Role role, RoleRecvStatus exp)
- throws IOException {
- this.expectation = exp;
-
- if (ofVersion == OFVersion.OF_10) {
- Boolean supportsNxRole = (Boolean)
- sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
- if (!supportsNxRole) {
- log.debug("Switch driver indicates no support for Nicira "
- + "role request messages. Not sending ...");
- state.handleUnsentRoleMessage(OFChannelHandler.this, role,
- expectation);
- return false;
- }
- // OF1.0 switch with support for NX_ROLE_REQUEST vendor extn.
- // make Role.EQUAL become Role.SLAVE
- role = (role == Role.EQUAL) ? Role.SLAVE : role;
- pendingXid = sendNxRoleRequest(role);
- pendingRole = role;
- roleSubmitTime = System.currentTimeMillis();
- requestPending = true;
- } else {
- // OF1.3 switch, use OFPT_ROLE_REQUEST message
- pendingXid = sendOF13RoleRequest(role);
- pendingRole = role;
- roleSubmitTime = System.currentTimeMillis();
- requestPending = true;
- }
- return true;
- }
-
- /**
- * Deliver a received role reply.
- *
- * Check if a request is pending and if the received reply matches the
- * the expected pending reply (we check both role and xid) we set
- * the role for the switch/channel.
- *
- * If a request is pending but doesn't match the reply we ignore it, and
- * return
- *
- * If no request is pending we disconnect with a SwitchStateException
- *
- * @param RoleReplyInfo information about role-reply in format that
- * controller can understand.
- * @throws SwitchStateException if no request is pending
- */
- synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
- throws SwitchStateException {
- if (!requestPending) {
- Role currentRole = (sw != null) ? sw.getRole() : null;
- if (currentRole != null) {
- if (currentRole == rri.getRole()) {
- // Don't disconnect if the role reply we received is
- // for the same role we are already in.
- log.debug("Received unexpected RoleReply from "
- + "Switch: {} in State: {}. "
- + "Role in reply is same as current role of this "
- + "controller for this sw. Ignoring ...",
- getSwitchInfoString(), state.toString());
- return RoleRecvStatus.OTHER_EXPECTATION;
- } else {
- String msg = String.format("Switch: [%s], State: [%s], "
- + "received unexpected RoleReply[%s]. "
- + "No roles are pending, and this controller's "
- + "current role:[%s] does not match reply. "
- + "Disconnecting switch ... ",
- OFChannelHandler.this.getSwitchInfoString(),
- OFChannelHandler.this.state.toString(),
- rri, currentRole);
- throw new SwitchStateException(msg);
- }
- }
- log.debug("Received unexpected RoleReply {} from "
- + "Switch: {} in State: {}. "
- + "This controller has no current role for this sw. "
- + "Ignoring ...", new Object[] {rri,
- getSwitchInfoString(), state});
- return RoleRecvStatus.OTHER_EXPECTATION;
- }
-
- int xid = (int) rri.getXid();
- Role role = rri.getRole();
- // XXX S should check generation id meaningfully and other cases of expectations
- // U64 genId = rri.getGenId();
-
- if (pendingXid != xid) {
- log.debug("Received older role reply from " +
- "switch {} ({}). Ignoring. " +
- "Waiting for {}, xid={}",
- new Object[] {getSwitchInfoString(), rri,
- pendingRole, pendingXid });
- return RoleRecvStatus.OLD_REPLY;
- }
-
- if (pendingRole == role) {
- log.debug("Received role reply message from {} that matched "
- + "expected role-reply {} with expectations {}",
- new Object[] {getSwitchInfoString(), role, expectation});
- counters.roleReplyReceived.updateCounterWithFlush();
- //setSwitchRole(role, RoleRecvStatus.RECEIVED_REPLY); dont want to set state here
- if (expectation == RoleRecvStatus.MATCHED_CURRENT_ROLE ||
- expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
- return expectation;
- } else {
- return RoleRecvStatus.OTHER_EXPECTATION;
- }
- }
-
- // if xids match but role's don't, perhaps its a query (OF1.3)
- if (expectation == RoleRecvStatus.REPLY_QUERY) {
- return expectation;
- }
-
- return RoleRecvStatus.OTHER_EXPECTATION;
- }
-
- /**
- * Called if we receive an error message. If the xid matches the
- * pending request we handle it otherwise we ignore it.
- *
- * Note: since we only keep the last pending request we might get
- * error messages for earlier role requests that we won't be able
- * to handle
- */
- synchronized RoleRecvStatus deliverError(OFErrorMsg error)
- throws SwitchStateException {
- if (!requestPending) {
- log.debug("Received an error msg from sw {}, but no pending "
- + "requests in role-changer; not handling ...",
- getSwitchInfoString());
- return RoleRecvStatus.OTHER_EXPECTATION;
- }
- if (pendingXid != error.getXid()) {
- if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
- log.debug("Received an error msg from sw {} for a role request,"
- + " but not for pending request in role-changer; "
- + " ignoring error {} ...",
- getSwitchInfoString(), error);
- }
- return RoleRecvStatus.OTHER_EXPECTATION;
- }
- // it is an error related to a currently pending role request message
- if (error.getErrType() == OFErrorType.BAD_REQUEST) {
- counters.roleReplyErrorUnsupported.updateCounterWithFlush();
- log.error("Received a error msg {} from sw {} in state {} for "
- + "pending role request {}. Switch driver indicates "
- + "role-messaging is supported. Possible issues in "
- + "switch driver configuration?", new Object[] {
- ((OFBadRequestErrorMsg) error).toString(),
- getSwitchInfoString(), state, pendingRole
- });
- return RoleRecvStatus.UNSUPPORTED;
- }
-
- if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
- OFRoleRequestFailedErrorMsg rrerr =
- (OFRoleRequestFailedErrorMsg) error;
- switch (rrerr.getCode()) {
- case BAD_ROLE:
- // switch says that current-role-req has bad role?
- // for now we disconnect
- // fall-thru
- case STALE:
- // switch says that current-role-req has stale gen-id?
- // for now we disconnect
- // fall-thru
- case UNSUP:
- // switch says that current-role-req has role that
- // cannot be supported? for now we disconnect
- String msgx = String.format("Switch: [%s], State: [%s], "
- + "received Error to for pending role request [%s]. "
- + "Error:[%s]. Disconnecting switch ... ",
- OFChannelHandler.this.getSwitchInfoString(),
- OFChannelHandler.this.state.toString(),
- pendingRole, rrerr);
- throw new SwitchStateException(msgx);
- default:
- break;
- }
- }
-
- // This error message was for a role request message but we dont know
- // how to handle errors for nicira role request messages
- return RoleRecvStatus.OTHER_EXPECTATION;
- }
-
- /**
- * Check if a pending role request has timed out.
- */
- void checkTimeout() {
- if (!requestPending) {
- return;
- }
- synchronized (this) {
- if (!requestPending) {
- return;
- }
- long now = System.currentTimeMillis();
- if (now - roleSubmitTime > roleTimeoutMs) {
- // timeout triggered.
- counters.roleReplyTimeout.updateCounterWithFlush();
- //setSwitchRole(pendingRole, RoleRecvStatus.NO_REPLY);
- // XXX S come back to this
- }
- }
- }
-
- }
//*************************
// Channel State Machine
@@ -628,8 +231,7 @@
log.info("Received features reply for switch at {} with dpid {}",
h.getSwitchInfoString(), h.thisdpid);
//update the controller about this connected switch
- boolean success = h.controller.addConnectedSwitch(
- h.thisdpid, h);
+ boolean success = h.sw.addConnectedSwitch();
if (!success) {
disconnectDuplicate(h);
return;
@@ -825,41 +427,16 @@
h.sw.setConnected(true);
h.sw.setChannel(h.channel);
- try {
- h.sw.setDebugCounterService(h.controller.getDebugCounter());
- } catch (CounterException e) {
- h.counters.switchCounterRegistrationFailed
- .updateCounterNoFlush();
- log.warn("Could not register counters for switch {} ",
- h.getSwitchInfoString(), e);
- }
log.info("Switch {} bound to class {}, description {}",
new Object[] {h.sw, h.sw.getClass(), drep });
//Put switch in EQUAL mode until we hear back from the global registry
log.debug("Setting new switch {} to EQUAL and sending Role request",
h.sw.getStringId());
- h.setSwitchRole(Role.EQUAL);
- try {
- boolean supportsRRMsg = h.roleChanger.sendRoleRequest(Role.EQUAL,
- RoleRecvStatus.MATCHED_CURRENT_ROLE);
- if (!supportsRRMsg) {
- log.warn("Switch {} does not support role request messages "
- + "of any kind. No role messages were sent. "
- + "This controller instance SHOULD become MASTER "
- + "from the registry process. ",
- h.getSwitchInfoString());
- }
- h.setState(WAIT_INITIAL_ROLE);
- // request control of switch from global registry -
- // necessary even if this is the only controller the
- // switch is connected to.
- h.controller.submitRegistryRequest(h.sw.getId());
- } catch (IOException e) {
- log.error("Exception when sending role request: {} ",
- e.getMessage());
- // FIXME shouldn't we disconnect?
- }
+ h.setSwitchRole(RoleState.EQUAL);
+ h.sw.startDriverHandshake();
+ h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
+
}
@Override
@@ -880,133 +457,6 @@
}
},
- /**
- * We are waiting for a role reply message in response to a role request
- * sent after hearing back from the registry service -- OR -- we are
- * just waiting to hear back from the registry service in the case that
- * the switch does not support role messages. If completed successfully,
- * the controller's role for this switch will be set here.
- * Before we move to the state corresponding to the role, we allow the
- * switch specific driver to complete its configuration. This configuration
- * typically depends on the role the controller is playing for this switch.
- * And so we set the switch role (for 'this' controller) before we start
- * the driver-sub-handshake.
- * Next State: WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
- */
- WAIT_INITIAL_ROLE(false) {
- @Override
- void processOFError(OFChannelHandler h, OFErrorMsg m)
- throws SwitchStateException {
- // role changer will ignore the error if it isn't for it
- RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
- if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
- logError(h, m);
- }
- }
-
- @Override
- void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
- throws IOException, SwitchStateException {
- Role role = extractNiciraRoleReply(h, m);
- // If role == null it means the vendor (experimenter) message
- // wasn't really a Nicira role reply. We ignore this case.
- if (role != null) {
- RoleReplyInfo rri = new RoleReplyInfo(role, null, m.getXid());
- RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
- if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
- setRoleAndStartDriverHandshake(h, rri.getRole());
- } // else do nothing - wait for the correct expected reply
- } else {
- unhandledMessageReceived(h, m);
- }
- }
-
- @Override
- void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
- throws SwitchStateException, IOException {
- RoleReplyInfo rri = extractOFRoleReply(h, m);
- RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
- if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
- setRoleAndStartDriverHandshake(h, rri.getRole());
- } // else do nothing - wait for the correct expected reply
- }
-
- @Override
- void handleUnsentRoleMessage(OFChannelHandler h, Role role,
- RoleRecvStatus expectation) throws IOException {
- // typically this is triggered for a switch where role messages
- // are not supported - we confirm that the role being set is
- // master and move to the next state
- if (expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
- if (role == Role.MASTER) {
- setRoleAndStartDriverHandshake(h, role);
- } else {
- log.error("Expected MASTER role from registry for switch "
- + "which has no support for role-messages."
- + "Received {}. It is possible that this switch "
- + "is connected to other controllers, in which "
- + "case it should support role messages - not "
- + "moving forward.", role);
- }
- } // else do nothing - wait to hear back from registry
-
- }
-
- private void setRoleAndStartDriverHandshake(OFChannelHandler h,
- Role role) throws IOException {
- h.setSwitchRole(role);
- h.sw.startDriverHandshake();
- if (h.sw.isDriverHandshakeComplete()) {
- Role mySwitchRole = h.sw.getRole();
- if (mySwitchRole == Role.MASTER) {
- log.info("Switch-driver sub-handshake complete. "
- + "Activating switch {} with Role: MASTER",
- h.getSwitchInfoString());
- handlePendingPortStatusMessages(h); //before activation
- boolean success = h.controller.addActivatedMasterSwitch(
- h.sw.getId(), h.sw);
- if (!success) {
- disconnectDuplicate(h);
- return;
- }
- h.setState(MASTER);
- } else {
- log.info("Switch-driver sub-handshake complete. "
- + "Activating switch {} with Role: EQUAL",
- h.getSwitchInfoString());
- handlePendingPortStatusMessages(h); //before activation
- boolean success = h.controller.addActivatedEqualSwitch(
- h.sw.getId(), h.sw);
- if (!success) {
- disconnectDuplicate(h);
- return;
- }
- h.setState(EQUAL);
- }
- } else {
- h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
- }
- }
-
- @Override
- void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
- throws IOException, SwitchStateException {
- illegalMessageReceived(h, m);
- }
-
- @Override
- void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
- throws SwitchStateException {
- illegalMessageReceived(h, m);
- }
-
- @Override
- void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
- throws IOException, SwitchStateException {
- h.pendingPortStatusMsg.add(m);
-
- }
- },
/**
* We are waiting for the respective switch driver to complete its
@@ -1026,39 +476,27 @@
@Override
void processOFMessage(OFChannelHandler h, OFMessage m)
- throws IOException {
+ throws IOException, SwitchStateException {
if (m.getType() == OFType.ECHO_REQUEST) {
processOFEchoRequest(h, (OFEchoRequest) m);
+ } else if (m.getType() == OFType.ROLE_REPLY) {
+ h.sw.handleRole(m);
+ } else if (m.getType() == OFType.ERROR) {
+ if (!h.sw.handleRoleError((OFErrorMsg)m)) {
+ h.sw.processDriverHandshakeMessage(m);
+ if (h.sw.isDriverHandshakeComplete()) {
+ h.setState(ACTIVE);
+ }
+ }
} else {
- // FIXME: other message to handle here?
- h.sw.processDriverHandshakeMessage(m);
- if (h.sw.isDriverHandshakeComplete()) {
- // consult the h.sw role and goto that state
- Role mySwitchRole = h.sw.getRole();
- if (mySwitchRole == Role.MASTER) {
- log.info("Switch-driver sub-handshake complete. "
- + "Activating switch {} with Role: MASTER",
- h.getSwitchInfoString());
- handlePendingPortStatusMessages(h); //before activation
- boolean success = h.controller.addActivatedMasterSwitch(
- h.sw.getId(), h.sw);
- if (!success) {
- disconnectDuplicate(h);
- return;
- }
- h.setState(MASTER);
- } else {
- log.info("Switch-driver sub-handshake complete. "
- + "Activating switch {} with Role: EQUAL",
- h.getSwitchInfoString());
- handlePendingPortStatusMessages(h); //before activation
- boolean success = h.controller.addActivatedEqualSwitch(
- h.sw.getId(), h.sw);
- if (!success) {
- disconnectDuplicate(h);
- return;
- }
- h.setState(EQUAL);
+ if (m.getType() == OFType.EXPERIMENTER &&
+ ((OFExperimenter) m).getExperimenter() ==
+ RoleManager.NICIRA_EXPERIMENTER) {
+ h.sw.handleNiciraRole(m);
+ } else {
+ h.sw.processDriverHandshakeMessage(m);
+ if (h.sw.isDriverHandshakeComplete()) {
+ h.setState(ACTIVE);
}
}
}
@@ -1084,7 +522,7 @@
* if we send a role request for SLAVE /and/ receive the role reply for
* SLAVE.
*/
- MASTER(true) {
+ ACTIVE(true) {
@LogMessageDoc(level = "WARN",
message = "Received permission error from switch {} while"
+ "being master. Reasserting master role.",
@@ -1097,13 +535,6 @@
@Override
void processOFError(OFChannelHandler h, OFErrorMsg m)
throws IOException, SwitchStateException {
- // first check if the error msg is in response to a role-request message
- RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
- if (rrstatus != RoleRecvStatus.OTHER_EXPECTATION) {
- // rolechanger has handled the error message - we are done
- return;
- }
-
// if we get here, then the error message is for something else
if (m.getErrType() == OFErrorType.BAD_REQUEST &&
((OFBadRequestErrorMsg) m).getCode() ==
@@ -1116,13 +547,10 @@
// if two controllers are master (even if its only for
// a brief period). We might need to see if these errors
// persist before we reassert
- h.counters.epermErrorWhileSwitchIsMaster.updateCounterWithFlush();
log.warn("Received permission error from switch {} while" +
"being master. Reasserting master role.",
h.getSwitchInfoString());
- //h.controller.reassertRole(h, Role.MASTER);
- // XXX S reassert in role changer or reconsider if all this
- // stuff is really needed
+ h.sw.reassertRole();
} else if (m.getErrType() == OFErrorType.FLOW_MOD_FAILED &&
((OFFlowModFailedErrorMsg) m).getCode() ==
OFFlowModFailedCode.ALL_TABLES_FULL) {
@@ -1136,35 +564,19 @@
@Override
void processOFStatisticsReply(OFChannelHandler h,
OFStatsReply m) {
- h.sw.deliverStatisticsReply(m);
+ h.sw.handleMessage(m);
}
@Override
void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
throws IOException, SwitchStateException {
- Role role = extractNiciraRoleReply(h, m);
- if (role == null) {
- // The message wasn't really a Nicira role reply. We just
- // dispatch it to the OFMessage listeners in this case.
- h.dispatchMessage(m);
- return;
- }
-
- RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
- new RoleReplyInfo(role, null, m.getXid()));
- if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
- checkAndSetRoleTransition(h, role);
- }
+ h.sw.handleNiciraRole(m);
}
@Override
void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
throws SwitchStateException, IOException {
- RoleReplyInfo rri = extractOFRoleReply(h, m);
- RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
- if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
- checkAndSetRoleTransition(h, rri.getRole());
- }
+ h.sw.handleRole(m);
}
@Override
@@ -1192,95 +604,6 @@
h.dispatchMessage(m);
}
- },
-
- /**
- * This controller is in EQUAL role for this switch. We enter this state
- * after some /other/ controller instance wins mastership-role over this
- * switch. The EQUAL role can be considered the same as the SLAVE role
- * if this controller does NOT send commands or packets to the switch.
- * This should always be true for OF1.0 switches. XXX S need to enforce.
- *
- * For OF1.3 switches, choosing this state as EQUAL instead of SLAVE,
- * gives us the flexibility that if an app wants to send commands/packets
- * to switches, it can, even thought it is running on a controller instance
- * that is not in a MASTER role for this switch. Of course, it is the job
- * of the app to ensure that commands/packets sent by this (EQUAL) controller
- * instance does not clash/conflict with commands/packets sent by the MASTER
- * controller for this switch. Neither the controller instances, nor the
- * switch provides any kind of resolution mechanism should conflicts occur.
- */
- EQUAL(true) {
- @Override
- void processOFError(OFChannelHandler h, OFErrorMsg m)
- throws IOException, SwitchStateException {
- // role changer will ignore the error if it isn't for it
- RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
- if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
- logError(h, m);
- h.dispatchMessage(m);
- }
- }
-
- @Override
- void processOFStatisticsReply(OFChannelHandler h,
- OFStatsReply m) {
- h.sw.deliverStatisticsReply(m);
- }
-
- @Override
- void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
- throws IOException, SwitchStateException {
- Role role = extractNiciraRoleReply(h, m);
- // If role == null it means the message wasn't really a
- // Nicira role reply. We ignore it in this state.
- if (role != null) {
- RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
- new RoleReplyInfo(role, null, m.getXid()));
- if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
- checkAndSetRoleTransition(h, role);
- }
- } else {
- unhandledMessageReceived(h, m);
- }
- }
-
- @Override
- void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
- throws SwitchStateException, IOException {
- RoleReplyInfo rri = extractOFRoleReply(h, m);
- RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
- if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
- checkAndSetRoleTransition(h, rri.getRole());
- }
- }
-
- // XXX S needs more handlers for 1.3 switches in equal role
-
- @Override
- void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
- throws IOException, SwitchStateException {
- handlePortStatusMessage(h, m, true);
- }
-
- @Override
- @LogMessageDoc(level = "WARN",
- message = "Received PacketIn from switch {} while "
- + "being slave. Reasserting slave role.",
- explanation = "The switch has receive a PacketIn despite being "
- + "in slave role indicating inconsistent controller roles",
- recommendation = "This situation can occurs transiently during role"
- + " changes. If, however, the condition persists or happens"
- + " frequently this indicates a role inconsistency. "
- + LogMessageDoc.CHECK_CONTROLLER)
- void processOFPacketIn(OFChannelHandler h, OFPacketIn m) throws IOException {
- // we don't expect packetIn while slave, reassert we are slave
- h.counters.packetInWhileSwitchIsSlave.updateCounterNoFlush();
- log.warn("Received PacketIn from switch {} while" +
- "being slave. Reasserting slave role.", h.sw);
- //h.controller.reassertRole(h, Role.SLAVE);
- // XXX reassert in role changer
- }
};
private final boolean handshakeComplete;
@@ -1345,7 +668,6 @@
*/
protected void unhandledMessageReceived(OFChannelHandler h,
OFMessage m) {
- h.counters.unhandledMessage.updateCounterNoFlush();
if (log.isDebugEnabled()) {
String msg = getSwitchStateMessage(h, m,
"Ignoring unexpected message");
@@ -1398,108 +720,7 @@
h.channel.disconnect();
}
- /**
- * Extract the role from an OFVendor message.
- *
- * Extract the role from an OFVendor message if the message is a
- * Nicira role reply. Otherwise return null.
- *
- * @param h The channel handler receiving the message
- * @param vendorMessage The vendor message to parse.
- * @return The role in the message if the message is a Nicira role
- * reply, null otherwise.
- * @throws SwitchStateException If the message is a Nicira role reply
- * but the numeric role value is unknown.
- */
- protected Role extractNiciraRoleReply(OFChannelHandler h,
- OFExperimenter experimenterMsg) throws SwitchStateException {
- int vendor = (int) experimenterMsg.getExperimenter();
- if (vendor != 0x2320) {
- return null;
- }
- OFNiciraControllerRoleReply nrr =
- (OFNiciraControllerRoleReply) experimenterMsg;
- Role role = null;
- OFNiciraControllerRole ncr = nrr.getRole();
- switch(ncr) {
- case ROLE_MASTER:
- role = Role.MASTER;
- break;
- case ROLE_OTHER:
- role = Role.EQUAL;
- break;
- case ROLE_SLAVE:
- role = Role.SLAVE;
- break;
- default: //handled below
- }
-
- if (role == null) {
- String msg = String.format("Switch: [%s], State: [%s], "
- + "received NX_ROLE_REPLY with invalid role "
- + "value %s",
- h.getSwitchInfoString(),
- this.toString(),
- nrr.getRole());
- throw new SwitchStateException(msg);
- }
- return role;
- }
-
- /**
- * Helper class returns role reply information in the format understood
- * by the controller.
- */
- protected static class RoleReplyInfo {
- private Role role;
- private U64 genId;
- private long xid;
-
- RoleReplyInfo(Role role, U64 genId, long xid) {
- this.role = role;
- this.genId = genId;
- this.xid = xid;
- }
- public Role getRole() { return role; }
- public U64 getGenId() { return genId; }
- public long getXid() { return xid; }
- @Override
- public String toString() {
- return "[Role:" + role + " GenId:" + genId + " Xid:" + xid + "]";
- }
- }
-
- /**
- * Extract the role information from an OF1.3 Role Reply Message.
- * @param h
- * @param rrmsg
- * @return RoleReplyInfo object
- * @throws SwitchStateException
- */
- protected RoleReplyInfo extractOFRoleReply(OFChannelHandler h,
- OFRoleReply rrmsg) throws SwitchStateException {
- OFControllerRole cr = rrmsg.getRole();
- Role role = null;
- switch(cr) {
- case ROLE_EQUAL:
- role = Role.EQUAL;
- break;
- case ROLE_MASTER:
- role = Role.MASTER;
- break;
- case ROLE_SLAVE:
- role = Role.SLAVE;
- break;
- case ROLE_NOCHANGE: // switch should send current role
- default:
- String msg = String.format("Unknown controller role %s "
- + "received from switch %s", cr, h.sw);
- throw new SwitchStateException(msg);
- }
-
- return new RoleReplyInfo(role, rrmsg.getGenerationId(), rrmsg.getXid());
- }
/**
* Handles all pending port status messages before a switch is declared
@@ -1567,52 +788,9 @@
throw new SwitchStateException(msg);
}
- Collection<PortChangeEvent> changes = h.sw.processOFPortStatus(m);
- if (doNotify) {
- for (PortChangeEvent ev: changes) {
- h.controller.notifyPortChanged(h.sw.getId(), ev.port, ev.type);
- }
- }
+ h.sw.handleMessage(m);
}
- /**
- * Checks if the role received (from the role-reply msg) is different
- * from the existing role in the IOFSwitch object for this controller.
- * If so, it transitions the controller to the new role. Note that
- * the caller should have already verified that the role-reply msg
- * received was in response to a role-request msg sent out by this
- * controller after hearing from the registry service.
- *
- * @param h the ChannelHandler that received the message
- * @param role the role in the recieved role reply message
- */
- protected void checkAndSetRoleTransition(OFChannelHandler h, Role role) {
- // we received a role-reply in response to a role message
- // sent after hearing from the registry service. It is
- // possible that the role of this controller instance for
- // this switch has changed:
- // for 1.0 switch: from MASTER to SLAVE
- // for 1.3 switch: from MASTER to EQUAL
- if ((h.sw.getRole() == Role.MASTER && role == Role.SLAVE) ||
- (h.sw.getRole() == Role.MASTER && role == Role.EQUAL)) {
- // the mastership has changed
- h.sw.setRole(role);
- h.setState(EQUAL);
- h.controller.transitionToEqualSwitch(h.sw.getId());
- return;
- }
-
- // or for both 1.0 and 1.3 switches from EQUAL to MASTER.
- // note that for 1.0, even though we mean SLAVE,
- // internally we call the role EQUAL.
- if (h.sw.getRole() == Role.EQUAL && role == Role.MASTER) {
- // the mastership has changed
- h.sw.setRole(role);
- h.setState(MASTER);
- h.controller.transitionToMasterSwitch(h.sw.getId());
- return;
- }
- }
/**
* Process an OF message received on the channel and
@@ -1635,7 +813,6 @@
*/
void processOFMessage(OFChannelHandler h, OFMessage m)
throws IOException, SwitchStateException {
- h.roleChanger.checkTimeout();
switch(m.getType()) {
case HELLO:
processOFHello(h, (OFHello) m);
@@ -1812,10 +989,6 @@
unhandledMessageReceived(h, m);
}
- void handleUnsentRoleMessage(OFChannelHandler h, Role role,
- RoleRecvStatus expectation) throws IOException {
- // do nothing in most states
- }
}
@@ -1830,7 +1003,6 @@
+ "specified IP address")
public void channelConnected(ChannelHandlerContext ctx,
ChannelStateEvent e) throws Exception {
- counters.switchConnected.updateCounterWithFlush();
channel = e.getChannel();
log.info("New switch connection from {}",
channel.getRemoteAddress());
@@ -1853,7 +1025,7 @@
// switch was a duplicate-dpid, calling the method below would clear
// all state for the original switch (with the same dpid),
// which we obviously don't want.
- controller.removeConnectedSwitch(thisdpid);
+ sw.removeConnectedSwitch();
} else {
// A duplicate was disconnected on this ChannelHandler,
// this is the same switch reconnecting, but the original state was
@@ -1914,12 +1086,10 @@
// switch timeout
log.error("Disconnecting switch {} due to read timeout",
getSwitchInfoString());
- counters.switchDisconnectReadTimeout.updateCounterWithFlush();
ctx.getChannel().close();
} else if (e.getCause() instanceof HandshakeTimeoutException) {
log.error("Disconnecting switch {}: failed to complete handshake",
getSwitchInfoString());
- counters.switchDisconnectHandshakeTimeout.updateCounterWithFlush();
ctx.getChannel().close();
} else if (e.getCause() instanceof ClosedChannelException) {
log.debug("Channel for sw {} already closed", getSwitchInfoString());
@@ -1930,7 +1100,6 @@
// still print stack trace if debug is enabled
log.debug("StackTrace for previous Exception: ", e.getCause());
}
- counters.switchDisconnectIOError.updateCounterWithFlush();
ctx.getChannel().close();
} else if (e.getCause() instanceof SwitchStateException) {
log.error("Disconnecting switch {} due to switch state error: {}",
@@ -1939,23 +1108,19 @@
// still print stack trace if debug is enabled
log.debug("StackTrace for previous Exception: ", e.getCause());
}
- counters.switchDisconnectSwitchStateException.updateCounterWithFlush();
ctx.getChannel().close();
} else if (e.getCause() instanceof OFParseError) {
log.error("Disconnecting switch "
+ getSwitchInfoString() +
" due to message parse failure",
e.getCause());
- counters.switchDisconnectParseError.updateCounterWithFlush();
ctx.getChannel().close();
} else if (e.getCause() instanceof RejectedExecutionException) {
log.warn("Could not process message: queue full");
- counters.rejectedExecutionException.updateCounterWithFlush();
} else {
log.error("Error while processing message from switch "
+ getSwitchInfoString()
+ "state " + this.state, e.getCause());
- counters.switchDisconnectOtherException.updateCounterWithFlush();
ctx.getChannel().close();
}
}
@@ -1986,12 +1151,10 @@
for (OFMessage ofm : msglist) {
- counters.messageReceived.updateCounterNoFlush();
// Do the actual packet processing
state.processOFMessage(this, ofm);
}
} else {
- counters.messageReceived.updateCounterNoFlush();
state.processOFMessage(this, (OFMessage) e.getMessage());
}
}
@@ -2080,7 +1243,7 @@
channel.write(Collections.singletonList(m));
}
- private void setSwitchRole(Role role) {
+ private void setSwitchRole(RoleState role) {
sw.setRole(role);
}
@@ -2146,9 +1309,4 @@
return state;
}
- void useRoleChangerWithOtherTimeoutForTesting(long roleTimeoutMs) {
- roleChanger = new RoleChanger(roleTimeoutMs);
- }
-
-
}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OpenFlowControllerImpl.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OpenFlowControllerImpl.java
new file mode 100644
index 0000000..976e347
--- /dev/null
+++ b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OpenFlowControllerImpl.java
@@ -0,0 +1,263 @@
+package org.onlab.onos.of.controller.impl.internal;
+
+import java.util.ArrayList;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.onos.of.controller.Dpid;
+import org.onlab.onos.of.controller.OpenFlowController;
+import org.onlab.onos.of.controller.OpenFlowSwitch;
+import org.onlab.onos.of.controller.OpenFlowSwitchListener;
+import org.onlab.onos.of.controller.PacketListener;
+import org.onlab.onos.of.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.util.HexString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(immediate = true)
+@Service
+public class OpenFlowControllerImpl implements OpenFlowController {
+
+ protected ConcurrentHashMap<Long, OpenFlowSwitch> connectedSwitches;
+ protected ConcurrentHashMap<Long, OpenFlowSwitch> activeMasterSwitches;
+ protected ConcurrentHashMap<Long, OpenFlowSwitch> activeEqualSwitches;
+
+ protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
+ protected ArrayList<OpenFlowSwitchListener> ofEventListener;
+
+ private final Controller ctrl = new Controller();
+
+ @Activate
+ public void activate() {
+ ctrl.start(agent);
+ }
+
+ @Deactivate
+ public void deactivate() {
+ ctrl.stop();
+ }
+
+ @Override
+ public Iterable<OpenFlowSwitch> getSwitches() {
+ return connectedSwitches.values();
+ }
+
+ @Override
+ public Iterable<OpenFlowSwitch> getMasterSwitches() {
+ return activeMasterSwitches.values();
+ }
+
+ @Override
+ public Iterable<OpenFlowSwitch> getEqualSwitches() {
+ return activeEqualSwitches.values();
+ }
+
+ @Override
+ public OpenFlowSwitch getSwitch(Dpid dpid) {
+ return connectedSwitches.get(dpid.value());
+ }
+
+ @Override
+ public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
+ return activeMasterSwitches.get(dpid.value());
+ }
+
+ @Override
+ public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
+ return activeEqualSwitches.get(dpid.value()); }
+
+ @Override
+ public void addListener(OpenFlowSwitchListener listener) {
+ if (!ofEventListener.contains(listener)) {
+ this.ofEventListener.add(listener);
+ }
+ }
+
+ @Override
+ public void removeListener(OpenFlowSwitchListener listener) {
+ this.ofEventListener.remove(listener);
+ }
+
+ @Override
+ public void addPacketListener(int priority, PacketListener listener) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void removePacketListener(PacketListener listener) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void write(Dpid dpid, OFMessage msg) {
+ this.getSwitch(dpid).write(msg);
+ }
+
+ @Override
+ public void processPacket(OFMessage msg) {
+ }
+
+ @Override
+ public void setRole(Dpid dpid, RoleState role) {
+ switch (role) {
+ case MASTER:
+ agent.transitionToMasterSwitch(dpid.value());
+ break;
+ case EQUAL:
+ agent.transitionToEqualSwitch(dpid.value());
+ break;
+ case SLAVE:
+ //agent.transitionToSlaveSwitch(dpid.value());
+ break;
+ default:
+ //WTF role is this?
+ }
+
+ }
+
+ public class OpenFlowSwitchAgent {
+
+ private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
+ private Lock switchLock = new ReentrantLock();
+
+ public boolean addConnectedSwitch(long dpid, AbstractOpenFlowSwitch sw) {
+ if (connectedSwitches.get(dpid) != null) {
+ log.error("Trying to add connectedSwitch but found a previous "
+ + "value for dpid: {}", dpid);
+ return false;
+ } else {
+ log.error("Added switch {}", dpid);
+ connectedSwitches.put(dpid, sw);
+ for (OpenFlowSwitchListener l : ofEventListener) {
+ l.switchAdded(new Dpid(dpid));
+ }
+ return true;
+ }
+ }
+
+ private boolean validActivation(long dpid) {
+ if (connectedSwitches.get(dpid) == null) {
+ log.error("Trying to activate switch but is not in "
+ + "connected switches: dpid {}. Aborting ..",
+ HexString.toHexString(dpid));
+ return false;
+ }
+ if (activeMasterSwitches.get(dpid) != null ||
+ activeEqualSwitches.get(dpid) != null) {
+ log.error("Trying to activate switch but it is already "
+ + "activated: dpid {}. Found in activeMaster: {} "
+ + "Found in activeEqual: {}. Aborting ..", new Object[] {
+ HexString.toHexString(dpid),
+ (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
+ (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Called when a switch is activated, with this controller's role as MASTER.
+ */
+ protected boolean addActivatedMasterSwitch(long dpid, AbstractOpenFlowSwitch sw) {
+ switchLock.lock();
+ try {
+ if (!validActivation(dpid)) {
+ return false;
+ }
+ activeMasterSwitches.put(dpid, sw);
+ return true;
+ } finally {
+ switchLock.unlock();
+ }
+ }
+
+ /**
+ * Called when a switch is activated, with this controller's role as EQUAL.
+ */
+ protected boolean addActivatedEqualSwitch(long dpid, AbstractOpenFlowSwitch sw) {
+ switchLock.lock();
+ try {
+ if (!validActivation(dpid)) {
+ return false;
+ }
+ activeEqualSwitches.put(dpid, sw);
+ return true;
+ } finally {
+ switchLock.unlock();
+ }
+ }
+
+ /**
+ * Called when this controller's role for a switch transitions from equal
+ * to master. For 1.0 switches, we internally refer to the role 'slave' as
+ * 'equal' - so this transition is equivalent to 'addActivatedMasterSwitch'.
+ */
+ protected void transitionToMasterSwitch(long dpid) {
+ switchLock.lock();
+ try {
+ OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
+ if (sw == null) {
+ log.error("Transition to master called on sw {}, but switch "
+ + "was not found in controller-cache", dpid);
+ return;
+ }
+ activeMasterSwitches.put(dpid, sw);
+ } finally {
+ switchLock.unlock();
+ }
+ }
+
+
+ /**
+ * Called when this controller's role for a switch transitions to equal.
+ * For 1.0 switches, we internally refer to the role 'slave' as
+ * 'equal'.
+ */
+ protected void transitionToEqualSwitch(long dpid) {
+ switchLock.lock();
+ try {
+ OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
+ if (sw == null) {
+ log.error("Transition to equal called on sw {}, but switch "
+ + "was not found in controller-cache", dpid);
+ return;
+ }
+ activeEqualSwitches.put(dpid, sw);
+ } finally {
+ switchLock.unlock();
+ }
+
+ }
+
+ /**
+ * Clear all state in controller switch maps for a switch that has
+ * disconnected from the local controller. Also release control for
+ * that switch from the global repository. Notify switch listeners.
+ */
+ public void removeConnectedSwitch(long dpid) {
+ connectedSwitches.remove(dpid);
+ OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
+ if (sw == null) {
+ sw = activeEqualSwitches.remove(dpid);
+ }
+ for (OpenFlowSwitchListener l : ofEventListener) {
+ l.switchRemoved(new Dpid(dpid));
+ }
+ }
+
+ public void processMessage(OFMessage m) {
+ processPacket(m);
+ }
+ }
+
+
+
+}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/RoleManager.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/RoleManager.java
new file mode 100644
index 0000000..f31487a
--- /dev/null
+++ b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/RoleManager.java
@@ -0,0 +1,708 @@
+package org.onlab.onos.of.controller.impl.internal;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onlab.onos.of.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFErrorType;
+import org.projectfloodlight.openflow.protocol.OFExperimenter;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
+import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
+import org.projectfloodlight.openflow.protocol.OFRoleReply;
+import org.projectfloodlight.openflow.protocol.OFRoleRequest;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
+import org.projectfloodlight.openflow.protocol.errormsg.OFRoleRequestFailedErrorMsg;
+import org.projectfloodlight.openflow.types.U64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A utility class to handle role requests and replies for this channel.
+ * After a role request is submitted the role changer keeps track of the
+ * pending request, collects the reply (if any) and times out the request
+ * if necessary.
+ *
+ * To simplify role handling we only keep track of the /last/ pending
+ * role reply send to the switch. If multiple requests are pending and
+ * we receive replies for earlier requests we ignore them. However, this
+ * way of handling pending requests implies that we could wait forever if
+ * a new request is submitted before the timeout triggers. If necessary
+ * we could work around that though.
+ */
+class RoleManager {
+ protected static final long NICIRA_EXPERIMENTER = 0x2320;
+
+ private static Logger log = LoggerFactory.getLogger(RoleManager.class);
+ // indicates that a request is currently pending
+ // needs to be volatile to allow correct double-check idiom
+ private volatile boolean requestPending;
+ // the transaction Id of the pending request
+ private int pendingXid;
+ // the role that's pending
+ private RoleState pendingRole;
+
+ // the expectation set by the caller for the returned role
+ private RoleRecvStatus expectation;
+ private AtomicInteger xidCounter;
+ private AbstractOpenFlowSwitch sw;
+
+
+ public RoleManager(AbstractOpenFlowSwitch sw) {
+ this.requestPending = false;
+ this.pendingXid = -1;
+ this.pendingRole = null;
+ this.xidCounter = new AtomicInteger(0);
+ this.expectation = RoleRecvStatus.MATCHED_CURRENT_ROLE;
+ this.sw = sw;
+ }
+
+ /**
+ * Send NX role request message to the switch requesting the specified
+ * role.
+ *
+ * @param sw switch to send the role request message to
+ * @param role role to request
+ */
+ private int sendNxRoleRequest(RoleState role) throws IOException {
+ // Convert the role enum to the appropriate role to send
+ OFNiciraControllerRole roleToSend = OFNiciraControllerRole.ROLE_OTHER;
+ switch (role) {
+ case MASTER:
+ roleToSend = OFNiciraControllerRole.ROLE_MASTER;
+ break;
+ case SLAVE:
+ case EQUAL:
+ default:
+ // ensuring that the only two roles sent to 1.0 switches with
+ // Nicira role support, are MASTER and SLAVE
+ roleToSend = OFNiciraControllerRole.ROLE_SLAVE;
+ log.warn("Sending Nx Role.SLAVE to switch {}.", sw);
+ }
+ int xid = xidCounter.getAndIncrement();
+ OFExperimenter roleRequest = OFFactories.getFactory(OFVersion.OF_10)
+ .buildNiciraControllerRoleRequest()
+ .setXid(xid)
+ .setRole(roleToSend)
+ .build();
+ sw.write(Collections.<OFMessage>singletonList(roleRequest));
+ return xid;
+ }
+
+ private int sendOF13RoleRequest(RoleState role) throws IOException {
+ // Convert the role enum to the appropriate role to send
+ OFControllerRole roleToSend = OFControllerRole.ROLE_NOCHANGE;
+ switch (role) {
+ case EQUAL:
+ roleToSend = OFControllerRole.ROLE_EQUAL;
+ break;
+ case MASTER:
+ roleToSend = OFControllerRole.ROLE_MASTER;
+ break;
+ case SLAVE:
+ roleToSend = OFControllerRole.ROLE_SLAVE;
+ break;
+ default:
+ log.warn("Sending default role.noChange to switch {}."
+ + " Should only be used for queries.", sw);
+ }
+
+ int xid = xidCounter.getAndIncrement();
+ OFRoleRequest rrm = OFFactories.getFactory(OFVersion.OF_13)
+ .buildRoleRequest()
+ .setRole(roleToSend)
+ .setXid(xid)
+ //FIXME fix below when we actually use generation ids
+ .setGenerationId(U64.ZERO)
+ .build();
+ sw.write(rrm);
+ return xid;
+ }
+
+ /**
+ * Send a role request with the given role to the switch and update
+ * the pending request and timestamp.
+ * Sends an OFPT_ROLE_REQUEST to an OF1.3 switch, OR
+ * Sends an NX_ROLE_REQUEST to an OF1.0 switch if configured to support it
+ * in the IOFSwitch driver. If not supported, this method sends nothing
+ * and returns 'false'. The caller should take appropriate action.
+ *
+ * One other optimization we do here is that for OF1.0 switches with
+ * Nicira role message support, we force the Role.EQUAL to become
+ * Role.SLAVE, as there is no defined behavior for the Nicira role OTHER.
+ * We cannot expect it to behave like SLAVE. We don't have this problem with
+ * OF1.3 switches, because Role.EQUAL is well defined and we can simulate
+ * SLAVE behavior by using ASYNC messages.
+ *
+ * @param role
+ * @throws IOException
+ * @returns false if and only if the switch does not support role-request
+ * messages, according to the switch driver; true otherwise.
+ */
+ synchronized boolean sendRoleRequest(RoleState role, RoleRecvStatus exp)
+ throws IOException {
+ this.expectation = exp;
+
+ if (sw.factory().getVersion() == OFVersion.OF_10) {
+ Boolean supportsNxRole = (Boolean)
+ sw.supportNxRole();
+ if (!supportsNxRole) {
+ log.debug("Switch driver indicates no support for Nicira "
+ + "role request messages. Not sending ...");
+ handleUnsentRoleMessage(role,
+ expectation);
+ return false;
+ }
+ // OF1.0 switch with support for NX_ROLE_REQUEST vendor extn.
+ // make Role.EQUAL become Role.SLAVE
+ role = (role == RoleState.EQUAL) ? RoleState.SLAVE : role;
+ pendingXid = sendNxRoleRequest(role);
+ pendingRole = role;
+ requestPending = true;
+ } else {
+ // OF1.3 switch, use OFPT_ROLE_REQUEST message
+ pendingXid = sendOF13RoleRequest(role);
+ pendingRole = role;
+ requestPending = true;
+ }
+ return true;
+ }
+
+ private void handleUnsentRoleMessage(RoleState role,
+ RoleRecvStatus exp) throws IOException {
+ // typically this is triggered for a switch where role messages
+ // are not supported - we confirm that the role being set is
+ // master
+ if (exp != RoleRecvStatus.MATCHED_SET_ROLE) {
+
+ log.error("Expected MASTER role from registry for switch "
+ + "which has no support for role-messages."
+ + "Received {}. It is possible that this switch "
+ + "is connected to other controllers, in which "
+ + "case it should support role messages - not "
+ + "moving forward.", role);
+
+ }
+
+ }
+
+ /**
+ * Deliver a received role reply.
+ *
+ * Check if a request is pending and if the received reply matches the
+ * the expected pending reply (we check both role and xid) we set
+ * the role for the switch/channel.
+ *
+ * If a request is pending but doesn't match the reply we ignore it, and
+ * return
+ *
+ * If no request is pending we disconnect with a SwitchStateException
+ *
+ * @param RoleReplyInfo information about role-reply in format that
+ * controller can understand.
+ * @throws SwitchStateException if no request is pending
+ */
+ synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
+ throws SwitchStateException {
+ if (!requestPending) {
+ RoleState currentRole = (sw != null) ? sw.getRole() : null;
+ if (currentRole != null) {
+ if (currentRole == rri.getRole()) {
+ // Don't disconnect if the role reply we received is
+ // for the same role we are already in.
+ log.debug("Received unexpected RoleReply from "
+ + "Switch: {}. "
+ + "Role in reply is same as current role of this "
+ + "controller for this sw. Ignoring ...",
+ sw.getStringId());
+ return RoleRecvStatus.OTHER_EXPECTATION;
+ } else {
+ String msg = String.format("Switch: [%s], "
+ + "received unexpected RoleReply[%s]. "
+ + "No roles are pending, and this controller's "
+ + "current role:[%s] does not match reply. "
+ + "Disconnecting switch ... ",
+ sw.getStringId(),
+ rri, currentRole);
+ throw new SwitchStateException(msg);
+ }
+ }
+ log.debug("Received unexpected RoleReply {} from "
+ + "Switch: {}. "
+ + "This controller has no current role for this sw. "
+ + "Ignoring ...", new Object[] {rri,
+ sw.getStringId(), });
+ return RoleRecvStatus.OTHER_EXPECTATION;
+ }
+
+ int xid = (int) rri.getXid();
+ RoleState role = rri.getRole();
+ // XXX S should check generation id meaningfully and other cases of expectations
+ // U64 genId = rri.getGenId();
+
+ if (pendingXid != xid) {
+ log.debug("Received older role reply from " +
+ "switch {} ({}). Ignoring. " +
+ "Waiting for {}, xid={}",
+ new Object[] {sw.getStringId(), rri,
+ pendingRole, pendingXid });
+ return RoleRecvStatus.OLD_REPLY;
+ }
+
+ if (pendingRole == role) {
+ log.debug("Received role reply message from {} that matched "
+ + "expected role-reply {} with expectations {}",
+ new Object[] {sw.getStringId(), role, expectation});
+
+ //setSwitchRole(role, RoleRecvStatus.RECEIVED_REPLY); dont want to set state here
+ if (expectation == RoleRecvStatus.MATCHED_CURRENT_ROLE ||
+ expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
+ return expectation;
+ } else {
+ return RoleRecvStatus.OTHER_EXPECTATION;
+ }
+ }
+
+ // if xids match but role's don't, perhaps its a query (OF1.3)
+ if (expectation == RoleRecvStatus.REPLY_QUERY) {
+ return expectation;
+ }
+
+ return RoleRecvStatus.OTHER_EXPECTATION;
+ }
+
+ /**
+ * Called if we receive an error message. If the xid matches the
+ * pending request we handle it otherwise we ignore it.
+ *
+ * Note: since we only keep the last pending request we might get
+ * error messages for earlier role requests that we won't be able
+ * to handle
+ */
+ synchronized RoleRecvStatus deliverError(OFErrorMsg error)
+ throws SwitchStateException {
+ if (!requestPending) {
+ log.debug("Received an error msg from sw {}, but no pending "
+ + "requests in role-changer; not handling ...",
+ sw.getStringId());
+ return RoleRecvStatus.OTHER_EXPECTATION;
+ }
+ if (pendingXid != error.getXid()) {
+ if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
+ log.debug("Received an error msg from sw {} for a role request,"
+ + " but not for pending request in role-changer; "
+ + " ignoring error {} ...",
+ sw.getStringId(), error);
+ }
+ return RoleRecvStatus.OTHER_EXPECTATION;
+ }
+ // it is an error related to a currently pending role request message
+ if (error.getErrType() == OFErrorType.BAD_REQUEST) {
+ log.error("Received a error msg {} from sw {} for "
+ + "pending role request {}. Switch driver indicates "
+ + "role-messaging is supported. Possible issues in "
+ + "switch driver configuration?", new Object[] {
+ ((OFBadRequestErrorMsg) error).toString(),
+ sw.getStringId(), pendingRole
+ });
+ return RoleRecvStatus.UNSUPPORTED;
+ }
+
+ if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
+ OFRoleRequestFailedErrorMsg rrerr =
+ (OFRoleRequestFailedErrorMsg) error;
+ switch (rrerr.getCode()) {
+ case BAD_ROLE:
+ // switch says that current-role-req has bad role?
+ // for now we disconnect
+ // fall-thru
+ case STALE:
+ // switch says that current-role-req has stale gen-id?
+ // for now we disconnect
+ // fall-thru
+ case UNSUP:
+ // switch says that current-role-req has role that
+ // cannot be supported? for now we disconnect
+ String msgx = String.format("Switch: [%s], "
+ + "received Error to for pending role request [%s]. "
+ + "Error:[%s]. Disconnecting switch ... ",
+ sw.getStringId(),
+ pendingRole, rrerr);
+ throw new SwitchStateException(msgx);
+ default:
+ break;
+ }
+ }
+
+ // This error message was for a role request message but we dont know
+ // how to handle errors for nicira role request messages
+ return RoleRecvStatus.OTHER_EXPECTATION;
+ }
+
+ /**
+ * Extract the role from an OFVendor message.
+ *
+ * Extract the role from an OFVendor message if the message is a
+ * Nicira role reply. Otherwise return null.
+ *
+ * @param h The channel handler receiving the message
+ * @param vendorMessage The vendor message to parse.
+ * @return The role in the message if the message is a Nicira role
+ * reply, null otherwise.
+ * @throws SwitchStateException If the message is a Nicira role reply
+ * but the numeric role value is unknown.
+ */
+ protected RoleState extractNiciraRoleReply(OFExperimenter experimenterMsg)
+ throws SwitchStateException {
+ int vendor = (int) experimenterMsg.getExperimenter();
+ if (vendor != 0x2320) {
+ return null;
+ }
+ OFNiciraControllerRoleReply nrr =
+ (OFNiciraControllerRoleReply) experimenterMsg;
+
+ RoleState role = null;
+ OFNiciraControllerRole ncr = nrr.getRole();
+ switch(ncr) {
+ case ROLE_MASTER:
+ role = RoleState.MASTER;
+ break;
+ case ROLE_OTHER:
+ role = RoleState.EQUAL;
+ break;
+ case ROLE_SLAVE:
+ role = RoleState.SLAVE;
+ break;
+ default: //handled below
+ }
+
+ if (role == null) {
+ String msg = String.format("Switch: [%s], "
+ + "received NX_ROLE_REPLY with invalid role "
+ + "value %s",
+ sw.getStringId(),
+ nrr.getRole());
+ throw new SwitchStateException(msg);
+ }
+ return role;
+ }
+
+ /**
+ * When we remove a pending role request we use this enum to indicate how we
+ * arrived at the decision. When we send a role request to the switch, we
+ * also use this enum to indicate what we expect back from the switch, so the
+ * role changer can match the reply to our expectation.
+ */
+ public enum RoleRecvStatus {
+ /** The switch returned an error indicating that roles are not.
+ * supported*/
+ UNSUPPORTED,
+ /** The request timed out. */
+ NO_REPLY,
+ /** The reply was old, there is a newer request pending. */
+ OLD_REPLY,
+ /**
+ * The reply's role matched the role that this controller set in the
+ * request message - invoked either initially at startup or to reassert
+ * current role.
+ */
+ MATCHED_CURRENT_ROLE,
+ /**
+ * The reply's role matched the role that this controller set in the
+ * request message - this is the result of a callback from the
+ * global registry, followed by a role request sent to the switch.
+ */
+ MATCHED_SET_ROLE,
+ /**
+ * The reply's role was a response to the query made by this controller.
+ */
+ REPLY_QUERY,
+ /** We received a role reply message from the switch
+ * but the expectation was unclear, or there was no expectation.
+ */
+ OTHER_EXPECTATION,
+ }
+
+ /**
+ * Helper class returns role reply information in the format understood
+ * by the controller.
+ */
+ protected static class RoleReplyInfo {
+ private RoleState role;
+ private U64 genId;
+ private long xid;
+
+ RoleReplyInfo(RoleState role, U64 genId, long xid) {
+ this.role = role;
+ this.genId = genId;
+ this.xid = xid;
+ }
+ public RoleState getRole() { return role; }
+ public U64 getGenId() { return genId; }
+ public long getXid() { return xid; }
+ @Override
+ public String toString() {
+ return "[Role:" + role + " GenId:" + genId + " Xid:" + xid + "]";
+ }
+ }
+
+ /**
+ * Extract the role information from an OF1.3 Role Reply Message.
+ * @param h
+ * @param rrmsg
+ * @return RoleReplyInfo object
+ * @throws SwitchStateException
+ */
+ protected RoleReplyInfo extractOFRoleReply(OFRoleReply rrmsg)
+ throws SwitchStateException {
+ OFControllerRole cr = rrmsg.getRole();
+ RoleState role = null;
+ switch(cr) {
+ case ROLE_EQUAL:
+ role = RoleState.EQUAL;
+ break;
+ case ROLE_MASTER:
+ role = RoleState.MASTER;
+ break;
+ case ROLE_SLAVE:
+ role = RoleState.SLAVE;
+ break;
+ case ROLE_NOCHANGE: // switch should send current role
+ default:
+ String msg = String.format("Unknown controller role %s "
+ + "received from switch %s", cr, sw);
+ throw new SwitchStateException(msg);
+ }
+
+ return new RoleReplyInfo(role, rrmsg.getGenerationId(), rrmsg.getXid());
+ }
+
+}
+
+
+///**
+// * We are waiting for a role reply message in response to a role request
+// * sent after hearing back from the registry service -- OR -- we are
+// * just waiting to hear back from the registry service in the case that
+// * the switch does not support role messages. If completed successfully,
+// * the controller's role for this switch will be set here.
+// * Before we move to the state corresponding to the role, we allow the
+// * switch specific driver to complete its configuration. This configuration
+// * typically depends on the role the controller is playing for this switch.
+// * And so we set the switch role (for 'this' controller) before we start
+// * the driver-sub-handshake.
+// * Next State: WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
+// */
+//WAIT_INITIAL_ROLE(false) {
+// @Override
+// void processOFError(OFChannelHandler h, OFErrorMsg m)
+// throws SwitchStateException {
+// // role changer will ignore the error if it isn't for it
+// RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
+// if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
+// logError(h, m);
+// }
+// }
+//
+// @Override
+// void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
+// throws IOException, SwitchStateException {
+// Role role = extractNiciraRoleReply(h, m);
+// // If role == null it means the vendor (experimenter) message
+// // wasn't really a Nicira role reply. We ignore this case.
+// if (role != null) {
+// RoleReplyInfo rri = new RoleReplyInfo(role, null, m.getXid());
+// RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
+// if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+// setRoleAndStartDriverHandshake(h, rri.getRole());
+// } // else do nothing - wait for the correct expected reply
+// } else {
+// unhandledMessageReceived(h, m);
+// }
+// }
+//
+// @Override
+// void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
+// throws SwitchStateException, IOException {
+// RoleReplyInfo rri = extractOFRoleReply(h, m);
+// RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
+// if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+// setRoleAndStartDriverHandshake(h, rri.getRole());
+// } // else do nothing - wait for the correct expected reply
+// }
+//
+// @Override
+// void handleUnsentRoleMessage(OFChannelHandler h, Role role,
+// RoleRecvStatus expectation) throws IOException {
+// // typically this is triggered for a switch where role messages
+// // are not supported - we confirm that the role being set is
+// // master and move to the next state
+// if (expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
+// if (role == Role.MASTER) {
+// setRoleAndStartDriverHandshake(h, role);
+// } else {
+// log.error("Expected MASTER role from registry for switch "
+// + "which has no support for role-messages."
+// + "Received {}. It is possible that this switch "
+// + "is connected to other controllers, in which "
+// + "case it should support role messages - not "
+// + "moving forward.", role);
+// }
+// } // else do nothing - wait to hear back from registry
+//
+// }
+//
+// private void setRoleAndStartDriverHandshake(OFChannelHandler h,
+// Role role) throws IOException {
+// h.setSwitchRole(role);
+// h.sw.startDriverHandshake();
+// if (h.sw.isDriverHandshakeComplete()) {
+// Role mySwitchRole = h.sw.getRole();
+// if (mySwitchRole == Role.MASTER) {
+// log.info("Switch-driver sub-handshake complete. "
+// + "Activating switch {} with Role: MASTER",
+// h.sw.getStringId());
+// handlePendingPortStatusMessages(h); //before activation
+// boolean success = h.sw.addActivatedMasterSwitch();
+// if (!success) {
+// disconnectDuplicate(h);
+// return;
+// }
+// h.setState(MASTER);
+// } else {
+// log.info("Switch-driver sub-handshake complete. "
+// + "Activating switch {} with Role: EQUAL",
+// h.sw.getStringId());
+// handlePendingPortStatusMessages(h); //before activation
+// boolean success = h.sw.addActivatedEqualSwitch();
+// if (!success) {
+// disconnectDuplicate(h);
+// return;
+// }
+// h.setState(EQUAL);
+// }
+// } else {
+// h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
+// }
+// }
+//
+// @Override
+// void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
+// throws IOException, SwitchStateException {
+// illegalMessageReceived(h, m);
+// }
+//
+// @Override
+// void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
+// throws SwitchStateException {
+// illegalMessageReceived(h, m);
+// }
+//
+// @Override
+// void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+// throws IOException, SwitchStateException {
+// h.pendingPortStatusMsg.add(m);
+//
+// }
+//},
+
+
+
+
+
+
+
+///**
+// * This controller is in EQUAL role for this switch. We enter this state
+// * after some /other/ controller instance wins mastership-role over this
+// * switch. The EQUAL role can be considered the same as the SLAVE role
+// * if this controller does NOT send commands or packets to the switch.
+// * This should always be true for OF1.0 switches. XXX S need to enforce.
+// *
+// * For OF1.3 switches, choosing this state as EQUAL instead of SLAVE,
+// * gives us the flexibility that if an app wants to send commands/packets
+// * to switches, it can, even thought it is running on a controller instance
+// * that is not in a MASTER role for this switch. Of course, it is the job
+// * of the app to ensure that commands/packets sent by this (EQUAL) controller
+// * instance does not clash/conflict with commands/packets sent by the MASTER
+// * controller for this switch. Neither the controller instances, nor the
+// * switch provides any kind of resolution mechanism should conflicts occur.
+// */
+//EQUAL(true) {
+// @Override
+// void processOFError(OFChannelHandler h, OFErrorMsg m)
+// throws IOException, SwitchStateException {
+// // role changer will ignore the error if it isn't for it
+// RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
+// if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
+// logError(h, m);
+// h.dispatchMessage(m);
+// }
+// }
+//
+// @Override
+// void processOFStatisticsReply(OFChannelHandler h,
+// OFStatsReply m) {
+// h.sw.handleMessage(m);
+// }
+//
+// @Override
+// void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
+// throws IOException, SwitchStateException {
+// Role role = extractNiciraRoleReply(h, m);
+// // If role == null it means the message wasn't really a
+// // Nicira role reply. We ignore it in this state.
+// if (role != null) {
+// RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
+// new RoleReplyInfo(role, null, m.getXid()));
+// if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+// checkAndSetRoleTransition(h, role);
+// }
+// } else {
+// unhandledMessageReceived(h, m);
+// }
+// }
+//
+// @Override
+// void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
+// throws SwitchStateException, IOException {
+// RoleReplyInfo rri = extractOFRoleReply(h, m);
+// RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
+// if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+// checkAndSetRoleTransition(h, rri.getRole());
+// }
+// }
+//
+// // XXX S needs more handlers for 1.3 switches in equal role
+//
+// @Override
+// void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+// throws IOException, SwitchStateException {
+// handlePortStatusMessage(h, m, true);
+// }
+//
+// @Override
+// @LogMessageDoc(level = "WARN",
+// message = "Received PacketIn from switch {} while "
+// + "being slave. Reasserting slave role.",
+// explanation = "The switch has receive a PacketIn despite being "
+// + "in slave role indicating inconsistent controller roles",
+// recommendation = "This situation can occurs transiently during role"
+// + " changes. If, however, the condition persists or happens"
+// + " frequently this indicates a role inconsistency. "
+// + LogMessageDoc.CHECK_CONTROLLER)
+// void processOFPacketIn(OFChannelHandler h, OFPacketIn m) throws IOException {
+// // we don't expect packetIn while slave, reassert we are slave
+// h.counters.packetInWhileSwitchIsSlave.updateCounterNoFlush();
+// log.warn("Received PacketIn from switch {} while" +
+// "being slave. Reasserting slave role.", h.sw);
+// //h.controller.reassertRole(h, Role.SLAVE);
+// // XXX reassert in role changer
+// }
+//};
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/ControllerRegistryEntry.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/ControllerRegistryEntry.java
deleted file mode 100644
index 5e83348..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/ControllerRegistryEntry.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.onlab.onos.of.controller.impl.registry;
-
-
-
-public class ControllerRegistryEntry implements Comparable<ControllerRegistryEntry> {
- //
- // TODO: Refactor the implementation and decide whether controllerId
- // is needed. If "yes", we might need to consider it inside the
- // compareTo(), equals() and hashCode() implementations.
- //
- private final String controllerId;
- private final int sequenceNumber;
-
- public ControllerRegistryEntry(String controllerId, int sequenceNumber) {
- this.controllerId = controllerId;
- this.sequenceNumber = sequenceNumber;
- }
-
- public String getControllerId() {
- return controllerId;
- }
-
- /**
- * Compares this object with the specified object for order.
- * NOTE: the test is based on ControllerRegistryEntry sequence numbers,
- * and doesn't include the controllerId.
- *
- * @param o the object to be compared.
- * @return a negative integer, zero, or a positive integer as this object
- * is less than, equal to, or greater than the specified object.
- */
- @Override
- public int compareTo(ControllerRegistryEntry o) {
- return this.sequenceNumber - o.sequenceNumber;
- }
-
- /**
- * Test whether some other object is "equal to" this one.
- * NOTE: the test is based on ControllerRegistryEntry sequence numbers,
- * and doesn't include the controllerId.
- *
- * @param obj the reference object with which to compare.
- * @return true if this object is the same as the obj argument; false
- * otherwise.
- */
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof ControllerRegistryEntry) {
- ControllerRegistryEntry other = (ControllerRegistryEntry) obj;
- return this.sequenceNumber == other.sequenceNumber;
- }
- return false;
- }
-
- /**
- * Get the hash code for the object.
- * NOTE: the computation is based on ControllerRegistryEntry sequence
- * numbers, and doesn't include the controller ID.
- *
- * @return a hash code value for this object.
- */
- @Override
- public int hashCode() {
- return Integer.valueOf(this.sequenceNumber).hashCode();
- }
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/IControllerRegistry.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/IControllerRegistry.java
deleted file mode 100644
index 21b1709..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/IControllerRegistry.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package org.onlab.onos.of.controller.impl.registry;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import org.onlab.onos.of.controller.impl.util.InstanceId;
-
-/**
- * A registry service that allows ONOS to register controllers and switches in a
- * way that is global to the entire ONOS cluster. The registry is the arbiter
- * for allowing controllers to control switches.
- * <p/>
- * The OVS/OF1.{2,3} fault tolerance model is a switch connects to multiple
- * controllers, and the controllers send role requests to tell the switch their
- * role in controlling the switch.
- * <p/>
- * The ONOS fault tolerance model allows only a single controller to have
- * control of a switch (MASTER role) at once. Controllers therefore need a
- * mechanism that enables them to decide who should control a each switch. The
- * registry service provides this mechanism.
- */
-public interface IControllerRegistry {
-
- /**
- * Callback interface for control change events.
- */
- public interface ControlChangeCallback {
- /**
- * Called whenever the control changes from the point of view of the
- * registry. The callee can check whether they have control or not using
- * the hasControl parameter.
- *
- * @param dpid The switch that control has changed for
- * @param hasControl Whether the listener now has control or not
- */
- void controlChanged(long dpid, boolean hasControl);
- }
-
- /**
- * Request for control of a switch. This method does not block. When control
- * for a switch changes, the controlChanged method on the callback object
- * will be called. This happens any time the control changes while the
- * request is still active (until releaseControl is called)
- *
- * @param dpid Switch to request control for
- * @param cb Callback that will be used to notify caller of control changes
- * @throws RegistryException Errors contacting the registry service
- */
- public void requestControl(long dpid, ControlChangeCallback cb)
- throws RegistryException;
-
- /**
- * Stop trying to take control of a switch. This removes the entry for this
- * controller requesting this switch in the registry. If the controller had
- * control when this is called, another controller will now gain control of
- * the switch. This call doesn't block.
- *
- * @param dpid Switch to release control of
- */
- public void releaseControl(long dpid);
-
- /**
- * Check whether the controller has control of the switch This call doesn't
- * block.
- *
- * @param dpid Switch to check control of
- * @return true if controller has control of the switch.
- */
- public boolean hasControl(long dpid);
-
- /**
- * Check whether this instance is the leader for the cluster. This call
- * doesn't block.
- *
- * @return true if the instance is the leader for the cluster, otherwise
- * false.
- */
- public boolean isClusterLeader();
-
- /**
- * Gets the unique ID used to identify this ONOS instance in the cluster.
- *
- * @return Instance ID.
- */
- public InstanceId getOnosInstanceId();
-
- /**
- * Register a controller to the ONOS cluster. Must be called before the
- * registry can be used to take control of any switches.
- *
- * @param controllerId A unique string ID identifying this controller in the
- * cluster
- * @throws RegistryException for errors connecting to registry service,
- * controllerId already registered
- */
- public void registerController(String controllerId)
- throws RegistryException;
-
- /**
- * Get all controllers in the cluster.
- *
- * @return Collection of controller IDs
- * @throws RegistryException on error
- */
- public Collection<String> getAllControllers() throws RegistryException;
-
- /**
- * Get all switches in the cluster, along with which controller is in
- * control of them (if any) and any other controllers that have requested
- * control.
- *
- * @return Map of all switches.
- */
- public Map<String, List<ControllerRegistryEntry>> getAllSwitches();
-
- /**
- * Get the controller that has control of a given switch.
- *
- * @param dpid Switch to find controller for
- * @return controller ID
- * @throws RegistryException Errors contacting registry service
- */
- public String getControllerForSwitch(long dpid) throws RegistryException;
-
- /**
- * Get all switches controlled by a given controller.
- *
- * @param controllerId ID of the controller
- * @return Collection of dpids
- */
- public Collection<Long> getSwitchesControlledByController(String controllerId);
-
- /**
- * Get a unique Id Block.
- *
- * @return Id Block.
- */
- public IdBlock allocateUniqueIdBlock();
-
- /**
- * Get next unique id and retrieve a new range of ids if needed.
- *
- * @param range range to use for the identifier
- * @return Id Block.
- */
- public IdBlock allocateUniqueIdBlock(long range);
-
- /**
- * Get a globally unique ID.
- *
- * @return a globally unique ID.
- */
- public long getNextUniqueId();
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/IdBlock.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/IdBlock.java
deleted file mode 100644
index 406a60d..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/IdBlock.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.onlab.onos.of.controller.impl.registry;
-
-public class IdBlock {
- private final long start;
- private final long end;
- private final long size;
-
- public IdBlock(long start, long end, long size) {
- this.start = start;
- this.end = end;
- this.size = size;
- }
-
- public long getStart() {
- return start;
- }
-
- public long getEnd() {
- return end;
- }
-
- public long getSize() {
- return size;
- }
-
- @Override
- public String toString() {
- return "IdBlock [start=" + start + ", end=" + end + ", size=" + size
- + "]";
- }
-}
-
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/RegistryException.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/RegistryException.java
deleted file mode 100644
index 029f028..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/RegistryException.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.onlab.onos.of.controller.impl.registry;
-
-public class RegistryException extends Exception {
-
- private static final long serialVersionUID = -8276300722010217913L;
-
- public RegistryException(String message) {
- super(message);
- }
-
- public RegistryException(String message, Throwable cause) {
- super(message, cause);
- }
-
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/DummySwitchForTesting.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/DummySwitchForTesting.java
deleted file mode 100644
index 2d925f8..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/DummySwitchForTesting.java
+++ /dev/null
@@ -1,360 +0,0 @@
-package org.onlab.onos.of.controller.impl.util;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Future;
-
-import org.jboss.netty.channel.Channel;
-import org.projectfloodlight.openflow.protocol.OFActionType;
-import org.projectfloodlight.openflow.protocol.OFCapabilities;
-import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFPortStatus;
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.U64;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.onlab.onos.of.controller.impl.IOFSwitch;
-import org.onlab.onos.of.controller.impl.Role;
-import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService;
-import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService.CounterException;
-
-public class DummySwitchForTesting implements IOFSwitch {
-
- protected static final Logger log = LoggerFactory.getLogger(DummySwitchForTesting.class);
-
- private Channel channel;
- private boolean connected = false;
- private OFVersion ofv = OFVersion.OF_10;
-
- private Collection<OFPortDesc> ports;
-
- private DatapathId datapathId;
-
- private Set<OFCapabilities> capabilities;
-
- private int buffers;
-
- private byte tables;
-
- private String stringId;
-
- private Role role;
-
- @Override
- public void disconnectSwitch() {
- this.channel.close();
- }
-
- @Override
- public void write(OFMessage m) throws IOException {
- this.channel.write(m);
-
- }
-
- @Override
- public void write(List<OFMessage> msglist) throws IOException {
- for (OFMessage m : msglist) {
- this.channel.write(m);
- }
-
- }
-
- @Override
- public Date getConnectedSince() {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public int getNextTransactionId() {
- return 0;
- }
-
- @Override
- public boolean isConnected() {
- return this.connected;
- }
-
- @Override
- public void setConnected(boolean connected) {
- this.connected = connected;
-
- }
-
- @Override
- public void flush() {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setChannel(Channel channel) {
- this.channel = channel;
-
- }
-
- @Override
- public long getId() {
- if (this.stringId == null) {
- throw new RuntimeException("Features reply has not yet been set");
- }
- return this.datapathId.getLong();
- }
-
- @Override
- public String getStringId() {
- // TODO Auto-generated method stub
- return "DummySwitch";
- }
-
- @Override
- public int getNumBuffers() {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public Set<OFCapabilities> getCapabilities() {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public byte getNumTables() {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public OFDescStatsReply getSwitchDescription() {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void cancelFeaturesReply(int transactionId) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public Set<OFActionType> getActions() {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void setOFVersion(OFVersion version) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public OFVersion getOFVersion() {
- return this.ofv;
- }
-
- @Override
- public Collection<OFPortDesc> getEnabledPorts() {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Collection<Integer> getEnabledPortNumbers() {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public OFPortDesc getPort(int portNumber) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public OFPortDesc getPort(String portName) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public OrderedCollection<PortChangeEvent> processOFPortStatus(
- OFPortStatus ps) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Collection<OFPortDesc> getPorts() {
- return ports;
- }
-
- @Override
- public boolean portEnabled(int portName) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public OrderedCollection<PortChangeEvent> setPorts(
- Collection<OFPortDesc> p) {
- this.ports = p;
- return null;
- }
-
- @Override
- public Map<Object, Object> getAttributes() {
- return null;
- }
-
- @Override
- public boolean hasAttribute(String name) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public Object getAttribute(String name) {
- return Boolean.FALSE;
- }
-
- @Override
- public void setAttribute(String name, Object value) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public Object removeAttribute(String name) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void deliverStatisticsReply(OFMessage reply) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void cancelStatisticsReply(int transactionId) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void cancelAllStatisticsReplies() {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public Future<List<OFStatsReply>> getStatistics(OFStatsRequest<?> request)
- throws IOException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void clearAllFlowMods() {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public Role getRole() {
- return this.role;
- }
-
- @Override
- public void setRole(Role role) {
- this.role = role;
- }
-
- @Override
- public U64 getNextGenerationId() {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void setDebugCounterService(IDebugCounterService debugCounter)
- throws CounterException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void startDriverHandshake() throws IOException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean isDriverHandshakeComplete() {
- return true;
- }
-
- @Override
- public void processDriverHandshakeMessage(OFMessage m) {
-
- }
-
- @Override
- public void setTableFull(boolean isFull) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setFeaturesReply(OFFeaturesReply featuresReply) {
- if (featuresReply == null) {
- log.error("Error setting featuresReply for switch: {}", getStringId());
- return;
- }
- this.datapathId = featuresReply.getDatapathId();
- this.capabilities = featuresReply.getCapabilities();
- this.buffers = (int) featuresReply.getNBuffers();
- this.tables = (byte) featuresReply.getNTables();
- this.stringId = this.datapathId.toString();
-
- }
-
- @Override
- public void setPortDescReply(OFPortDescStatsReply portDescReply) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void handleMessage(OFMessage m) {
- log.info("Got packet {} but I am dumb so I don't know what to do.", m);
- }
-
- @Override
- public boolean portEnabled(String portName) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public OrderedCollection<PortChangeEvent> comparePorts(
- Collection<OFPortDesc> p) {
- // TODO Auto-generated method stub
- return null;
- }
-
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/EnumBitmaps.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/EnumBitmaps.java
deleted file mode 100644
index c7734c0..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/EnumBitmaps.java
+++ /dev/null
@@ -1,149 +0,0 @@
-package org.onlab.onos.of.controller.impl.util;
-
-import java.util.EnumSet;
-import java.util.Set;
-
-/**
- * A utility class to convert between integer based bitmaps for (OpenFlow)
- * flags and Enum and EnumSet based representations.
- *
- * The enum used to represent individual flags needs to implement the
- * BitmapableEnum interface.
- *
- * Example:
- * {@code
- * int bitmap = 0x11; // OFPPC_PORT_DOWN | OFPPC_NO_STP
- * EnumSet<OFPortConfig> s = toEnumSet(OFPortConfig.class, bitmap);
- * // s will contain OFPPC_PORT_DOWN and OFPPC_NO_STP
- * }
- *
- * {@code
- * EnumSet<OFPortConfig> s = EnumSet.of(OFPPC_NO_STP, OFPPC_PORT_DOWN);
- * int bitmap = toBitmap(s); // returns 0x11
- * }
- *
- */
-public final class EnumBitmaps {
-
-
- private EnumBitmaps() { }
-
- /**
- * Enums used to represent individual flags needs to implement this
- * interface.
- */
- public interface BitmapableEnum {
- /** Return the value in the bitmap that the enum constant represents.
- * The returned value must have only a single bit set. E.g.,1 << 3
- */
- int getValue();
- }
-
-
- /**
- * Convert an integer bitmap to an EnumSet.
- *
- * See class description for example
- * @param type The Enum class to use. Must implement BitmapableEnum
- * @param bitmap The integer bitmap
- * @return A newly allocated EnumSet representing the bits set in the
- * bitmap
- * @throws NullPointerException if type is null
- * @throws IllegalArgumentException if any enum constant from type has
- * more than one bit set.
- * @throws IllegalArgumentException if the bitmap has any bits set not
- * represented by an enum constant.
- */
- public static <E extends Enum<E> & BitmapableEnum>
- EnumSet<E> toEnumSet(Class<E> type, int bitmap) {
- if (type == null) {
- throw new NullPointerException("Given enum type must not be null");
- }
- EnumSet<E> s = EnumSet.noneOf(type);
- // allSetBitmap will eventually have all valid bits for the given
- // type set.
- int allSetBitmap = 0;
- for (E element: type.getEnumConstants()) {
- if (Integer.bitCount(element.getValue()) != 1) {
- String msg = String.format("The %s (%x) constant of the " +
- "enum %s is supposed to represent a bitmap entry but " +
- "has more than one bit set.",
- element.toString(), element.getValue(), type.getName());
- throw new IllegalArgumentException(msg);
- }
- allSetBitmap |= element.getValue();
- if ((bitmap & element.getValue()) != 0) {
- s.add(element);
- }
- }
- if (((~allSetBitmap) & bitmap) != 0) {
- // check if only valid flags are set in the given bitmap
- String msg = String.format("The bitmap %x for enum %s has " +
- "bits set that are presented by any enum constant",
- bitmap, type.getName());
- throw new IllegalArgumentException(msg);
- }
- return s;
- }
-
- /**
- * Return the bitmap mask with all possible bits set. E.g., If a bitmap
- * has the individual flags 0x1, 0x2, and 0x8 (note the missing 0x4) then
- * the mask will be 0xb (1011 binary)
- *
- * @param type The Enum class to use. Must implement BitmapableEnum
- * @throws NullPointerException if type is null
- * @throws IllegalArgumentException if any enum constant from type has
- * more than one bit set
- * @return an integer with all possible bits for the given bitmap enum
- * type set.
- */
- public static <E extends Enum<E> & BitmapableEnum>
- int getMask(Class<E> type) {
- if (type == null) {
- throw new NullPointerException("Given enum type must not be null");
- }
- // allSetBitmap will eventually have all valid bits for the given
- // type set.
- int allSetBitmap = 0;
- for (E element: type.getEnumConstants()) {
- if (Integer.bitCount(element.getValue()) != 1) {
- String msg = String.format("The %s (%x) constant of the " +
- "enum %s is supposed to represent a bitmap entry but " +
- "has more than one bit set.",
- element.toString(), element.getValue(), type.getName());
- throw new IllegalArgumentException(msg);
- }
- allSetBitmap |= element.getValue();
- }
- return allSetBitmap;
- }
-
- /**
- * Convert the given EnumSet to the integer bitmap representation.
- * @param set The EnumSet to convert. The enum must implement
- * BitmapableEnum
- * @return the integer bitmap
- * @throws IllegalArgumentException if an enum constant from the set (!) has
- * more than one bit set
- * @throws NullPointerException if the set is null
- */
- public static <E extends Enum<E> & BitmapableEnum>
- int toBitmap(Set<E> set) {
- if (set == null) {
- throw new NullPointerException("Given set must not be null");
- }
- int bitmap = 0;
- for (E element: set) {
- if (Integer.bitCount(element.getValue()) != 1) {
- String msg = String.format("The %s (%x) constant in the set " +
- "is supposed to represent a bitmap entry but " +
- "has more than one bit set.",
- element.toString(), element.getValue());
- throw new IllegalArgumentException(msg);
- }
- bitmap |= element.getValue();
- }
- return bitmap;
- }
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/FilterIterator.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/FilterIterator.java
deleted file mode 100644
index 319aae8..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/FilterIterator.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * Copyright 2012, Big Switch Networks, Inc.
- * Originally created by David Erickson, Stanford University
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- **/
-
-package org.onlab.onos.of.controller.impl.util;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-/**
- * An iterator that will filter values from an iterator and return only
- * those values that match the predicate.
- */
-public abstract class FilterIterator<T> implements Iterator<T> {
- protected Iterator<T> subIterator;
- protected T next;
-
- /**
- * Construct a filter iterator from the given sub iterator.
- *
- * @param subIterator the sub iterator over which we'll filter
- */
- public FilterIterator(Iterator<T> subIterator) {
- super();
- this.subIterator = subIterator;
- }
-
- /**
- * Check whether the given value should be returned by the
- * filter.
- *
- * @param value the value to check
- * @return true if the value should be included
- */
- protected abstract boolean matches(T value);
-
- // ***********
- // Iterator<T>
- // ***********
-
- @Override
- public boolean hasNext() {
- if (next != null) {
- return true;
- }
-
- while (subIterator.hasNext()) {
- next = subIterator.next();
- if (matches(next)) {
- return true;
- }
- }
- next = null;
- return false;
- }
-
- @Override
- public T next() {
- if (hasNext()) {
- T cur = next;
- next = null;
- return cur;
- }
- throw new NoSuchElementException();
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/InstanceId.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/InstanceId.java
deleted file mode 100644
index 4a7892e..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/InstanceId.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.onlab.onos.of.controller.impl.util;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkArgument;
-
-/**
- * The class representing an ONOS Instance ID.
- *
- * This class is immutable.
- */
-public final class InstanceId {
- private final String id;
-
- /**
- * Constructor from a string value.
- *
- * @param id the value to use.
- */
- public InstanceId(String id) {
- this.id = checkNotNull(id);
- checkArgument(!id.isEmpty(), "Empty ONOS Instance ID");
- }
-
- @Override
- public int hashCode() {
- return id.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
-
- if (!(obj instanceof InstanceId)) {
- return false;
- }
-
- InstanceId that = (InstanceId) obj;
- return this.id.equals(that.id);
- }
-
- @Override
- public String toString() {
- return id;
- }
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/IterableIterator.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/IterableIterator.java
deleted file mode 100644
index a59b244..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/IterableIterator.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Copyright 2012 Big Switch Networks, Inc.
- * Originally created by David Erickson, Stanford University
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- **/
-
-package org.onlab.onos.of.controller.impl.util;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-/**
- * Iterator over all values in an iterator of iterators.
- *
- * @param <T> the type of elements returned by this iterator
- */
-public class IterableIterator<T> implements Iterator<T> {
- Iterator<? extends Iterable<T>> subIterator;
- Iterator<T> current = null;
-
- public IterableIterator(Iterator<? extends Iterable<T>> subIterator) {
- super();
- this.subIterator = subIterator;
- }
-
- @Override
- public boolean hasNext() {
- if (current == null) {
- if (subIterator.hasNext()) {
- current = subIterator.next().iterator();
- } else {
- return false;
- }
- }
- while (!current.hasNext() && subIterator.hasNext()) {
- current = subIterator.next().iterator();
- }
-
- return current.hasNext();
- }
-
- @Override
- public T next() {
- if (hasNext()) {
- return current.next();
- }
- throw new NoSuchElementException();
- }
-
- @Override
- public void remove() {
- if (hasNext()) {
- current.remove();
- }
- throw new NoSuchElementException();
- }
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/LRUHashMap.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/LRUHashMap.java
deleted file mode 100644
index 866794f..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/LRUHashMap.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Copyright 2011, Big Switch Networks, Inc.
- * Originally created by David Erickson, Stanford University
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- **/
-
-package org.onlab.onos.of.controller.impl.util;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-public class LRUHashMap<K, V> extends LinkedHashMap<K, V> {
-
- private static final long serialVersionUID = 1L;
-
- private final int capacity;
-
- public LRUHashMap(int capacity) {
- super(capacity + 1, 0.75f, true);
- this.capacity = capacity;
- }
-
- protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
- return size() > capacity;
- }
-
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/LinkedHashSetWrapper.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/LinkedHashSetWrapper.java
deleted file mode 100644
index 1778d06..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/LinkedHashSetWrapper.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.onlab.onos.of.controller.impl.util;
-
-import java.util.Collection;
-import java.util.LinkedHashSet;
-
-import com.google.common.collect.ForwardingCollection;
-
-/**
- * A simple wrapper / forwarder that forwards all calls to a LinkedHashSet.
- * This wrappers sole reason for existence is to implement the
- * OrderedCollection marker interface.
- *
- */
-public class LinkedHashSetWrapper<E>
- extends ForwardingCollection<E> implements OrderedCollection<E> {
- private final Collection<E> delegate;
-
- public LinkedHashSetWrapper() {
- super();
- this.delegate = new LinkedHashSet<E>();
- }
-
- public LinkedHashSetWrapper(Collection<? extends E> c) {
- super();
- this.delegate = new LinkedHashSet<E>(c);
- }
-
- @Override
- protected Collection<E> delegate() {
- return this.delegate;
- }
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/MultiIterator.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/MultiIterator.java
deleted file mode 100644
index 7b709e9..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/MultiIterator.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Copyright 2012 Big Switch Networks, Inc.
- * Originally created by David Erickson, Stanford University
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- **/
-
-package org.onlab.onos.of.controller.impl.util;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-/**
- * Iterator over all values in an iterator of iterators.
- *
- * @param <T> the type of elements returned by this iterator
- */
-public class MultiIterator<T> implements Iterator<T> {
- Iterator<Iterator<T>> subIterator;
- Iterator<T> current = null;
-
- public MultiIterator(Iterator<Iterator<T>> subIterator) {
- super();
- this.subIterator = subIterator;
- }
-
- @Override
- public boolean hasNext() {
- if (current == null) {
- if (subIterator.hasNext()) {
- current = subIterator.next();
- } else {
- return false;
- }
- }
- while (!current.hasNext() && subIterator.hasNext()) {
- current = subIterator.next();
- }
-
- return current.hasNext();
- }
-
- @Override
- public T next() {
- if (hasNext()) {
- return current.next();
- }
- throw new NoSuchElementException();
- }
-
- @Override
- public void remove() {
- if (hasNext()) {
- current.remove();
- }
- throw new NoSuchElementException();
- }
-}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/OrderedCollection.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/OrderedCollection.java
deleted file mode 100644
index 9dce568..0000000
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/OrderedCollection.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.onlab.onos.of.controller.impl.util;
-
-import java.util.Collection;
-
-/**
- * A marker interface indicating that this Collection defines a particular
- * iteration order. The details about the iteration order are specified by
- * the concrete implementation.
- *
- * @param <E>
- */
-public interface OrderedCollection<E> extends Collection<E> {
-
-}
diff --git a/of/ctl/src/test/java/org/onlab/onos/of/controller/impl/internal/ControllerTest.java b/of/ctl/src/test/java/org/onlab/onos/of/controller/impl/internal/ControllerTest.java
deleted file mode 100644
index 5de3647..0000000
--- a/of/ctl/src/test/java/org/onlab/onos/of/controller/impl/internal/ControllerTest.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/**
- * Copyright 2011, Big Switch Networks, Inc.
- * Originally created by David Erickson, Stanford University
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- **/
-
-package org.onlab.onos.of.controller.impl.internal;
-
-import junit.framework.TestCase;
-import org.onlab.onos.of.controller.impl.IOFSwitch;
-
-import org.easymock.EasyMock;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-
-public class ControllerTest extends TestCase {
-
- private Controller controller;
- private IOFSwitch sw;
- private OFChannelHandler h;
-
- @Override
- @Before
- public void setUp() throws Exception {
- super.setUp();
- sw = EasyMock.createMock(IOFSwitch.class);
- h = EasyMock.createMock(OFChannelHandler.class);
- controller = new Controller();
- ControllerRunThread t = new ControllerRunThread();
- t.start();
- /*
- * Making sure the thread is properly started before making calls
- * to controller class.
- */
- Thread.sleep(200);
- }
-
- /**
- * Starts the base mocks used in these tests.
- */
- private void startMocks() {
- EasyMock.replay(sw, h);
- }
-
- /**
- * Reset the mocks to a known state.
- * Automatically called after tests.
- */
- @After
- private void resetMocks() {
- EasyMock.reset(sw);
- }
-
- /**
- * Fetches the controller instance.
- * @return the controller
- */
- public Controller getController() {
- return controller;
- }
-
- /**
- * Run the controller's main loop so that updates are processed.
- */
- protected class ControllerRunThread extends Thread {
- @Override
- public void run() {
- controller.openFlowPort = 0; // Don't listen
- controller.activate();
- }
- }
-
- /**
- * Verify that we are able to add a switch that just connected.
- * If it already exists then this should fail
- *
- * @throws Exception error
- */
- @Test
- public void testAddConnectedSwitches() throws Exception {
- startMocks();
- assertTrue(controller.addConnectedSwitch(0, h));
- assertFalse(controller.addConnectedSwitch(0, h));
- }
-
- /**
- * Add active master but cannot re-add active master.
- * @throws Exception an error occurred.
- */
- @Test
- public void testAddActivatedMasterSwitch() throws Exception {
- startMocks();
- controller.addConnectedSwitch(0, h);
- assertTrue(controller.addActivatedMasterSwitch(0, sw));
- assertFalse(controller.addActivatedMasterSwitch(0, sw));
- }
-
- /**
- * Tests that an activated switch can be added but cannot be re-added.
- *
- * @throws Exception an error occurred
- */
- @Test
- public void testAddActivatedEqualSwitch() throws Exception {
- startMocks();
- controller.addConnectedSwitch(0, h);
- assertTrue(controller.addActivatedEqualSwitch(0, sw));
- assertFalse(controller.addActivatedEqualSwitch(0, sw));
- }
-
- /**
- * Move an equal switch to master.
- * @throws Exception an error occurred
- */
- @Test
- public void testTranstitionToMaster() throws Exception {
- startMocks();
- controller.addConnectedSwitch(0, h);
- controller.addActivatedEqualSwitch(0, sw);
- controller.transitionToMasterSwitch(0);
- assertNotNull(controller.getMasterSwitch(0));
- }
-
- /**
- * Transition a master switch to equal state.
- * @throws Exception an error occurred
- */
- @Test
- public void testTranstitionToEqual() throws Exception {
- startMocks();
- controller.addConnectedSwitch(0, h);
- controller.addActivatedMasterSwitch(0, sw);
- controller.transitionToEqualSwitch(0);
- assertNotNull(controller.getEqualSwitch(0));
- }
-
- /**
- * Remove the switch from the controller instance.
- * @throws Exception an error occurred
- */
- @Test
- public void testRemoveSwitch() throws Exception {
- sw.cancelAllStatisticsReplies();
- EasyMock.expectLastCall().once();
- sw.setConnected(false);
- EasyMock.expectLastCall().once();
- startMocks();
- controller.addConnectedSwitch(0, h);
- controller.addActivatedMasterSwitch(0, sw);
- controller.removeConnectedSwitch(0);
- assertNull(controller.getSwitch(0));
- EasyMock.verify(sw, h);
- }
-}
diff --git a/of/ctl/src/test/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandlerTest.java b/of/ctl/src/test/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandlerTest.java
deleted file mode 100644
index f267923..0000000
--- a/of/ctl/src/test/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandlerTest.java
+++ /dev/null
@@ -1,1569 +0,0 @@
-package org.onlab.onos.of.controller.impl.internal;
-
-import static org.easymock.EasyMock.capture;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.onlab.onos.of.controller.impl.IOFSwitch;
-import org.onlab.onos.of.controller.impl.Role;
-import org.onlab.onos.of.controller.impl.debugcounter.DebugCounter;
-import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService;
-import org.onlab.onos.of.controller.impl.internal.OFChannelHandler.RoleRecvStatus;
-
-import org.easymock.Capture;
-import org.easymock.CaptureType;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.channel.ChannelStateEvent;
-import org.jboss.netty.channel.ExceptionEvent;
-import org.jboss.netty.channel.MessageEvent;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFExperimenter;
-import org.projectfloodlight.openflow.protocol.OFFactories;
-import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
-import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
-import org.projectfloodlight.openflow.protocol.OFHelloElem;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
-import org.projectfloodlight.openflow.protocol.OFPacketIn;
-import org.projectfloodlight.openflow.protocol.OFPacketInReason;
-import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFSetConfig;
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFStatsType;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.U32;
-
-/**
- * Channel handler deals with the switch connection and dispatches
- * switch messages to the appropriate locations. These Unit Testing cases
- * test the channeler state machine and role changer. In the first release,
- * we will focus on OF version 1.0. we will add the testing case for
- * version 1.3 later.
- */
-public class OFChannelHandlerTest {
- private Controller controller;
- private IDebugCounterService debugCounterService;
- private OFChannelHandler handler;
- private Channel channel;
- private ChannelHandlerContext ctx;
- private MessageEvent messageEvent;
- private ChannelStateEvent channelStateEvent;
- private ChannelPipeline pipeline;
- private Capture<ExceptionEvent> exceptionEventCapture;
- private Capture<List<OFMessage>> writeCapture;
- private OFFeaturesReply featuresReply;
- private Set<Integer> seenXids = null;
- private IOFSwitch swImplBase;
- private OFVersion ofVersion = OFVersion.OF_10;
- private OFFactory factory13;
- private OFFactory factory10;
- private OFFactory factory;
-
- @Before
- public void setUp() throws Exception {
- controller = createMock(Controller.class);
- ctx = createMock(ChannelHandlerContext.class);
- channelStateEvent = createMock(ChannelStateEvent.class);
- channel = createMock(Channel.class);
- messageEvent = createMock(MessageEvent.class);
- exceptionEventCapture = new Capture<ExceptionEvent>(CaptureType.ALL);
- pipeline = createMock(ChannelPipeline.class);
- writeCapture = new Capture<List<OFMessage>>(CaptureType.ALL);
- swImplBase = createMock(IOFSwitch.class);
- seenXids = null;
- factory13 = OFFactories.getFactory(OFVersion.OF_13);
- factory10 = OFFactories.getFactory(OFVersion.OF_10);
- factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
-
- // TODO: should mock IDebugCounterService and make sure
- // the expected counters are updated.
- debugCounterService = new DebugCounter();
- Controller.Counters counters =
- new Controller.Counters();
- counters.createCounters(debugCounterService);
- expect(controller.getCounters()).andReturn(counters).anyTimes();
- expect(controller.getOFMessageFactory10()).andReturn(factory10)
- .anyTimes();
- expect(controller.getOFMessageFactory13()).andReturn(factory13)
- .anyTimes();
- expect(controller.addConnectedSwitch(2000, handler)).andReturn(true)
- .anyTimes();
- replay(controller);
- handler = new OFChannelHandler(controller);
- verify(controller);
- reset(controller);
-
- resetChannel();
-
- // replay controller. Reset it if you need more specific behavior
- replay(controller);
-
- // replay switch. Reset it if you need more specific behavior
- replay(swImplBase);
-
- // Mock ctx and channelStateEvent
- expect(ctx.getChannel()).andReturn(channel).anyTimes();
- expect(channelStateEvent.getChannel()).andReturn(channel).anyTimes();
- replay(ctx, channelStateEvent);
-
- /* Setup an exception event capture on the channel. Right now
- * we only expect exception events to be send up the channel.
- * However, it's easy to extend to other events if we need it
- */
- pipeline.sendUpstream(capture(exceptionEventCapture));
- expectLastCall().anyTimes();
- replay(pipeline);
- featuresReply = (OFFeaturesReply) buildOFMessage(OFType.FEATURES_REPLY);
- }
-
- @After
- public void tearDown() {
- /* ensure no exception was thrown */
- if (exceptionEventCapture.hasCaptured()) {
- Throwable ex = exceptionEventCapture.getValue().getCause();
- throw new AssertionError("Unexpected exception: " +
- ex.getClass().getName() + "(" + ex + ")");
- }
- assertFalse("Unexpected messages have been captured",
- writeCapture.hasCaptured());
- // verify all mocks.
- verify(channel);
- verify(messageEvent);
- verify(controller);
- verify(ctx);
- verify(channelStateEvent);
- verify(pipeline);
- verify(swImplBase);
-
- }
-
- /**
- * Reset the channel mock and set basic method call expectations.
- *
- **/
- void resetChannel() {
- reset(channel);
- expect(channel.getPipeline()).andReturn(pipeline).anyTimes();
- expect(channel.getRemoteAddress()).andReturn(null).anyTimes();
- }
-
- /**
- * reset, setup, and replay the messageEvent mock for the given
- * messages.
- */
- void setupMessageEvent(List<OFMessage> messages) {
- reset(messageEvent);
- expect(messageEvent.getMessage()).andReturn(messages).atLeastOnce();
- replay(messageEvent);
- }
-
- /**
- * reset, setup, and replay the messageEvent mock for the given
- * messages, mock controller send message to channel handler.
- *
- * This method will reset, start replay on controller, and then verify
- */
- void sendMessageToHandlerWithControllerReset(List<OFMessage> messages)
- throws Exception {
- verify(controller);
- reset(controller);
-
- sendMessageToHandlerNoControllerReset(messages);
- }
-
- /**
- * reset, setup, and replay the messageEvent mock for the given
- * messages, mock controller send message to channel handler.
- *
- * This method will start replay on controller, and then verify
- */
- void sendMessageToHandlerNoControllerReset(List<OFMessage> messages)
- throws Exception {
- setupMessageEvent(messages);
-
- expect(controller.addConnectedSwitch(1000, handler))
- .andReturn(true).anyTimes();
- replay(controller);
-
- handler.messageReceived(ctx, messageEvent);
- verify(controller);
- }
-
- /**
- * Extract the list of OFMessages that was captured by the Channel.write()
- * capture. Will check that something was actually captured first. We'll
- * collapse the messages from multiple writes into a single list of
- * OFMessages.
- * Resets the channelWriteCapture.
- */
- List<OFMessage> getMessagesFromCapture() {
- List<OFMessage> msgs = new ArrayList<OFMessage>();
-
- assertTrue("No write on channel was captured",
- writeCapture.hasCaptured());
- List<List<OFMessage>> capturedVals = writeCapture.getValues();
-
- for (List<OFMessage> oneWriteList: capturedVals) {
- msgs.addAll(oneWriteList);
- }
- writeCapture.reset();
- return msgs;
- }
-
-
- /**
- * Verify that the given exception event capture (as returned by
- * getAndInitExceptionCapture) has thrown an exception of the given
- * expectedExceptionClass.
- * Resets the capture
- */
- void verifyExceptionCaptured(
- Class<? extends Throwable> expectedExceptionClass) {
- assertTrue("Excpected exception not thrown",
- exceptionEventCapture.hasCaptured());
- Throwable caughtEx = exceptionEventCapture.getValue().getCause();
- assertEquals(expectedExceptionClass, caughtEx.getClass());
- exceptionEventCapture.reset();
- }
-
- /**
- * Make sure that the transaction ids in the given messages are
- * not 0 and differ between each other.
- * While it's not a defect per se if the xids are we want to ensure
- * we use different ones for each message we send.
- */
- void verifyUniqueXids(List<OFMessage> msgs) {
- if (seenXids == null) {
- seenXids = new HashSet<Integer>();
- }
- for (OFMessage m: msgs) {
- int xid = (int) m.getXid();
- assertTrue("Xid in messags is 0", xid != 0);
- assertFalse("Xid " + xid + " has already been used",
- seenXids.contains(xid));
- seenXids.add(xid);
- }
- }
-
-
-
- public void testInitState() throws Exception {
- OFMessage m = buildOFMessage(OFType.HELLO);
-
- expect(messageEvent.getMessage()).andReturn(null);
- replay(channel, messageEvent);
-
- // We don't expect to receive /any/ messages in init state since
- // channelConnected moves us to a different state
- sendMessageToHandlerWithControllerReset(Collections.singletonList(m));
-
- verifyExceptionCaptured(SwitchStateException.class);
- assertEquals(OFChannelHandler.ChannelState.INIT,
- handler.getStateForTesting());
- }
-
- /**
- * move the channel from scratch to WAIT_HELLO state.
- *
- */
- @Test
- public void moveToWaitHello() throws Exception {
- resetChannel();
- channel.write(capture(writeCapture));
- expectLastCall().andReturn(null).once();
- replay(channel);
- // replay unused mocks
- replay(messageEvent);
-
- handler.channelConnected(ctx, channelStateEvent);
-
- List<OFMessage> msgs = getMessagesFromCapture();
- assertEquals(1, msgs.size());
- assertEquals(OFType.HELLO, msgs.get(0).getType());
- assertEquals(OFChannelHandler.ChannelState.WAIT_HELLO,
- handler.getStateForTesting());
- //Should verify that the Hello received from the controller
- //is ALWAYS OF1.3 hello regardless of the switch version
- assertEquals(OFVersion.OF_13, msgs.get(0).getVersion());
- verifyUniqueXids(msgs);
- }
-
-
- /**
- * Move the channel from scratch to WAIT_FEATURES_REPLY state.
- * Builds on moveToWaitHello().
- * adds testing for WAIT_HELLO state.
- */
- @Test
- public void moveToWaitFeaturesReply() throws Exception {
- moveToWaitHello();
- resetChannel();
- channel.write(capture(writeCapture));
- expectLastCall().andReturn(null).atLeastOnce();
- replay(channel);
-
- OFMessage hello = buildOFMessage(OFType.HELLO);
- sendMessageToHandlerWithControllerReset(Collections.singletonList(hello));
-
- List<OFMessage> msgs = getMessagesFromCapture();
- assertEquals(1, msgs.size());
- assertEquals(OFType.FEATURES_REQUEST, msgs.get(0).getType());
- if (ofVersion == OFVersion.OF_10) {
- assertEquals(OFVersion.OF_10, msgs.get(0).getVersion());
- }
- verifyUniqueXids(msgs);
-
- assertEquals(OFChannelHandler.ChannelState.WAIT_FEATURES_REPLY,
- handler.getStateForTesting());
- }
-
- /**
- * Move the channel from scratch to WAIT_CONFIG_REPLY state.
- * Builds on moveToWaitFeaturesReply.
- * adds testing for WAIT_FEATURES_REPLY state.
- */
- @Test
- public void moveToWaitConfigReply() throws Exception {
- moveToWaitFeaturesReply();
-
- resetChannel();
- channel.write(capture(writeCapture));
- expectLastCall().andReturn(null).atLeastOnce();
- replay(channel);
-
- sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(featuresReply));
- List<OFMessage> msgs = getMessagesFromCapture();
- assertEquals(3, msgs.size());
- assertEquals(OFType.SET_CONFIG, msgs.get(0).getType());
- OFSetConfig sc = (OFSetConfig) msgs.get(0);
- assertEquals((short) 0xffff, sc.getMissSendLen());
- assertEquals(OFType.BARRIER_REQUEST, msgs.get(1).getType());
- assertEquals(OFType.GET_CONFIG_REQUEST, msgs.get(2).getType());
- verifyUniqueXids(msgs);
- assertEquals(OFChannelHandler.ChannelState.WAIT_CONFIG_REPLY,
- handler.getStateForTesting());
- }
-
- /**
- * Move the channel from scratch to WAIT_DESCRIPTION_STAT_REPLY state.
- * Builds on moveToWaitConfigReply().
- * adds testing for WAIT_CONFIG_REPLY state.
- */
- @Test
- public void moveToWaitDescriptionStatReply() throws Exception {
- moveToWaitConfigReply();
- resetChannel();
- channel.write(capture(writeCapture));
- expectLastCall().andReturn(null).atLeastOnce();
- replay(channel);
-
- OFGetConfigReply cr = (OFGetConfigReply) buildOFMessage(OFType.GET_CONFIG_REPLY);
-
- sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(cr));
-
- List<OFMessage> msgs = getMessagesFromCapture();
- assertEquals(1, msgs.size());
- assertEquals(OFType.STATS_REQUEST, msgs.get(0).getType());
- OFStatsRequest<?> sr = (OFStatsRequest<?>) msgs.get(0);
- assertEquals(OFStatsType.DESC, sr.getStatsType());
- verifyUniqueXids(msgs);
- assertEquals(OFChannelHandler.ChannelState.WAIT_DESCRIPTION_STAT_REPLY,
- handler.getStateForTesting());
- }
-
-
- private OFStatsReply createDescriptionStatsReply() throws IOException {
- OFStatsReply sr = (OFStatsReply) buildOFMessage(OFType.STATS_REPLY);
- return sr;
- }
-
- /**
- * Move the channel from scratch to WAIT_INITIAL_ROLE state.
- * for a switch that does not have a sub-handshake.
- * Builds on moveToWaitDescriptionStatReply().
- * adds testing for WAIT_DESCRIPTION_STAT_REPLY state.
- *
- */
- @Test
- public void moveToWaitInitialRole()
- throws Exception {
- moveToWaitDescriptionStatReply();
-
- long xid = 2000;
-
- // build the stats reply
- OFStatsReply sr = createDescriptionStatsReply();
-
- resetChannel();
- replay(channel);
-
- setupMessageEvent(Collections.<OFMessage>singletonList(sr));
-
- // mock controller
- reset(controller);
- reset(swImplBase);
-
- expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
- .andReturn(swImplBase).anyTimes();
- expect(controller.getDebugCounter())
- .andReturn(debugCounterService).anyTimes();
- controller.submitRegistryRequest(1000);
- expectLastCall().once();
- replay(controller);
-
- //TODO: With the description stats message you are sending in the test,
- //you will end up with an OFSwitchImplBase object
- //which by default does NOT support the nicira role messages.
- //If you wish to test the case where Nicira role messages are supported,
- //then make a comment here that states that this is different
- //from the default behavior of switchImplbase /or/
- //send the right desc-stats (for example send what is expected from OVS 1.0)
-
- if (ofVersion == OFVersion.OF_10) {
- expect(swImplBase.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
- .andReturn(true).once();
-
- swImplBase.write(capture(writeCapture));
- expectLastCall().anyTimes();
- }
-
- swImplBase.setOFVersion(ofVersion);
- expectLastCall().once();
- swImplBase.setConnected(true);
- expectLastCall().once();
- swImplBase.setChannel(channel);
- expectLastCall().once();
- swImplBase.setDebugCounterService(controller.getDebugCounter());
- expectLastCall().once();
- expect(swImplBase.getStringId())
- .andReturn(null).anyTimes();
- swImplBase.setRole(Role.EQUAL);
- expectLastCall().once();
-
- expect(swImplBase.getNextTransactionId())
- .andReturn((int) xid).anyTimes();
- expect(swImplBase.getId())
- .andReturn(1000L).once();
-
- swImplBase.setFeaturesReply(featuresReply);
- expectLastCall().once();
- swImplBase.setPortDescReply((OFPortDescStatsReply) null);
- replay(swImplBase);
-
- // send the description stats reply
- handler.messageReceived(ctx, messageEvent);
-
- List<OFMessage> msgs = getMessagesFromCapture();
- assertEquals(1, msgs.size());
- assertEquals(OFType.EXPERIMENTER, msgs.get(0).getType());
- verifyNiciraMessage((OFExperimenter) msgs.get(0));
-
- verify(controller);
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
- }
-
- /**
- * Move the channel from scratch to.
- * WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state.
- * Builds on moveToWaitInitialRole().
- */
- @Test
- public void moveToWaitSubHandshake()
- throws Exception {
- moveToWaitInitialRole();
-
- int xid = 2000;
- resetChannel();
- replay(channel);
-
- reset(swImplBase);
- // Set the role
- setupSwitchSendRoleRequestAndVerify(true, xid, Role.SLAVE);
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
- // build the stats reply
- OFStatsReply sr = createDescriptionStatsReply();
- OFMessage rr = getRoleReply(xid, Role.SLAVE);
- setupMessageEvent(Collections.<OFMessage>singletonList(rr));
-
- // mock controller
- reset(controller);
- reset(swImplBase);
-
- expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
- .andReturn(swImplBase).anyTimes();
- expect(controller.getDebugCounter())
- .andReturn(debugCounterService).anyTimes();
-
- replay(controller);
-
- expect(swImplBase.getStringId())
- .andReturn(null).anyTimes();
- swImplBase.setRole(Role.SLAVE);
- expectLastCall().once();
- expect(swImplBase.getNextTransactionId())
- .andReturn(xid).anyTimes();
- swImplBase.startDriverHandshake();
- expectLastCall().once();
-
- //when this flag is false, state machine will move to
- //WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state
- expect(swImplBase.isDriverHandshakeComplete())
- .andReturn(false).once();
-
- replay(swImplBase);
-
- // send the description stats reply
- handler.messageReceived(ctx, messageEvent);
-
- assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE,
- handler.getStateForTesting());
- }
-
- /**
- * Move the channel from scratch to WAIT_INITIAL_ROLE state,
- * then move the channel to EQUAL state based on the switch Role.
- * This test basically test the switch with role support.
- * Builds on moveToWaitInitialRole().
- *
- * In WAIT_INITIAL_ROLE state, when any messages (except ECHO_REQUEST
- * and PORT_STATUS), state machine will transit to MASTER or
- * EQUAL state based on the switch role.
- */
- @Test
- public void moveToSlaveWithHandshakeComplete()
- throws Exception {
-
- moveToWaitInitialRole();
-
- int xid = 2000;
- resetChannel();
- replay(channel);
-
- reset(swImplBase);
- // Set the role
- setupSwitchSendRoleRequestAndVerify(true, xid, Role.SLAVE);
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
- // build the stats reply
- OFStatsReply sr = createDescriptionStatsReply();
- OFMessage rr = getRoleReply(xid, Role.SLAVE);
- setupMessageEvent(Collections.<OFMessage>singletonList(rr));
-
- // mock controller
- reset(controller);
- reset(swImplBase);
-
- expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
- .andReturn(swImplBase).anyTimes();
-
- expect(controller.getDebugCounter())
- .andReturn(debugCounterService).anyTimes();
-
- expect(controller.addActivatedEqualSwitch(1000, swImplBase))
- .andReturn(true).once();
- replay(controller);
-
- expect(swImplBase.getStringId())
- .andReturn(null).anyTimes();
- //consult the role in sw to determine the next state.
- //in this testing case, we are testing that channel handler
- // will move to EQUAL state when switch role is in SLAVE.
- expect(swImplBase.getRole()).andReturn(Role.SLAVE).once();
- swImplBase.setRole(Role.SLAVE);
- expectLastCall().once();
-
- expect(swImplBase.getNextTransactionId())
- .andReturn(xid).anyTimes();
- expect(swImplBase.getId())
- .andReturn(1000L).once();
- swImplBase.startDriverHandshake();
- expectLastCall().once();
-
- //when this flag is true, don't need to move interim state
- //WAIT_SWITCH_DRIVER_SUB_HANDSHAKE. channel handler will
- //move to corresponding state after consulting the role in sw
- //This is essentially the same test as the one above,
- //except for this line
- expect(swImplBase.isDriverHandshakeComplete())
- .andReturn(true).once();
-
- replay(swImplBase);
-
- // send the description stats reply
- handler.messageReceived(ctx, messageEvent);
-
- assertEquals(OFChannelHandler.ChannelState.EQUAL,
- handler.getStateForTesting());
- }
-
- /**
- * Move the channel from scratch to WAIT_INITIAL_ROLE state,
- * then to MASTERL state based on the switch Role.
- * This test basically test the switch with role support.
- * Builds on moveToWaitInitialRole().
- *
- * In WAIT_INITIAL_ROLE state, when any messages (except ECHO_REQUEST
- * and PORT_STATUS), state machine will transit to MASTER or
- * EQUAL state based on the switch role.
- */
- @Test
- public void moveToMasterWithHandshakeComplete()
- throws Exception {
-
- moveToWaitInitialRole();
-
- int xid = 2000;
- resetChannel();
- replay(channel);
-
- reset(swImplBase);
- // Set the role
- setupSwitchSendRoleRequestAndVerify(true, xid, Role.MASTER);
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
- // build the stats reply
- OFStatsReply sr = createDescriptionStatsReply();
- OFMessage rr = getRoleReply(xid, Role.MASTER);
- setupMessageEvent(Collections.<OFMessage>singletonList(rr));
-
- // mock controller
- reset(controller);
- reset(swImplBase);
-
- expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
- .andReturn(swImplBase).anyTimes();
-
- expect(controller.getDebugCounter())
- .andReturn(debugCounterService).anyTimes();
-
- expect(controller.addActivatedMasterSwitch(1000, swImplBase))
- .andReturn(true).once();
- replay(controller);
-
- expect(swImplBase.getStringId())
- .andReturn(null).anyTimes();
- expect(swImplBase.getRole()).andReturn(Role.MASTER).once();
- swImplBase.setRole(Role.MASTER);
- expectLastCall().once();
-
- expect(swImplBase.getNextTransactionId())
- .andReturn(xid).anyTimes();
- expect(swImplBase.getId())
- .andReturn(1000L).once();
- swImplBase.startDriverHandshake();
- expectLastCall().once();
- expect(swImplBase.isDriverHandshakeComplete())
- .andReturn(true).once();
-
- replay(swImplBase);
-
-
- // send the description stats reply
- handler.messageReceived(ctx, messageEvent);
-
- assertEquals(OFChannelHandler.ChannelState.MASTER,
- handler.getStateForTesting());
- }
-
- /**
- * Move the channel from scratch to
- * WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state.
- * Builds on moveToWaitSubHandshake().
- */
- @Test
- public void moveToEqualViaWaitSubHandshake()
- throws Exception {
- moveToWaitSubHandshake();
-
- long xid = 2000;
- resetChannel();
- replay(channel);
-
- // build the stats reply
- OFStatsReply sr = createDescriptionStatsReply();
-
- setupMessageEvent(Collections.<OFMessage>singletonList(sr));
-
- // mock controller
- reset(controller);
- reset(swImplBase);
-
- expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
- .andReturn(swImplBase).anyTimes();
- expect(controller.getDebugCounter())
- .andReturn(debugCounterService).anyTimes();
-
- expect(controller.addActivatedEqualSwitch(1000, swImplBase))
- .andReturn(true).once();
- replay(controller);
-
- expect(swImplBase.getStringId())
- .andReturn(null).anyTimes();
- expect(swImplBase.getRole()).andReturn(Role.SLAVE).once();
- expect(swImplBase.getNextTransactionId())
- .andReturn((int) xid).anyTimes();
- expect(swImplBase.getId())
- .andReturn(1000L).once();
-
- swImplBase.processDriverHandshakeMessage(sr);
- expectLastCall().once();
- expect(swImplBase.isDriverHandshakeComplete())
- .andReturn(true).once();
-
- replay(swImplBase);
-
- // send the description stats reply
- handler.messageReceived(ctx, messageEvent);
-
- assertEquals(OFChannelHandler.ChannelState.EQUAL,
- handler.getStateForTesting());
- }
-
- /**
- * Move the channel from scratch to
- * WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state.
- * Builds on moveToWaitSubHandshake().
- */
- @Test
- public void moveToMasterViaWaitSubHandshake()
- throws Exception {
- moveToWaitSubHandshake();
-
- long xid = 2000;
- resetChannel();
- replay(channel);
-
- // In this state, any messages except echo request, port status and
- // error go to the switch sub driver handshake. Once the switch reports
- // that its sub driver handshake is complete (#isDriverHandshakeComplete
- // return true) then the channel handle consults the switch role and
- // moves the state machine to the appropriate state (MASTER or EQUALS).
- // In this test we expect the state machine to end up in MASTER state.
- OFStatsReply sr = createDescriptionStatsReply();
-
- setupMessageEvent(Collections.<OFMessage>singletonList(sr));
-
- // mock controller
- reset(controller);
- reset(swImplBase);
-
- expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
- .andReturn(swImplBase).anyTimes();
-
- expect(controller.getDebugCounter())
- .andReturn(debugCounterService).anyTimes();
- expect(controller.addActivatedMasterSwitch(1000, swImplBase))
- .andReturn(true).once();
- replay(controller);
-
- expect(swImplBase.getStringId())
- .andReturn(null).anyTimes();
- expect(swImplBase.getRole()).andReturn(Role.MASTER).once();
- expect(swImplBase.getNextTransactionId())
- .andReturn((int) xid).anyTimes();
- expect(swImplBase.getId())
- .andReturn(1000L).once();
-
- swImplBase.processDriverHandshakeMessage(sr);
- expectLastCall().once();
- expect(swImplBase.isDriverHandshakeComplete())
- .andReturn(true).once();
-
- replay(swImplBase);
-
- // send the description stats reply
- handler.messageReceived(ctx, messageEvent);
- verify(controller);
- assertEquals(OFChannelHandler.ChannelState.MASTER,
- handler.getStateForTesting());
- }
-
- /**
- * Test the behavior in WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state.
- * ECHO_REQUEST message received case.
- */
- @Test
- public void testWaitSwitchDriverSubhandshake() throws Exception {
- moveToWaitSubHandshake();
-
- long xid = 2000;
- resetChannel();
- channel.write(capture(writeCapture));
- expectLastCall().andReturn(null).atLeastOnce();
- replay(channel);
-
- OFMessage er = buildOFMessage(OFType.ECHO_REQUEST);
-
- setupMessageEvent(Collections.<OFMessage>singletonList(er));
-
- // mock controller
- reset(controller);
- reset(swImplBase);
-
- expect(controller.getOFMessageFactory10()).andReturn(factory10);
- expect(controller.getDebugCounter())
- .andReturn(debugCounterService).anyTimes();
-
- replay(controller);
-
- expect(swImplBase.getStringId())
- .andReturn(null).anyTimes();
- expect(swImplBase.getNextTransactionId())
- .andReturn((int) xid).anyTimes();
-
- replay(swImplBase);
-
- handler.messageReceived(ctx, messageEvent);
-
- List<OFMessage> msgs = getMessagesFromCapture();
- assertEquals(1, msgs.size());
- assertEquals(OFType.ECHO_REPLY, msgs.get(0).getType());
- verifyUniqueXids(msgs);
- assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE,
- handler.getStateForTesting());
- }
-
- /**
- * Helper.
- * Verify that the given OFMessage is a correct Nicira RoleRequest message.
- */
- private void verifyNiciraMessage(OFExperimenter ofMessage) {
-
- int vendor = (int) ofMessage.getExperimenter();
- assertEquals(vendor, 0x2320); // magic number representing nicira
- }
-
- /**
- * Setup the mock switch and write capture for a role request, set the
- * role and verify mocks.
- * @param supportsNxRole whether the switch supports role request messages
- * to setup the attribute. This must be null (don't yet know if roles
- * supported: send to check) or true.
- * @param xid The xid to use in the role request
- * @param role The role to send
- * @throws IOException
- */
- private void setupSwitchSendRoleRequestAndVerify(Boolean supportsNxRole,
- int xid,
- Role role) throws IOException {
-
- RoleRecvStatus expectation = RoleRecvStatus.MATCHED_SET_ROLE;
-
- expect(swImplBase.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
- .andReturn(supportsNxRole).atLeastOnce();
-
- if (supportsNxRole != null && supportsNxRole) {
- expect(swImplBase.getNextTransactionId()).andReturn(xid).once();
- swImplBase.write(capture(writeCapture));
- expectLastCall().anyTimes();
- }
- replay(swImplBase);
-
- handler.sendRoleRequest(role, expectation);
-
- if (supportsNxRole != null && supportsNxRole) {
- List<OFMessage> msgs = getMessagesFromCapture();
- assertEquals(1, msgs.size());
- verifyNiciraMessage((OFExperimenter) msgs.get(0));
- }
- }
-
- /**
- * Setup the mock switch for a role change request where the switch
- * does not support roles.
- *
- * Needs to verify and reset the controller since we need to set
- * an expectation
- */
- private void setupSwitchRoleChangeUnsupported(int xid,
- Role role) {
- boolean supportsNxRole = false;
- RoleRecvStatus expectation = RoleRecvStatus.NO_REPLY;
- reset(swImplBase);
- expect(swImplBase.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
- .andReturn(supportsNxRole).atLeastOnce();
- // TODO: hmmm. While it's not incorrect that we set the attribute
- // again it looks odd. Maybe change
- swImplBase.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, supportsNxRole);
- expectLastCall().anyTimes();
-
- replay(swImplBase);
-
- handler.sendRoleRequest(role, expectation);
-
- verify(swImplBase);
- }
-
- /*
- * Return a Nicira RoleReply message for the given role.
- */
- private OFMessage getRoleReply(long xid, Role role) {
-
- OFNiciraControllerRole nr = null;
-
- switch(role) {
- case MASTER:
- nr = OFNiciraControllerRole.ROLE_MASTER;
- break;
- case EQUAL:
- nr = OFNiciraControllerRole.ROLE_SLAVE;
- break;
- case SLAVE:
- nr = OFNiciraControllerRole.ROLE_SLAVE;
- break;
- default: //handled below
- }
- OFMessage m = factory10.buildNiciraControllerRoleReply()
- .setRole(nr)
- .setXid(xid)
- .build();
- return m;
- }
-
- /**
- * Move the channel from scratch to MASTER state.
- * Builds on moveToWaitInitialRole().
- * adds testing for WAIT_INITAL_ROLE state.
- *
- * This method tests the case that the switch does NOT support roles.
- * In ONOS if the switch-driver says that nicira-role messages are not
- * supported, then ONOS does NOT send role-request messages
- * (see handleUnsentRoleMessage())
- */
- @Test
- public void testInitialMoveToMasterNoRole() throws Exception {
- int xid = 43;
- // first, move us to WAIT_INITIAL_ROLE_STATE
-
- moveToWaitInitialRole();
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
- OFStatsReply sr = createDescriptionStatsReply();
-
- reset(controller);
- reset(swImplBase);
-
- expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
- .andReturn(swImplBase).anyTimes();
-
- expect(controller.getDebugCounter())
- .andReturn(debugCounterService).anyTimes();
-
- expect(controller.addActivatedMasterSwitch(1000, swImplBase))
- .andReturn(true).once();
- replay(controller);
-
- reset(swImplBase);
- swImplBase.setRole(Role.MASTER);
- expectLastCall().once();
- swImplBase.startDriverHandshake();
- expectLastCall().once();
- expect(swImplBase.isDriverHandshakeComplete())
- .andReturn(true).once();
- expect(swImplBase.getStringId())
- .andReturn(null).anyTimes();
- expect(swImplBase.getRole()).andReturn(Role.MASTER).once();
-
- expect(swImplBase.getId())
- .andReturn(1000L).once();
- // Set the role
- setupSwitchSendRoleRequestAndVerify(false, xid, Role.MASTER);
-
- assertEquals(OFChannelHandler.ChannelState.MASTER,
- handler.getStateForTesting());
- }
-
- /**
- * Move the channel from scratch to WAIT_INITIAL_ROLE state.
- * Builds on moveToWaitInitialRole().
- * adds testing for WAIT_INITAL_ROLE state
- *
- * We let the initial role request time out. Role support should be
- * disabled but the switch should be activated.
- */
- /* TBD
- @Test
- public void testInitialMoveToMasterTimeout() throws Exception {
- int timeout = 50;
- handler.useRoleChangerWithOtherTimeoutForTesting(timeout);
- int xid = 4343;
-
- // first, move us to WAIT_INITIAL_ROLE_STATE
-
- moveToWaitInitialRole();
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
- // prepare mocks and inject the role reply message
- reset(swImplBase);
- // Set the role
- swImplBase.setRole(Role.MASTER);
- expectLastCall().once();
- swImplBase.startDriverHandshake();
- expectLastCall().once();
- expect(swImplBase.isDriverHandshakeComplete())
- .andReturn(false).once();
- if (ofVersion == OFVersion.OF_10) {
- expect(swImplBase.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
- .andReturn(true).once();
-
- swImplBase.write(capture(writeCapture),
- EasyMock.<FloodlightContext>anyObject());
- expectLastCall().anyTimes();
- }
- expect(swImplBase.getNextTransactionId()).andReturn(xid).once();
-
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
- // Set the role
- setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER);
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
- OFMessage m = buildOFMessage(OFType.ECHO_REPLY);
-
- setupMessageEvent(Collections.<OFMessage>singletonList(m));
-
- Thread.sleep(timeout+5);
-
- verify(controller);
- reset(controller);
-
- expect(controller.addActivatedMasterSwitch(1000, swImplBase))
- .andReturn(true).once();
- controller.flushAll();
- expectLastCall().once();
-
- replay(controller);
-
- handler.messageReceived(ctx, messageEvent);
-
- assertEquals(OFChannelHandler.ChannelState.MASTER,
- handler.getStateForTesting());
-
- }
-
- */
- /**
- * Move the channel from scratch to SLAVE state.
- * Builds on doMoveToWaitInitialRole().
- * adds testing for WAIT_INITAL_ROLE state
- *
- * This method tests the case that the switch does NOT support roles.
- * The channel handler still needs to send the initial request to find
- * out that whether the switch supports roles.
- *
- */
- @Test
- public void testInitialMoveToSlaveNoRole() throws Exception {
- int xid = 44;
- // first, move us to WAIT_INITIAL_ROLE_STATE
- moveToWaitInitialRole();
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
- reset(swImplBase);
- // Set the role
- setupSwitchSendRoleRequestAndVerify(false, xid, Role.SLAVE);
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
- }
-
- /**
- * Move the channel from scratch to SLAVE state.
- * Builds on doMoveToWaitInitialRole().
- * adds testing for WAIT_INITAL_ROLE state
- *
- * We let the initial role request time out. The switch should be
- * disconnected
- */
- /* TBD
- @Test
- public void testInitialMoveToSlaveTimeout() throws Exception {
- int timeout = 50;
- handler.useRoleChangerWithOtherTimeoutForTesting(timeout);
- int xid = 4444;
-
- // first, move us to WAIT_INITIAL_ROLE_STATE
- moveToWaitInitialRole();
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
- // Set the role
- setupSwitchSendRoleRequestAndVerify(null, xid, Role.SLAVE);
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
- // prepare mocks and inject the role reply message
- reset(sw);
- sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
- expectLastCall().once();
- sw.setRole(Role.SLAVE);
- expectLastCall().once();
- sw.disconnectSwitch(); // Make sure we disconnect
- expectLastCall().once();
- replay(sw);
-
- OFMessage m = buildOFMessage(OFType.ECHO_REPLY);
-
- Thread.sleep(timeout+5);
-
- sendMessageToHandlerWithControllerReset(Collections.singletonList(m));
- }
-
- */
- /**
- * Move channel from scratch to WAIT_INITIAL_STATE, then MASTER,
- * then SLAVE for cases where the switch does not support roles.
- * I.e., the final SLAVE transition should disconnect the switch.
- */
- @Test
- public void testNoRoleInitialToMasterToSlave() throws Exception {
- int xid = 46;
- reset(swImplBase);
- replay(swImplBase);
-
- reset(controller);
- replay(controller);
-
- // First, lets move the state to MASTER without role support
- testInitialMoveToMasterNoRole();
- assertEquals(OFChannelHandler.ChannelState.MASTER,
- handler.getStateForTesting());
-
- // try to set master role again. should be a no-op
- setupSwitchRoleChangeUnsupported(xid, Role.MASTER);
-
- assertEquals(OFChannelHandler.ChannelState.MASTER,
- handler.getStateForTesting());
-
- setupSwitchRoleChangeUnsupported(xid, Role.SLAVE);
- //switch does not support role message. there is no role set
- assertEquals(OFChannelHandler.ChannelState.MASTER,
- handler.getStateForTesting());
-
- }
-
- /**
- * Move the channel to MASTER state.
- * Expects that the channel is in MASTER or SLAVE state.
- *
- */
- public void changeRoleToMasterWithRequest() throws Exception {
- int xid = 4242;
-
- assertTrue("This method can only be called when handler is in " +
- "MASTER or SLAVE role", handler.isHandshakeComplete());
-
- reset(swImplBase);
- reset(controller);
- // Set the role
- setupSwitchSendRoleRequestAndVerify(true, xid, Role.MASTER);
-
- // prepare mocks and inject the role reply message
-
- reset(controller);
- expect(controller.addActivatedMasterSwitch(1000, swImplBase))
- .andReturn(true).once();
- OFMessage reply = getRoleReply(xid, Role.MASTER);
-
- // sendMessageToHandler will verify and rest controller mock
-
- OFStatsReply sr = createDescriptionStatsReply();
- setupMessageEvent(Collections.<OFMessage>singletonList(reply));
-
- // mock controller
- reset(controller);
- reset(swImplBase);
-
- expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
- .andReturn(swImplBase).anyTimes();
-
- expect(controller.getDebugCounter())
- .andReturn(debugCounterService).anyTimes();
- controller.transitionToMasterSwitch(1000);
- expectLastCall().once();
-
- replay(controller);
-
- expect(swImplBase.getStringId())
- .andReturn(null).anyTimes();
- expect(swImplBase.getRole()).andReturn(Role.EQUAL).atLeastOnce();
- expect(swImplBase.getNextTransactionId())
- .andReturn(xid).anyTimes();
- expect(swImplBase.getId())
- .andReturn(1000L).once();
-
- swImplBase.setRole(Role.MASTER);
- expectLastCall().once();
- replay(swImplBase);
-
- // send the description stats reply
- handler.messageReceived(ctx, messageEvent);
-
- assertEquals(OFChannelHandler.ChannelState.MASTER,
- handler.getStateForTesting());
- }
-
- /**
- * Move the channel to SLAVE state.
- * Expects that the channel is in MASTER or SLAVE state.
- *
- */
- public void changeRoleToSlaveWithRequest() throws Exception {
- int xid = 2323;
-
- assertTrue("This method can only be called when handler is in " +
- "MASTER or SLAVE role", handler.isHandshakeComplete());
-
- // Set the role
- reset(controller);
- reset(swImplBase);
-
- swImplBase.write(capture(writeCapture));
- expectLastCall().anyTimes();
-
- expect(swImplBase.getNextTransactionId())
- .andReturn(xid).anyTimes();
-
-
- if (ofVersion == OFVersion.OF_10) {
- expect(swImplBase.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
- .andReturn(true).once();
-
- swImplBase.write(capture(writeCapture));
- expectLastCall().anyTimes();
- }
- replay(swImplBase);
-
- handler.sendRoleRequest(Role.SLAVE, RoleRecvStatus.MATCHED_SET_ROLE);
-
- List<OFMessage> msgs = getMessagesFromCapture();
- assertEquals(1, msgs.size());
- verifyNiciraMessage((OFExperimenter) msgs.get(0));
-
-
- OFMessage reply = getRoleReply(xid, Role.SLAVE);
- OFStatsReply sr = createDescriptionStatsReply();
- setupMessageEvent(Collections.<OFMessage>singletonList(reply));
-
- // mock controller
- reset(controller);
- reset(swImplBase);
-
- controller.transitionToEqualSwitch(1000);
- expectLastCall().once();
- expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
- .andReturn(swImplBase).anyTimes();
-
- expect(controller.getDebugCounter())
- .andReturn(debugCounterService).anyTimes();
-
- replay(controller);
-
- expect(swImplBase.getStringId())
- .andReturn(null).anyTimes();
- expect(swImplBase.getRole()).andReturn(Role.MASTER).atLeastOnce();
- expect(swImplBase.getNextTransactionId())
- .andReturn(xid).anyTimes();
-
- // prepare mocks and inject the role reply message
- swImplBase.setRole(Role.SLAVE);
- expectLastCall().once();
- expect(swImplBase.getId())
- .andReturn(1000L).once();
- replay(swImplBase);
-
- handler.messageReceived(ctx, messageEvent);
-
- assertEquals(OFChannelHandler.ChannelState.EQUAL,
- handler.getStateForTesting());
- }
-
- @Test
- public void testMultiRoleChange1() throws Exception {
- moveToMasterWithHandshakeComplete();
- changeRoleToMasterWithRequest();
- changeRoleToSlaveWithRequest();
- changeRoleToSlaveWithRequest();
- changeRoleToMasterWithRequest();
- changeRoleToSlaveWithRequest();
- }
-
- @Test
- public void testMultiRoleChange2() throws Exception {
- moveToSlaveWithHandshakeComplete();
- changeRoleToMasterWithRequest();
- changeRoleToSlaveWithRequest();
- changeRoleToSlaveWithRequest();
- changeRoleToMasterWithRequest();
- changeRoleToSlaveWithRequest();
- }
-
- /**
- * Start from scratch and reply with an unexpected error to the role
- * change request.
- * Builds on doMoveToWaitInitialRole()
- * adds testing for WAIT_INITAL_ROLE state
- */
- /* TBD
- @Test
- public void testInitialRoleChangeOtherError() throws Exception {
- int xid = 4343;
- // first, move us to WAIT_INITIAL_ROLE_STATE
- moveToWaitInitialRole();
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
- reset(swImplBase);
- // Set the role
- setupSwitchSendRoleRequestAndVerify(true, xid, Role.MASTER);
- assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
- handler.getStateForTesting());
-
-
- // FIXME: shouldn't use ordinal(), but OFError is broken
-
- OFMessage err = factory.errorMsgs().buildBadActionErrorMsg()
- .setCode(OFBadActionCode.BAD_LEN)
- .setXid(2000)
- .build();
- verify(swImplBase);
- reset(swImplBase);
- replay(swImplBase);
- sendMessageToHandlerWithControllerReset(Collections.singletonList(err));
-
- verifyExceptionCaptured(SwitchStateException.class);
- }
- */
- /**
- * Test dispatch of messages while in MASTER role.
- */
- @Test
- public void testMessageDispatchMaster() throws Exception {
-
- moveToMasterWithHandshakeComplete();
-
- // Send packet in. expect dispatch
- OFPacketIn pi = (OFPacketIn)
- buildOFMessage(OFType.PACKET_IN);
- setupMessageEvent(Collections.<OFMessage>singletonList(pi));
-
- reset(swImplBase);
- swImplBase.handleMessage(pi);
- expectLastCall().once();
- replay(swImplBase);
- // send the description stats reply
- handler.messageReceived(ctx, messageEvent);
-
- assertEquals(OFChannelHandler.ChannelState.MASTER,
- handler.getStateForTesting());
-
- verify(controller);
- // TODO: many more to go
- }
-
- /**
- * Test port status message handling while MASTER.
- *
- */
- /* Patrick: TBD
- @Test
- public void testPortStatusMessageMaster() throws Exception {
- long dpid = featuresReply.getDatapathId().getLong();
- testInitialMoveToMasterWithRole();
- List<OFPortDesc> ports = new ArrayList<OFPortDesc>();
- // A dummy port.
- OFPortDesc p = factory.buildPortDesc()
- .setName("Eth1")
- .setPortNo(OFPort.ofInt(1))
- .build();
- ports.add(p);
-
- p.setName("Port1");
- p.setPortNumber((short)1);
-
- OFPortStatus ps = (OFPortStatus)buildOFMessage(OFType.PORT_STATUS);
- ps.setDesc(p);
-
- // The events we expect sw.handlePortStatus to return
- // We'll just use the same list for all valid OFPortReasons and add
- // arbitrary events for arbitrary ports that are not necessarily
- // related to the port status message. Our goal
- // here is not to return the correct set of events but the make sure
- // that a) sw.handlePortStatus is called
- // b) the list of events sw.handlePortStatus returns is sent
- // as IOFSwitchListener notifications.
- OrderedCollection<PortChangeEvent> events =
- new LinkedHashSetWrapper<PortChangeEvent>();
- ImmutablePort p1 = ImmutablePort.create("eth1", (short)1);
- ImmutablePort p2 = ImmutablePort.create("eth2", (short)2);
- ImmutablePort p3 = ImmutablePort.create("eth3", (short)3);
- ImmutablePort p4 = ImmutablePort.create("eth4", (short)4);
- ImmutablePort p5 = ImmutablePort.create("eth5", (short)5);
- events.add(new PortChangeEvent(p1, PortChangeType.ADD));
- events.add(new PortChangeEvent(p2, PortChangeType.DELETE));
- events.add(new PortChangeEvent(p3, PortChangeType.UP));
- events.add(new PortChangeEvent(p4, PortChangeType.DOWN));
- events.add(new PortChangeEvent(p5, PortChangeType.OTHER_UPDATE));
-
-
- for (OFPortReason reason: OFPortReason.values()) {
- ps.setReason(reason.getReasonCode());
-
- reset(sw);
- expect(sw.getId()).andReturn(dpid).anyTimes();
-
- expect(sw.processOFPortStatus(ps)).andReturn(events).once();
- replay(sw);
-
- reset(controller);
- controller.notifyPortChanged(sw, p1, PortChangeType.ADD);
- controller.notifyPortChanged(sw, p2, PortChangeType.DELETE);
- controller.notifyPortChanged(sw, p3, PortChangeType.UP);
- controller.notifyPortChanged(sw, p4, PortChangeType.DOWN);
- controller.notifyPortChanged(sw, p5, PortChangeType.OTHER_UPDATE);
- sendMessageToHandlerNoControllerReset(
- Collections.<OFMessage>singletonList(ps));
- verify(sw);
- verify(controller);
- }
- }
-
- */
- /**
- * Build an OF message.
- * @throws IOException
- */
- private OFMessage buildOFMessage(OFType t) throws IOException {
- OFMessage m = null;
- switch (t) {
-
- case HELLO:
- // The OF protocol requires us to start things off by sending the highest
- // version of the protocol supported.
-
- // bitmap represents OF1.0 (ofp_version=0x01) and OF1.3 (ofp_version=0x04)
- // see Sec. 7.5.1 of the OF1.3.4 spec
- if (ofVersion == OFVersion.OF_13) {
- U32 bitmap = U32.ofRaw(0x00000012);
- OFHelloElem hem = factory13.buildHelloElemVersionbitmap()
- .setBitmaps(Collections.singletonList(bitmap))
- .build();
- m = factory13.buildHello()
- .setXid(2000)
- .setElements(Collections.singletonList(hem))
- .build();
- } else {
- m = factory10.buildHello()
- .setXid(2000)
- .build();
- }
- break;
- case FEATURES_REQUEST:
- m = factory.buildFeaturesRequest()
- .setXid(2000)
- .build();
- break;
- case FEATURES_REPLY:
-
- m = factory.buildFeaturesReply()
- .setDatapathId(DatapathId.of(1000L))
- .setXid(2000)
- .build();
- break;
- case SET_CONFIG:
- m = factory.buildSetConfig()
- .setMissSendLen((short) 0xffff)
- .setXid(2000)
- .build();
- break;
- case BARRIER_REQUEST:
- m = factory.buildBarrierRequest()
- .setXid(2000)
- .build();
- break;
- case GET_CONFIG_REQUEST:
- m = factory.buildGetConfigRequest()
- .setXid(2000)
- .build();
- break;
- case GET_CONFIG_REPLY:
- m = factory.buildGetConfigReply()
- .setMissSendLen((short) 0xffff)
- .setXid(2000)
- .build();
- break;
- case STATS_REQUEST:
- break;
- case STATS_REPLY:
- m = factory.buildDescStatsReply()
- .setDpDesc("Datapath Description")
- .setHwDesc("Hardware Secription")
- .setMfrDesc("Manufacturer Desctiption")
- .setSerialNum("Serial Number")
- .setSwDesc("Software Desription")
- .build();
- break;
- case ECHO_REQUEST:
- m = factory.buildEchoRequest()
- .setXid(2000)
- .build();
- break;
- case FLOW_REMOVED:
- break;
-
- case PACKET_IN:
- m = factory.buildPacketIn()
- .setReason(OFPacketInReason.NO_MATCH)
- .setTotalLen(1500)
- .setXid(2000)
- .build();
- break;
- case PORT_STATUS:
- m = factory.buildPortStatus()
- .setXid(2000)
- .build();
- break;
-
- default:
- m = factory.buildFeaturesRequest()
- .setXid(2000)
- .build();
- break;
- }
-
- return (m);
- }
-}