tom

Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Showing 37 changed files with 778 additions and 1487 deletions
......@@ -63,7 +63,7 @@
<configuration>
<instructions>
<Export-Package>
org.projectfloodlight.openflow.*
org.onlab.onos.of.*,org.projectfloodlight.openflow.*
</Export-Package>
</instructions>
</configuration>
......
package org.onlab.onos.of.controller;
/**
* Created by tom on 8/21/14.
*/
public interface DeleteMe {
}
package org.onlab.onos.of.controller.impl.util;
package org.onlab.onos.of.controller;
import org.projectfloodlight.openflow.util.HexString;
......
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);
}
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);
}
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
}
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);
}
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();
}
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);
}
package org.onlab.onos.of.controller.impl;
package org.onlab.onos.of.controller;
import org.projectfloodlight.openflow.protocol.OFControllerRole;
......@@ -10,27 +10,14 @@ import org.projectfloodlight.openflow.protocol.OFControllerRole;
* to the OF1.3 enum, before role messages are sent to the switch.
* See sendRoleRequestMessage method in OFSwitchImpl
*/
public enum Role {
public enum RoleState {
EQUAL(OFControllerRole.ROLE_EQUAL),
MASTER(OFControllerRole.ROLE_MASTER),
SLAVE(OFControllerRole.ROLE_SLAVE);
private Role(OFControllerRole nxRole) {
private RoleState(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);
}*/
}
......
......@@ -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>
......
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();
}
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;
}
}
}
/**
* 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;
}
}
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 @@ public interface IOFSwitchManager {
* @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);
}
......
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);
}
}
}
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();
}
}
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();
}
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
+ "]";
}
}
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);
}
}
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;
}
}
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;
}
}
/**
* 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();
}
}
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;
}
}
/**
* 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();
}
}
/**
* 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;
}
}
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;
}
}
/**
* 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();
}
}
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> {
}
/**
* 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);
}
}