alshabib

refactored OF switch into driver and frontend

Showing 24 changed files with 788 additions and 378 deletions
package org.onlab.onos.of.controller;
import java.util.List;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
/**
* Abstract model of an OpenFlow Switch.
*
* Represents to provider facing side of a switch.
*/
public interface OpenFlowSwitch {
/**
* Writes the message to this switch.
* Writes the message to the driver.
*
* @param msg the message to write
*/
public void sendMsg(OFMessage msg);
/**
* Writes to the OFMessage list to the driver.
*
* @param msgs the messages to be written
*/
public void sendMsg(List<OFMessage> msgs);
/**
* Handle a message from the switch.
* @param fromSwitch the message to handle
*/
public void handleMessage(OFMessage fromSwitch);
/**
* Sets the role for this switch.
* @param role the role to set.
*/
public void setRole(RoleState role);
/**
* Fetch the role for this switch.
* @return the role.
*/
public RoleState getRole();
/**
* Fetches the ports of this switch.
* @return unmodifiable list of the ports.
*/
public List<OFPortDesc> getPorts();
/**
* Provides the factory for this OF version.
* @return OF version specific factory.
*/
public OFFactory factory();
/**
* Gets a string version of the ID for this switch.
*
* @return string version of the ID
*/
public String getStringId();
/**
* Gets the datapathId of the switch.
*
* @return the switch dpid in long format
*/
public long getId();
/**
* Disconnects the switch by closing the TCP connection. Results in a call
* to the channel handler's channelDisconnected method for cleanup
*/
public void disconnectSwitch();
}
......
......@@ -21,3 +21,5 @@ public enum RoleState {
}
......
......@@ -15,7 +15,7 @@
* under the License.
**/
package org.onlab.onos.of.controller.impl.internal;
package org.onlab.onos.of.controller.driver;
import java.io.IOException;
import java.util.Collections;
......@@ -24,11 +24,7 @@ import java.util.concurrent.atomic.AtomicInteger;
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.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFErrorMsg;
import org.projectfloodlight.openflow.protocol.OFExperimenter;
......@@ -43,19 +39,22 @@ import org.projectfloodlight.openflow.protocol.OFVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
/**
* An abstract representation of an OpenFlow switch. Can be extended by others
* to serve as a base for their vendor specific representation of a switch.
*/
public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver {
private static Logger log =
LoggerFactory.getLogger(AbstractOpenFlowSwitch.class);
protected Channel channel;
protected boolean startDriverHandshakeCalled = false;
private boolean connected;
private Dpid dpid;
private OpenFlowSwitchAgent agent;
private AtomicInteger xidCounter = new AtomicInteger(0);
protected boolean startDriverHandshakeCalled = false;
private final Dpid dpid;
private OpenFlowAgent agent;
private final AtomicInteger xidCounter = new AtomicInteger(0);
private OFVersion ofVersion;
......@@ -63,12 +62,17 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
protected boolean tableFull;
private final RoleManager roleMan = new RoleManager(this);
private RoleHandler roleMan;
protected RoleState role;
protected OFFeaturesReply features;
protected OFDescStatsReply desc;
/**
* Given a dpid build this switch.
* @param dp the dpid
*/
protected AbstractOpenFlowSwitch(Dpid dp) {
this.dpid = dp;
}
......@@ -77,59 +81,38 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
// 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
*/
@Override
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 sendMsg(OFMessage m);
@Override
public final void sendMsg(OFMessage m) {
this.write(m);
}
/**
* Writes to the OFMessage list to the output stream.
*
* @param msgs the messages to be written
*/
public void write(List<OFMessage> msgs) {
this.channel.write(msgs);
@Override
public final void sendMsg(List<OFMessage> msgs) {
this.write(msgs);
}
@Override
public abstract void write(OFMessage msg);
/**
* Checks if the switch is still connected.
* Only call while holding processMessageLock
*
* @return whether the switch is still disconnected
*/
@Override
public abstract void write(List<OFMessage> msgs);
@Override
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) {
@Override
public 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
*/
@Override
public final void setChannel(Channel channel) {
this.channel = channel;
};
......@@ -138,41 +121,32 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
// Switch features related
//************************
/**
* Gets the datapathId of the switch.
*
* @return the switch buffers
*/
@Override
public final long getId() {
return this.dpid.value();
};
/**
* Gets a string version of the ID for this switch.
*
* @return string version of the ID
*/
@Override
public final String getStringId() {
return this.dpid.toString();
}
@Override
public final void setOFVersion(OFVersion ofV) {
this.ofVersion = ofV;
}
void setTableFull(boolean full) {
@Override
public void setTableFull(boolean full) {
this.tableFull = full;
}
@Override
public void setFeaturesReply(OFFeaturesReply featuresReply) {
this.features = featuresReply;
}
/**
* Let peoeple know if you support Nicira style role requests.
*
* @return support Nicira roles or not.
*/
@Override
public abstract Boolean supportNxRole();
//************************
......@@ -183,65 +157,80 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
*
* @param m the actual message
*/
@Override
public final void handleMessage(OFMessage m) {
this.agent.processMessage(m);
}
@Override
public RoleState getRole() {
return role;
};
final boolean addConnectedSwitch() {
return this.agent.addConnectedSwitch(this.getId(), this);
@Override
public final boolean connectSwitch() {
return this.agent.addConnectedSwitch(dpid, this);
}
final boolean addActivatedMasterSwitch() {
return this.agent.addActivatedMasterSwitch(this.getId(), this);
@Override
public final boolean activateMasterSwitch() {
return this.agent.addActivatedMasterSwitch(dpid, this);
}
final boolean addActivatedEqualSwitch() {
return this.agent.addActivatedEqualSwitch(this.getId(), this);
@Override
public final boolean activateEqualSwitch() {
return this.agent.addActivatedEqualSwitch(dpid, this);
}
final void transitionToEqualSwitch() {
this.agent.transitionToEqualSwitch(this.getId());
@Override
public final void transitionToEqualSwitch() {
this.agent.transitionToEqualSwitch(dpid);
}
final void transitionToMasterSwitch() {
this.agent.transitionToMasterSwitch(this.getId());
@Override
public final void transitionToMasterSwitch() {
this.agent.transitionToMasterSwitch(dpid);
}
final void removeConnectedSwitch() {
this.agent.removeConnectedSwitch(this.getId());
@Override
public final void removeConnectedSwitch() {
this.agent.removeConnectedSwitch(dpid);
}
protected OFFactory factory() {
@Override
public OFFactory factory() {
return OFFactories.getFactory(ofVersion);
}
@Override
public void setPortDescReply(OFPortDescStatsReply portDescReply) {
this.ports = portDescReply;
}
@Override
public abstract void startDriverHandshake();
@Override
public abstract boolean isDriverHandshakeComplete();
@Override
public abstract void processDriverHandshakeMessage(OFMessage m);
@Override
public void setRole(RoleState role) {
try {
if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
this.role = role;
}
} catch (IOException e) {
log.error("Unable to write to switch {}.", this.dpid);
log.error("Unable to write to switch {}.", this.dpid);
}
}
// Role Handling
void handleRole(OFMessage m) throws SwitchStateException {
@Override
public void handleRole(OFMessage m) throws SwitchStateException {
RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
......@@ -254,7 +243,8 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
}
}
void handleNiciraRole(OFMessage m) throws SwitchStateException {
@Override
public void handleNiciraRole(OFMessage m) throws SwitchStateException {
RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
if (r == null) {
// The message wasn't really a Nicira role reply. We just
......@@ -274,7 +264,8 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
}
}
boolean handleRoleError(OFErrorMsg error) {
@Override
public boolean handleRoleError(OFErrorMsg error) {
try {
return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
} catch (SwitchStateException e) {
......@@ -283,25 +274,39 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
return true;
}
void reassertRole() {
@Override
public void reassertRole() {
if (this.getRole() == RoleState.MASTER) {
this.setRole(RoleState.MASTER);
}
}
void setAgent(OpenFlowSwitchAgent ag) {
this.agent = ag;
@Override
public final void setAgent(OpenFlowAgent ag) {
if (this.agent == null) {
this.agent = ag;
}
}
@Override
public final void setRoleHandler(RoleHandler roleHandler) {
if (this.roleMan == null) {
this.roleMan = roleHandler;
}
}
public void setSwitchDescription(OFDescStatsReply desc) {
// TODO Auto-generated method stub
@Override
public void setSwitchDescription(OFDescStatsReply d) {
this.desc = d;
}
protected int getNextTransactionId() {
@Override
public int getNextTransactionId() {
return this.xidCounter.getAndIncrement();
}
protected List<OFPortDesc> getPorts() {
@Override
public List<OFPortDesc> getPorts() {
return Collections.unmodifiableList(ports.getEntries());
}
......
package org.onlab.onos.of.controller.driver;
import org.onlab.onos.of.controller.Dpid;
import org.onlab.onos.of.controller.OpenFlowSwitch;
import org.projectfloodlight.openflow.protocol.OFMessage;
/**
* Responsible for keeping track of the current set of switches
* connected to the system. As well as whether they are in Master
* role or not.
*
*/
public interface OpenFlowAgent {
/**
* Add a switch that has just connected to the system.
* @param dpid the dpid to add
* @param sw the actual switch object.
* @return true if added, false otherwise.
*/
public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw);
/**
* Checks if the activation for this switch is valid.
* @param dpid the dpid to check
* @return true if valid, false otherwise
*/
public boolean validActivation(Dpid dpid);
/**
* Called when a switch is activated, with this controller's role as MASTER.
* @param dpid the dpid to add.
* @param sw the actual switch
* @return true if added, false otherwise.
*/
public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw);
/**
* Called when a switch is activated, with this controller's role as EQUAL.
* @param dpid the dpid to add.
* @param sw the actual switch
* @return true if added, false otherwise.
*/
public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw);
/**
* 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'.
* @param dpid the dpid to transistion.
*/
public void transitionToMasterSwitch(Dpid dpid);
/**
* 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'.
* @param dpid the dpid to transistion.
*/
public void transitionToEqualSwitch(Dpid dpid);
/**
* 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.
* @param dpid the dpid to remove.
*/
public void removeConnectedSwitch(Dpid dpid);
/**
* Process a message coming from a switch.
* @param m the message to process
*/
public void processMessage(OFMessage m);
}
package org.onlab.onos.of.controller.driver;
import java.util.List;
import org.jboss.netty.channel.Channel;
import org.onlab.onos.of.controller.OpenFlowSwitch;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFErrorMsg;
import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFVersion;
/**
* Represents the driver side of an OpenFlow switch.
* This interface should never be exposed to consumers.
*
*/
public interface OpenFlowSwitchDriver extends OpenFlowSwitch {
/**
* Sets the OpenFlow agent to be used. This method
* can only be called once.
* @param agent the agent to set.
*/
public void setAgent(OpenFlowAgent agent);
/**
* Sets the Role handler object.
* This method can only be called once.
* @param roleHandler the roleHandler class
*/
public void setRoleHandler(RoleHandler roleHandler);
/**
* Reasserts this controllers role to the switch.
* Useful in cases where the switch no longer agrees
* that this controller has the role it claims.
*/
public void reassertRole();
/**
* Handle the situation where the role request triggers an error.
* @param error the error to handle.
* @return true if handled, false if not.
*/
public boolean handleRoleError(OFErrorMsg error);
/**
* If this driver know of Nicira style role messages, these should
* be handled here.
* @param m the role message to handle.
* @throws SwitchStateException if the message received was
* not a nicira role or was malformed.
*/
public void handleNiciraRole(OFMessage m) throws SwitchStateException;
/**
* Handle OF 1.x (where x > 0) role messages.
* @param m the role message to handle
* @throws SwitchStateException if the message received was
* not a nicira role or was malformed.
*/
public void handleRole(OFMessage m) throws SwitchStateException;
/**
* Starts the driver specific handshake process.
*/
public void startDriverHandshake();
/**
* Checks whether the driver specific handshake is complete.
* @return true is finished, false if not.
*/
public boolean isDriverHandshakeComplete();
/**
* Process a message during the driver specific handshake.
* @param m the message to process.
*/
public void processDriverHandshakeMessage(OFMessage m);
/**
* Announce to the OpenFlow agent that this switch has connected.
* @return true if successful, false if duplicate switch.
*/
public boolean connectSwitch();
/**
* Activate this MASTER switch-controller relationship in the OF agent.
* @return true is successful, false is switch has not
* connected or is unknown to the system.
*/
public boolean activateMasterSwitch();
/**
* Activate this EQUAL switch-controller relationship in the OF agent.
* @return true is successful, false is switch has not
* connected or is unknown to the system.
*/
public boolean activateEqualSwitch();
/**
* Transition this switch-controller relationship to an EQUAL state.
*/
public void transitionToEqualSwitch();
/**
* Transition this switch-controller relationship to an Master state.
*/
public void transitionToMasterSwitch();
/**
* Remove this switch from the openflow agent.
*/
public void removeConnectedSwitch();
/**
* Sets the ports on this switch.
* @param portDescReply the port set and descriptions
*/
public void setPortDescReply(OFPortDescStatsReply portDescReply);
/**
* Sets the features reply for this switch.
* @param featuresReply the features to set.
*/
public void setFeaturesReply(OFFeaturesReply featuresReply);
/**
* Sets the switch description.
* @param desc the descriptions
*/
public void setSwitchDescription(OFDescStatsReply desc);
/**
* Gets the next transaction id to use.
* @return the xid
*/
public int getNextTransactionId();
/**
* Does this switch support Nicira Role messages.
* @return true if supports, false otherwise.
*/
public Boolean supportNxRole();
/**
* Sets the OF version for this switch.
* @param ofV the version to set.
*/
public void setOFVersion(OFVersion ofV);
/**
* Sets this switch has having a full flowtable.
* @param full true if full, false otherswise.
*/
public void setTableFull(boolean full);
/**
* Sets the associated Netty channel for this switch.
* @param channel the Netty channel
*/
public void setChannel(Channel channel);
/**
* Sets whether the switch is connected.
*
* @param connected whether the switch is connected
*/
public void setConnected(boolean connected);
/**
* Checks if the switch is still connected.
*
* @return whether the switch is still connected
*/
public boolean isConnected();
/**
* Writes the message to the output stream
* in a driver specific manner.
*
* @param msg the message to write
*/
public void write(OFMessage msg);
/**
* Writes to the OFMessage list to the output stream
* in a driver specific manner.
*
* @param msgs the messages to be written
*/
public void write(List<OFMessage> msgs);
}
package org.onlab.onos.of.controller.driver;
import org.onlab.onos.of.controller.Dpid;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFVersion;
/**
* Switch factory which returns concrete switch objects for the
* physical openflow switch in use.
*
*/
public interface OpenFlowSwitchDriverFactory {
/**
* Constructs the real openflow switch representation.
* @param dpid the dpid for this switch.
* @param desc its description.
* @param ofv the OF version in use
* @return the openflow switch representation.
*/
public OpenFlowSwitchDriver getOFSwitchImpl(Dpid dpid,
OFDescStatsReply desc, OFVersion ofv);
}
package org.onlab.onos.of.controller.driver;
import java.io.IOException;
import org.onlab.onos.of.controller.RoleState;
import org.projectfloodlight.openflow.protocol.OFErrorMsg;
import org.projectfloodlight.openflow.protocol.OFExperimenter;
import org.projectfloodlight.openflow.protocol.OFRoleReply;
/**
* Role handling.
*
*/
public interface RoleHandler {
/**
* 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 experimenterMsg 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.
*/
public RoleState extractNiciraRoleReply(OFExperimenter experimenterMsg)
throws SwitchStateException;
/**
* 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.
*/
public boolean sendRoleRequest(RoleState role, RoleRecvStatus exp)
throws IOException;
/**
* Extract the role information from an OF1.3 Role Reply Message.
* @param h
* @param rrmsg
* @return RoleReplyInfo object
* @throws SwitchStateException
*/
public RoleReplyInfo extractOFRoleReply(OFRoleReply rrmsg)
throws SwitchStateException;
/**
* 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 rri information about role-reply in format that
* controller can understand.
* @throws SwitchStateException if no request is pending
*/
public RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
throws SwitchStateException;
/**
* 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
*/
public RoleRecvStatus deliverError(OFErrorMsg error)
throws SwitchStateException;
}
package org.onlab.onos.of.controller.driver;
/**
* 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,
}
package org.onlab.onos.of.controller.driver;
import org.onlab.onos.of.controller.RoleState;
import org.projectfloodlight.openflow.types.U64;
/**
* Helper class returns role reply information in the format understood
* by the controller.
*/
public class RoleReplyInfo {
private final RoleState role;
private final U64 genId;
private final long xid;
public 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 + "]";
}
}
package org.onlab.onos.of.controller.impl.internal;
package org.onlab.onos.of.controller.driver;
/**
* Thrown when IOFSwitch.startDriverHandshake() is called more than once.
......
package org.onlab.onos.of.controller.impl.internal;
package org.onlab.onos.of.controller.driver;
import org.projectfloodlight.openflow.protocol.OFMessage;
......
package org.onlab.onos.of.controller.impl.internal;
package org.onlab.onos.of.controller.driver;
/**
* Base class for exception thrown by switch driver sub-handshake processing.
......
package org.onlab.onos.of.controller.impl.internal;
package org.onlab.onos.of.controller.driver;
/**
* Thrown when a switch driver's sub-handshake has not been started but an
......
package org.onlab.onos.of.controller.impl.internal;
package org.onlab.onos.of.controller.driver;
/**
* Thrown when a switch driver's sub-handshake state-machine receives an
......
......@@ -15,7 +15,7 @@
* under the License.
**/
package org.onlab.onos.of.controller.impl.internal;
package org.onlab.onos.of.controller.driver;
/**
* This exception indicates an error or unexpected message during
......
......@@ -30,9 +30,10 @@ 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.Dpid;
import org.onlab.onos.of.controller.driver.OpenFlowAgent;
import org.onlab.onos.of.controller.driver.OpenFlowSwitchDriver;
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.onlab.onos.of.drivers.DriverManager;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFFactories;
......@@ -74,7 +75,7 @@ public class Controller {
// Flag to always flush flow table on switch reconnect (HA or otherwise)
protected boolean alwaysClearFlowsOnSwAdd = false;
private OpenFlowSwitchAgent agent;
private OpenFlowAgent agent;
// Perf. related configuration
protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
......@@ -120,17 +121,17 @@ public class Controller {
* Tell controller that we're ready to accept switches loop.
*/
@LogMessageDocs({
@LogMessageDoc(message = "Listening for switch connections on {address}",
explanation = "The controller is ready and listening for new" +
" switch connections"),
@LogMessageDoc(message = "Storage exception in controller " +
"updates loop; terminating process",
explanation = ERROR_DATABASE,
recommendation = LogMessageDoc.CHECK_CONTROLLER),
@LogMessageDoc(level = "ERROR",
message = "Exception in controller updates loop",
explanation = "Failed to dispatch controller event",
recommendation = LogMessageDoc.GENERIC_ACTION)
@LogMessageDoc(message = "Listening for switch connections on {address}",
explanation = "The controller is ready and listening for new" +
" switch connections"),
@LogMessageDoc(message = "Storage exception in controller " +
"updates loop; terminating process",
explanation = ERROR_DATABASE,
recommendation = LogMessageDoc.CHECK_CONTROLLER),
@LogMessageDoc(level = "ERROR",
message = "Exception in controller updates loop",
explanation = "Failed to dispatch controller event",
recommendation = LogMessageDoc.GENERIC_ACTION)
})
public void run() {
......@@ -221,15 +222,16 @@ public class Controller {
* @param desc
* @return switch instance
*/
protected AbstractOpenFlowSwitch getOFSwitchInstance(long dpid,
protected OpenFlowSwitchDriver getOFSwitchInstance(long dpid,
OFDescStatsReply desc, OFVersion ofv) {
AbstractOpenFlowSwitch sw = DriverManager.getOFSwitchImpl(new Dpid(dpid),
OpenFlowSwitchDriver sw = DriverManager.getSwitch(new Dpid(dpid),
desc, ofv);
sw.setAgent(agent);
sw.setRoleHandler(new RoleManager(sw));
return sw;
}
public void start(OpenFlowSwitchAgent ag) {
public void start(OpenFlowAgent ag) {
log.info("Initialising OpenFlow Lib and IO");
this.agent = ag;
this.init(new HashMap<String, String>());
......
package org.onlab.onos.of.controller.impl.internal;
import org.onlab.onos.of.controller.driver.AbstractOpenFlowSwitch;
import org.projectfloodlight.openflow.protocol.OFVersion;
......
......@@ -18,6 +18,8 @@ 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.driver.OpenFlowSwitchDriver;
import org.onlab.onos.of.controller.driver.SwitchStateException;
import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
import org.projectfloodlight.openflow.exceptions.OFParseError;
......@@ -66,7 +68,7 @@ import org.slf4j.LoggerFactory;
class OFChannelHandler extends IdleStateAwareChannelHandler {
private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
private final Controller controller;
private AbstractOpenFlowSwitch sw;
private OpenFlowSwitchDriver sw;
private long thisdpid; // channelHandler cached value of connected switch id
private Channel channel;
// State needs to be volatile because the HandshakeTimeoutHandler
......@@ -413,7 +415,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
OFDescStatsReply drep = (OFDescStatsReply) m;
// Here is where we differentiate between different kinds of switches
h.sw = h.controller.getOFSwitchInstance(h.thisdpid, drep, h.ofVersion);
boolean success = h.sw.addConnectedSwitch();
boolean success = h.sw.connectSwitch();
if (!success) {
disconnectDuplicate(h);
return;
......@@ -431,7 +433,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
//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.sw.addActivatedEqualSwitch();
h.sw.activateEqualSwitch();
//h.setSwitchRole(RoleState.EQUAL);
h.setSwitchRole(RoleState.MASTER);
h.sw.startDriverHandshake();
......@@ -489,8 +491,8 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
}
}
} else {
if (m.getType() == OFType.EXPERIMENTER &&
((OFExperimenter) m).getExperimenter() ==
if (m.getType() == OFType.EXPERIMENTER &&
((OFExperimenter) m).getExperimenter() ==
RoleManager.NICIRA_EXPERIMENTER) {
h.sw.handleNiciraRole(m);
} else {
......@@ -848,8 +850,8 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
processOFQueueGetConfigReply(h, (OFQueueGetConfigReply) m);
break;
case STATS_REPLY: // multipart_reply in 1.3
processOFStatisticsReply(h, (OFStatsReply) m);
break;
processOFStatisticsReply(h, (OFStatsReply) m);
break;
case EXPERIMENTER:
processOFExperimenter(h, (OFExperimenter) m);
break;
......@@ -916,12 +918,12 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
}
OFFactory factory = (h.ofVersion == OFVersion.OF_13) ?
h.controller.getOFMessageFactory13() : h.controller.getOFMessageFactory10();
OFEchoReply reply = factory
.buildEchoReply()
.setXid(m.getXid())
.setData(m.getData())
.build();
h.channel.write(Collections.singletonList(reply));
OFEchoReply reply = factory
.buildEchoReply()
.setXid(m.getXid())
.setData(m.getData())
.build();
h.channel.write(Collections.singletonList(reply));
}
void processOFEchoReply(OFChannelHandler h, OFEchoReply m)
......@@ -1044,41 +1046,41 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
message = "Disconnecting switch {switch} due to read timeout",
explanation = "The connected switch has failed to send any "
+ "messages or respond to echo requests",
recommendation = LogMessageDoc.CHECK_SWITCH),
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Disconnecting switch {switch}: failed to "
+ "complete handshake",
explanation = "The switch did not respond correctly "
+ "to handshake messages",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Disconnecting switch {switch} due to IO Error: {}",
explanation = "There was an error communicating with the switch",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Disconnecting switch {switch} due to switch "
+ "state error: {error}",
explanation = "The switch sent an unexpected message",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Disconnecting switch {switch} due to "
+ "message parse failure",
explanation = "Could not parse a message from the switch",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Terminating controller due to storage exception",
explanation = Controller.ERROR_DATABASE,
recommendation = LogMessageDoc.CHECK_CONTROLLER),
@LogMessageDoc(level = "ERROR",
message = "Could not process message: queue full",
explanation = "OpenFlow messages are arriving faster than "
+ "the controller can process them.",
recommendation = LogMessageDoc.CHECK_CONTROLLER),
@LogMessageDoc(level = "ERROR",
message = "Error while processing message "
+ "from switch {switch} {cause}",
explanation = "An error occurred processing the switch message",
recommendation = LogMessageDoc.GENERIC_ACTION)
message = "Disconnecting switch {switch}: failed to "
+ "complete handshake",
explanation = "The switch did not respond correctly "
+ "to handshake messages",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Disconnecting switch {switch} due to IO Error: {}",
explanation = "There was an error communicating with the switch",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Disconnecting switch {switch} due to switch "
+ "state error: {error}",
explanation = "The switch sent an unexpected message",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Disconnecting switch {switch} due to "
+ "message parse failure",
explanation = "Could not parse a message from the switch",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Terminating controller due to storage exception",
explanation = Controller.ERROR_DATABASE,
recommendation = LogMessageDoc.CHECK_CONTROLLER),
@LogMessageDoc(level = "ERROR",
message = "Could not process message: queue full",
explanation = "OpenFlow messages are arriving faster than "
+ "the controller can process them.",
recommendation = LogMessageDoc.CHECK_CONTROLLER),
@LogMessageDoc(level = "ERROR",
message = "Error while processing message "
+ "from switch {switch} {cause}",
explanation = "An error occurred processing the switch message",
recommendation = LogMessageDoc.GENERIC_ACTION)
})
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
......
......@@ -15,8 +15,9 @@ 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.onlab.onos.of.controller.driver.AbstractOpenFlowSwitch;
import org.onlab.onos.of.controller.driver.OpenFlowAgent;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.util.HexString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -27,12 +28,12 @@ public class OpenFlowControllerImpl implements OpenFlowController {
private static final Logger log =
LoggerFactory.getLogger(OpenFlowControllerImpl.class);
protected ConcurrentHashMap<Long, OpenFlowSwitch> connectedSwitches =
new ConcurrentHashMap<Long, OpenFlowSwitch>();
protected ConcurrentHashMap<Long, OpenFlowSwitch> activeMasterSwitches =
new ConcurrentHashMap<Long, OpenFlowSwitch>();
protected ConcurrentHashMap<Long, OpenFlowSwitch> activeEqualSwitches =
new ConcurrentHashMap<Long, OpenFlowSwitch>();
protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
protected ArrayList<OpenFlowSwitchListener> ofEventListener =
......@@ -118,12 +119,13 @@ public class OpenFlowControllerImpl implements OpenFlowController {
((AbstractOpenFlowSwitch) getSwitch(dpid)).setRole(role);
}
public class OpenFlowSwitchAgent {
public class OpenFlowSwitchAgent implements OpenFlowAgent {
private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
private Lock switchLock = new ReentrantLock();
private final Lock switchLock = new ReentrantLock();
public boolean addConnectedSwitch(long dpid, AbstractOpenFlowSwitch sw) {
@Override
public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
if (connectedSwitches.get(dpid) != null) {
log.error("Trying to add connectedSwitch but found a previous "
+ "value for dpid: {}", dpid);
......@@ -132,17 +134,18 @@ public class OpenFlowControllerImpl implements OpenFlowController {
log.error("Added switch {}", dpid);
connectedSwitches.put(dpid, sw);
for (OpenFlowSwitchListener l : ofEventListener) {
l.switchAdded(new Dpid(dpid));
l.switchAdded(dpid);
}
return true;
}
}
private boolean validActivation(long dpid) {
@Override
public boolean validActivation(Dpid dpid) {
if (connectedSwitches.get(dpid) == null) {
log.error("Trying to activate switch but is not in "
+ "connected switches: dpid {}. Aborting ..",
HexString.toHexString(dpid));
dpid);
return false;
}
if (activeMasterSwitches.get(dpid) != null ||
......@@ -150,18 +153,17 @@ public class OpenFlowControllerImpl implements OpenFlowController {
log.error("Trying to activate switch but it is already "
+ "activated: dpid {}. Found in activeMaster: {} "
+ "Found in activeEqual: {}. Aborting ..", new Object[] {
HexString.toHexString(dpid),
dpid,
(activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
(activeEqualSwitches.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) {
@Override
public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
switchLock.lock();
try {
if (!validActivation(dpid)) {
......@@ -172,31 +174,25 @@ public class OpenFlowControllerImpl implements OpenFlowController {
} finally {
switchLock.unlock();
}
}
}
/**
* Called when a switch is activated, with this controller's role as EQUAL.
*/
protected boolean addActivatedEqualSwitch(long dpid, AbstractOpenFlowSwitch sw) {
@Override
public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
switchLock.lock();
try {
if (!validActivation(dpid)) {
return false;
}
activeEqualSwitches.put(dpid, sw);
log.info("Added Activated EQUAL Switch {}", dpid);
return true;
if (!validActivation(dpid)) {
return false;
}
activeEqualSwitches.put(dpid, sw);
log.info("Added Activated EQUAL Switch {}", dpid);
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) {
@Override
public void transitionToMasterSwitch(Dpid dpid) {
switchLock.lock();
try {
if (activeMasterSwitches.containsKey(dpid)) {
......@@ -215,12 +211,8 @@ public class OpenFlowControllerImpl implements OpenFlowController {
}
/**
* 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) {
@Override
public void transitionToEqualSwitch(Dpid dpid) {
switchLock.lock();
try {
if (activeEqualSwitches.containsKey(dpid)) {
......@@ -239,22 +231,19 @@ public class OpenFlowControllerImpl implements OpenFlowController {
}
/**
* 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) {
@Override
public void removeConnectedSwitch(Dpid 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));
l.switchRemoved(dpid);
}
}
@Override
public void processMessage(OFMessage m) {
processPacket(m);
}
......
......@@ -4,6 +4,11 @@ import java.io.IOException;
import java.util.Collections;
import org.onlab.onos.of.controller.RoleState;
import org.onlab.onos.of.controller.driver.OpenFlowSwitchDriver;
import org.onlab.onos.of.controller.driver.RoleHandler;
import org.onlab.onos.of.controller.driver.RoleRecvStatus;
import org.onlab.onos.of.controller.driver.RoleReplyInfo;
import org.onlab.onos.of.controller.driver.SwitchStateException;
import org.projectfloodlight.openflow.protocol.OFControllerRole;
import org.projectfloodlight.openflow.protocol.OFErrorMsg;
import org.projectfloodlight.openflow.protocol.OFErrorType;
......@@ -35,7 +40,7 @@ import org.slf4j.LoggerFactory;
* a new request is submitted before the timeout triggers. If necessary
* we could work around that though.
*/
class RoleManager {
class RoleManager implements RoleHandler {
protected static final long NICIRA_EXPERIMENTER = 0x2320;
private static Logger log = LoggerFactory.getLogger(RoleManager.class);
......@@ -49,10 +54,10 @@ class RoleManager {
// the expectation set by the caller for the returned role
private RoleRecvStatus expectation;
private AbstractOpenFlowSwitch sw;
private final OpenFlowSwitchDriver sw;
public RoleManager(AbstractOpenFlowSwitch sw) {
public RoleManager(OpenFlowSwitchDriver sw) {
this.requestPending = false;
this.pendingXid = -1;
this.pendingRole = null;
......@@ -122,33 +127,13 @@ class RoleManager {
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)
@Override
public synchronized boolean sendRoleRequest(RoleState role, RoleRecvStatus exp)
throws IOException {
this.expectation = exp;
if (sw.factory().getVersion() == OFVersion.OF_10) {
Boolean supportsNxRole = (Boolean)
sw.supportNxRole();
Boolean supportsNxRole = sw.supportNxRole();
if (!supportsNxRole) {
log.debug("Switch driver indicates no support for Nicira "
+ "role request messages. Not sending ...");
......@@ -189,23 +174,9 @@ class RoleManager {
}
/**
* 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)
@Override
public synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
throws SwitchStateException {
if (!requestPending) {
RoleState currentRole = (sw != null) ? sw.getRole() : null;
......@@ -280,12 +251,13 @@ class RoleManager {
* error messages for earlier role requests that we won't be able
* to handle
*/
synchronized RoleRecvStatus deliverError(OFErrorMsg error)
@Override
public 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());
sw.getStringId());
return RoleRecvStatus.OTHER_EXPECTATION;
}
if (pendingXid != error.getXid()) {
......@@ -353,7 +325,8 @@ class RoleManager {
* @throws SwitchStateException If the message is a Nicira role reply
* but the numeric role value is unknown.
*/
protected RoleState extractNiciraRoleReply(OFExperimenter experimenterMsg)
@Override
public RoleState extractNiciraRoleReply(OFExperimenter experimenterMsg)
throws SwitchStateException {
int vendor = (int) experimenterMsg.getExperimenter();
if (vendor != 0x2320) {
......@@ -389,72 +362,14 @@ class RoleManager {
}
/**
* 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
* @param rrmsg the role message
* @return RoleReplyInfo object
* @throws SwitchStateException
* @throws SwitchStateException if the role information could not be extracted.
*/
protected RoleReplyInfo extractOFRoleReply(OFRoleReply rrmsg)
@Override
public RoleReplyInfo extractOFRoleReply(OFRoleReply rrmsg)
throws SwitchStateException {
OFControllerRole cr = rrmsg.getRole();
RoleState role = null;
......
......@@ -3,11 +3,9 @@ package org.onlab.onos.of.drivers;
import org.onlab.onos.of.controller.Dpid;
import org.onlab.onos.of.controller.RoleState;
import org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch;
import org.onlab.onos.of.controller.driver.OpenFlowSwitchDriver;
import org.onlab.onos.of.controller.driver.OpenFlowSwitchDriverFactory;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -16,7 +14,7 @@ import org.slf4j.LoggerFactory;
* A simple implementation of a driver manager that differentiates between
* connected switches using the OF Description Statistics Reply message.
*/
public final class DriverManager {
public final class DriverManager implements OpenFlowSwitchDriverFactory {
private static final Logger log = LoggerFactory.getLogger(DriverManager.class);
......@@ -32,7 +30,8 @@ public final class DriverManager {
* @return A IOFSwitch instance if the driver found an implementation for
* the given description. Otherwise it returns OFSwitchImplBase
*/
public static AbstractOpenFlowSwitch getOFSwitchImpl(Dpid dpid,
@Override
public OpenFlowSwitchDriver getOFSwitchImpl(Dpid dpid,
OFDescStatsReply desc, OFVersion ofv) {
String vendor = desc.getMfrDesc();
String hw = desc.getHwDesc();
......@@ -53,42 +52,7 @@ public final class DriverManager {
log.warn("DriverManager could not identify switch desc: {}. "
+ "Assigning OFSwitchImplBase", desc);
AbstractOpenFlowSwitch base = new AbstractOpenFlowSwitch(dpid) {
@Override
public void sendMsg(OFMessage m) {
channel.write(m);
}
@Override
public Boolean supportNxRole() {
return false;
}
@Override
public void startDriverHandshake() {}
@Override
public void setFeaturesReply(OFFeaturesReply featuresReply) {
this.features = featuresReply;
}
@Override
public void processDriverHandshakeMessage(OFMessage m) {}
@Override
public boolean isDriverHandshakeComplete() {
return true;
}
@Override
public RoleState getRole() {
return role;
}
};
base.setSwitchDescription(desc);
return base;
return null;
}
/**
......@@ -108,4 +72,10 @@ public final class DriverManager {
public static void setConfigForCpqd(boolean usePipeline13) {
cpqdUsePipeline13 = usePipeline13;
}
public static OpenFlowSwitchDriver getSwitch(Dpid dpid,
OFDescStatsReply desc, OFVersion ofv) {
return new DriverManager().getOFSwitchImpl(dpid, desc, ofv);
}
}
......
package org.onlab.onos.of.drivers;
import java.util.List;
import org.onlab.onos.of.controller.Dpid;
import org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch;
import org.onlab.onos.of.controller.driver.AbstractOpenFlowSwitch;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFMessage;
......@@ -29,11 +31,6 @@ public class OFSwitchImplOVS10 extends AbstractOpenFlowSwitch {
}
@Override
public void sendMsg(OFMessage m) {
channel.write(m);
}
@Override
public Boolean supportNxRole() {
return true;
}
......@@ -48,4 +45,15 @@ public class OFSwitchImplOVS10 extends AbstractOpenFlowSwitch {
@Override
public void processDriverHandshakeMessage(OFMessage m) {}
@Override
public void write(OFMessage msg) {
channel.write(msg);
}
@Override
public void write(List<OFMessage> msgs) {
channel.write(msgs);
}
}
......
package org.onlab.onos.of.drivers;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.onlab.onos.of.controller.Dpid;
import org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch;
import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeAlreadyStarted;
import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeCompleted;
import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeNotStarted;
import org.onlab.onos.of.controller.driver.AbstractOpenFlowSwitch;
import org.onlab.onos.of.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
import org.onlab.onos.of.controller.driver.SwitchDriverSubHandshakeCompleted;
import org.onlab.onos.of.controller.driver.SwitchDriverSubHandshakeNotStarted;
import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFErrorMsg;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.slf4j.Logger;
......@@ -25,7 +25,7 @@ public class OFSwitchImplOVS13 extends AbstractOpenFlowSwitch {
private static Logger log =
LoggerFactory.getLogger(OFSwitchImplOVS13.class);
private AtomicBoolean driverHandshakeComplete;
private final AtomicBoolean driverHandshakeComplete;
private OFFactory factory;
private long barrierXidToWaitFor = -1;
......@@ -78,7 +78,7 @@ public class OFSwitchImplOVS13 extends AbstractOpenFlowSwitch {
break;
case ERROR:
log.error("Switch {} Error {}", getStringId(), (OFErrorMsg) m);
log.error("Switch {} Error {}", getStringId(), m);
break;
case FEATURES_REPLY:
......@@ -129,12 +129,18 @@ public class OFSwitchImplOVS13 extends AbstractOpenFlowSwitch {
}
@Override
public void sendMsg(OFMessage m) {
channel.write(m);
public Boolean supportNxRole() {
return false;
}
@Override
public Boolean supportNxRole() {
return false;
public void write(OFMessage msg) {
channel.write(msg);
}
@Override
public void write(List<OFMessage> msgs) {
channel.write(msgs);
}
}
......