diff --git a/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java b/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java index 347bf5bb9bcbd167c3b812804f40dbac05154bf3..624483a8d412308dde64c964b2baa7596a0d482a 100644 --- a/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java +++ b/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java @@ -11,6 +11,7 @@ import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.counter.ICounterStoreService; +import net.floodlightcontroller.flowcache.IFlowCacheService; import net.floodlightcontroller.perfmon.IPktInProcessingTimeService; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.storage.IStorageSourceService; @@ -48,6 +49,7 @@ public class FloodlightProvider implements IFloodlightModule { dependencies.add(IPktInProcessingTimeService.class); dependencies.add(IRestApiService.class); dependencies.add(ICounterStoreService.class); + dependencies.add(IFlowCacheService.class); dependencies.add(IThreadPoolService.class); return dependencies; } @@ -60,6 +62,8 @@ public class FloodlightProvider implements IFloodlightModule { context.getServiceImpl(IPktInProcessingTimeService.class)); controller.setCounterStore( context.getServiceImpl(ICounterStoreService.class)); + controller.setFlowCacheMgr( + context.getServiceImpl(IFlowCacheService.class)); controller.setRestApiService( context.getServiceImpl(IRestApiService.class)); controller.setThreadPoolService( diff --git a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java index 1e3ec6f91af7f7d7550515b6c05ee42675a54f58..b9a628ba84d16c812d6b7309696eb05251f885f1 100644 --- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java +++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java @@ -33,7 +33,8 @@ import org.openflow.protocol.factory.BasicFactory; * * @author David Erickson (daviderickson@cs.stanford.edu) */ -public interface IFloodlightProviderService extends IFloodlightService { +public interface IFloodlightProviderService extends + IFloodlightService { /** * A value stored in the floodlight context containing a parsed packet @@ -206,5 +207,13 @@ public interface IFloodlightProviderService extends IFloodlightService { * switch over to ACTIVE role */ public void setAlwaysClearFlowsOnSwAdd(boolean value); + + /** + * Adds an OFSwitch driver + * @param desc The starting portion of switch's manufacturer string + * @param driver The object implementing OFSwitchDriver interface + */ + public void addOFSwitchDriver(String desc, IOFSwitchDriver driver); + } diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java index 60df97b40d5b858ac3e2cc8a8ac60a8100aced8a..68e025b807cc8212a432f343a732714497eadd97 100644 --- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java +++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java @@ -23,7 +23,11 @@ import java.util.Date; import java.util.List; import java.util.Map; import java.util.concurrent.Future; +import java.util.concurrent.locks.Lock; + import net.floodlightcontroller.core.IFloodlightProviderService.Role; +import net.floodlightcontroller.core.internal.Controller; +import net.floodlightcontroller.threadpool.IThreadPoolService; import org.jboss.netty.channel.Channel; import org.openflow.protocol.OFFeaturesReply; @@ -375,5 +379,39 @@ public interface IOFSwitch { * Flush all flows queued for this switch in the current thread. * NOTE: The contract is limited to the current thread */ - public void flush(); + public void flush(); + + /** + * Send HA role request + * + * @param role + * @param cookie + * @return + * @throws IOException + */ + public int sendNxRoleRequest(Role role, long cookie) throws IOException; + + /** + * Check HA role request cookie + * + * @param cookie + * @return + */ + public boolean checkFirstPendingRoleRequestCookie(long cookie); + + public void setChannel(Channel channel); + + public void setFloodlightProvider(Controller controller); + + public void setThreadPoolService(IThreadPoolService threadPool); + + public void deliverRoleReply(int xid, Role role); + + public void deliverRoleRequestNotSupported(int xid); + + public Lock getListenerReadLock(); + + public boolean checkFirstPendingRoleRequestXid(int xid); + + public Lock getListenerWriteLock(); } diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java b/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java new file mode 100644 index 0000000000000000000000000000000000000000..197642959516a2b2353cdf695d2217efbcd856c1 --- /dev/null +++ b/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java @@ -0,0 +1,12 @@ +package net.floodlightcontroller.core; + +import org.openflow.protocol.statistics.OFDescriptionStatistics; + +public interface IOFSwitchDriver { + /** + * Return an IOFSwitch object based on switch's manufacturer description + * from OFDescriptionStatitics. + * @param description + */ + public IOFSwitch getOFSwitchImpl(OFDescriptionStatistics description); +} diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java index 6cb369f7bc52fa8067cd3c5f8034991a0b15c097..cfe1d85bb60a96ef5e60ec732fd7b1953560c328 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java +++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java @@ -39,12 +39,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Executors; -import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IHAListener; @@ -52,6 +48,7 @@ import net.floodlightcontroller.core.IInfoProvider; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IListener.Command; import net.floodlightcontroller.core.IOFSwitch; +import net.floodlightcontroller.core.IOFSwitchDriver; import net.floodlightcontroller.core.IOFSwitchFilter; import net.floodlightcontroller.core.IOFSwitchListener; import net.floodlightcontroller.core.annotations.LogMessageDoc; @@ -60,6 +57,7 @@ import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState; import net.floodlightcontroller.core.util.ListenerDispatcher; import net.floodlightcontroller.core.web.CoreWebRoutable; import net.floodlightcontroller.counter.ICounterStoreService; +import net.floodlightcontroller.flowcache.IFlowCacheService; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.perfmon.IPktInProcessingTimeService; import net.floodlightcontroller.restserver.IRestApiService; @@ -73,6 +71,7 @@ import net.floodlightcontroller.util.LoadMonitor; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; @@ -97,12 +96,14 @@ import org.openflow.protocol.OFError.OFPortModFailedCode; import org.openflow.protocol.OFError.OFQueueOpFailedCode; import org.openflow.protocol.OFFeaturesReply; import org.openflow.protocol.OFGetConfigReply; +import org.openflow.protocol.OFGetConfigRequest; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPhysicalPort; import org.openflow.protocol.OFPortStatus; import org.openflow.protocol.OFPortStatus.OFPortReason; import org.openflow.protocol.OFSetConfig; +import org.openflow.protocol.OFStatisticsReply; import org.openflow.protocol.OFStatisticsRequest; import org.openflow.protocol.OFSwitchConfig; import org.openflow.protocol.OFType; @@ -139,6 +140,10 @@ public class Controller implements IFloodlightProviderService, protected ConcurrentMap<OFType, ListenerDispatcher<OFType,IOFMessageListener>> messageListeners; + // OFSwitch driver binding map and order + protected Map<String, IOFSwitchDriver>switchBindingMap; + protected List<String> switchDescSortedList; + // The activeSwitches map contains only those switches that are actively // being controlled by us -- it doesn't contain switches that are // in the slave role @@ -148,7 +153,7 @@ public class Controller implements IFloodlightProviderService, // send role request messages to switches when our role changes to master // We add a switch to this set after it successfully completes the // handshake. Access to this Set needs to be synchronized with roleChanger - protected HashSet<OFSwitchImpl> connectedSwitches; + protected HashSet<IOFSwitch> connectedSwitches; // The controllerNodeIPsCache maps Controller IDs to their IP address. // It's only used by handleControllerNodeIPsChanged @@ -162,6 +167,7 @@ public class Controller implements IFloodlightProviderService, // Module dependencies protected IRestApiService restApi; protected ICounterStoreService counterStore = null; + protected IFlowCacheService bigFlowCacheMgr; protected IStorageSourceService storageSource; protected IPktInProcessingTimeService pktinProcTime; protected IThreadPoolService threadPool; @@ -333,6 +339,10 @@ public class Controller implements IFloodlightProviderService, this.counterStore = counterStore; } + public void setFlowCacheMgr(IFlowCacheService flowCacheMgr) { + this.bigFlowCacheMgr = flowCacheMgr; + } + public void setPktInProcessingService(IPktInProcessingTimeService pits) { this.pktinProcTime = pits; } @@ -404,7 +414,8 @@ public class Controller implements IFloodlightProviderService, */ protected class OFChannelHandler extends IdleStateAwareChannelUpstreamHandler { - protected OFSwitchImpl sw; + protected IOFSwitch sw; + protected Channel channel; protected OFChannelState state; public OFChannelHandler(OFChannelState state) { @@ -416,19 +427,11 @@ public class Controller implements IFloodlightProviderService, explanation="A new switch has connected from the " + "specified IP address") public void channelConnected(ChannelHandlerContext ctx, - ChannelStateEvent e) throws Exception { + ChannelStateEvent e) throws Exception { + channel = e.getChannel(); log.info("New switch connection from {}", - e.getChannel().getRemoteAddress()); - - sw = new OFSwitchImpl(); - sw.setChannel(e.getChannel()); - sw.setFloodlightProvider(Controller.this); - sw.setThreadPoolService(threadPool); - - List<OFMessage> msglist = new ArrayList<OFMessage>(1); - msglist.add(factory.getMessage(OFType.HELLO)); - e.getChannel().write(msglist); - + channel.getRemoteAddress()); + sendHandShakeMessage(OFType.HELLO); } @Override @@ -623,6 +626,7 @@ public class Controller implements IFloodlightProviderService, // Flush all flow-mods/packet-out/stats generated from this "train" OFSwitchImpl.flush_all(); counterStore.updateFlush(); + bigFlowCacheMgr.updateFlush(); } } @@ -634,73 +638,21 @@ public class Controller implements IFloodlightProviderService, " during handshake {exception}", explanation="Could not process the switch description string", recommendation=LogMessageDoc.CHECK_SWITCH) - void processSwitchDescReply() { + void processSwitchDescReply(OFStatisticsReply m) { try { // Read description, if it has been updated - @SuppressWarnings("unchecked") - Future<List<OFStatistics>> desc_future = - (Future<List<OFStatistics>>)sw. - getAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE); - List<OFStatistics> values = - desc_future.get(0, TimeUnit.MILLISECONDS); - if (values != null) { - OFDescriptionStatistics description = - new OFDescriptionStatistics(); - ChannelBuffer data = - ChannelBuffers.buffer(description.getLength()); - for (OFStatistics f : values) { - f.writeTo(data); - description.readFrom(data); - break; // SHOULD be a list of length 1 - } - sw.setAttribute(IOFSwitch.SWITCH_DESCRIPTION_DATA, - description); - sw.setSwitchProperties(description); - data = null; - - // At this time, also set other switch properties from storage - boolean is_core_switch = false; - IResultSet resultSet = null; - try { - String swid = sw.getStringId(); - resultSet = - storageSource.getRow(SWITCH_CONFIG_TABLE_NAME, swid); - for (Iterator<IResultSet> it = - resultSet.iterator(); it.hasNext();) { - // In case of multiple rows, use the status - // in last row? - Map<String, Object> row = it.next().getRow(); - if (row.containsKey(SWITCH_CONFIG_CORE_SWITCH)) { - if (log.isDebugEnabled()) { - log.debug("Reading SWITCH_IS_CORE_SWITCH " + - "config for switch={}, is-core={}", - sw, row.get(SWITCH_CONFIG_CORE_SWITCH)); - } - String ics = - (String)row.get(SWITCH_CONFIG_CORE_SWITCH); - is_core_switch = ics.equals("true"); - } - } - } - finally { - if (resultSet != null) - resultSet.close(); - } - if (is_core_switch) { - sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, - new Boolean(true)); - } - } - sw.removeAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE); + OFDescriptionStatistics description = + new OFDescriptionStatistics(); + ChannelBuffer data = + ChannelBuffers.buffer(description.getLength()); + OFStatistics f = m.getFirstStatistics(); + f.writeTo(data); + description.readFrom(data); + state.description = description; state.hasDescription = true; checkSwitchReady(); } - catch (InterruptedException ex) { - // Ignore - } - catch (TimeoutException ex) { - // Ignore - } catch (Exception ex) { + catch (Exception ex) { log.error("Exception in reading description " + " during handshake", ex); } @@ -711,9 +663,11 @@ public class Controller implements IFloodlightProviderService, * the switch * @throws IOException */ - void sendHelloConfiguration() throws IOException { + private void sendHandShakeMessage(OFType type) throws IOException { // Send initial Features Request - sw.write(factory.getMessage(OFType.FEATURES_REQUEST), null); + List<OFMessage> msglist = new ArrayList<OFMessage>(1); + msglist.add(factory.getMessage(type)); + channel.write(msglist); } /** @@ -721,30 +675,40 @@ public class Controller implements IFloodlightProviderService, * the features reply * @throws IOException */ - void sendFeatureReplyConfiguration() throws IOException { + private void sendFeatureReplyConfiguration() throws IOException { + List<OFMessage> msglist = new ArrayList<OFMessage>(3); + // Ensure we receive the full packet via PacketIn - OFSetConfig config = (OFSetConfig) factory + OFSetConfig configSet = (OFSetConfig) factory .getMessage(OFType.SET_CONFIG); - config.setMissSendLength((short) 0xffff) - .setLengthU(OFSwitchConfig.MINIMUM_LENGTH); - sw.write(config, null); - sw.write(factory.getMessage(OFType.GET_CONFIG_REQUEST), - null); + configSet.setMissSendLength((short) 0xffff) + .setLengthU(OFSwitchConfig.MINIMUM_LENGTH); + configSet.setXid(-4); + msglist.add(configSet); + + // Verify (need barrier?) + OFGetConfigRequest configReq = (OFGetConfigRequest) + factory.getMessage(OFType.GET_CONFIG_REQUEST); + configReq.setXid(-3); + msglist.add(configReq); // Get Description to set switch-specific flags OFStatisticsRequest req = new OFStatisticsRequest(); req.setStatisticType(OFStatisticsType.DESC); + req.setXid(-2); // something "large" req.setLengthU(req.getLengthU()); - Future<List<OFStatistics>> dfuture = - sw.getStatistics(req); - sw.setAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE, - dfuture); - + msglist.add(req); + + channel.write(msglist); } protected void checkSwitchReady() { + if (!state.switchBindingDone) { + bindSwitchToDriver(); + } + if (state.hsState == HandshakeState.FEATURES_REPLY && - state.hasDescription && state.hasGetConfigReply) { + state.switchBindingDone) { state.hsState = HandshakeState.READY; @@ -769,10 +733,10 @@ public class Controller implements IFloodlightProviderService, log.debug("This controller's role is {}, " + "sending initial role request msg to {}", role, sw); - Collection<OFSwitchImpl> swList = new ArrayList<OFSwitchImpl>(1); + Collection<IOFSwitch> swList = new ArrayList<IOFSwitch>(1); swList.add(sw); roleChanger.submitRequest(swList, role); - } + } else { // Role supported not enabled on controller (for now) // automatically promote switch to active state. @@ -788,6 +752,86 @@ public class Controller implements IFloodlightProviderService, } } + protected void bindSwitchToDriver() { + if (!state.hasGetConfigReply) { + log.debug("Waiting for config reply from switch {}", + channel.getRemoteAddress()); + return; + } + if (!state.hasDescription) { + log.debug("Waiting for switch description from switch {}", + channel.getRemoteAddress()); + return; + } + + for (String desc : switchDescSortedList) { + if (state.description.getManufacturerDescription() + .startsWith(desc)) { + sw = switchBindingMap.get(desc) + .getOFSwitchImpl(state.description); + if (sw != null) { + break; + } + } + } + if (sw == null) { + sw = new OFSwitchImpl(); + } + + // set switch information + sw.setChannel(channel); + sw.setFloodlightProvider(Controller.this); + sw.setThreadPoolService(threadPool); + sw.setFeaturesReply(state.featuresReply); + sw.setAttribute(IOFSwitch.SWITCH_DESCRIPTION_DATA, + state.description); + sw.setSwitchProperties(state.description); + readPropertyFromStorage(); + + state.featuresReply = null; + state.description = null; + state.switchBindingDone = true; + + log.info("Switch {} bound to class {}", + HexString.toHexString(sw.getId()), sw.getClass().getName()); + return; + } + + private void readPropertyFromStorage() { + // At this time, also set other switch properties from storage + boolean is_core_switch = false; + IResultSet resultSet = null; + try { + String swid = sw.getStringId(); + resultSet = + storageSource.getRow(SWITCH_CONFIG_TABLE_NAME, swid); + for (Iterator<IResultSet> it = + resultSet.iterator(); it.hasNext();) { + // In case of multiple rows, use the status + // in last row? + Map<String, Object> row = it.next().getRow(); + if (row.containsKey(SWITCH_CONFIG_CORE_SWITCH)) { + if (log.isDebugEnabled()) { + log.debug("Reading SWITCH_IS_CORE_SWITCH " + + "config for switch={}, is-core={}", + sw, row.get(SWITCH_CONFIG_CORE_SWITCH)); + } + String ics = + (String)row.get(SWITCH_CONFIG_CORE_SWITCH); + is_core_switch = ics.equals("true"); + } + } + } + finally { + if (resultSet != null) + resultSet.close(); + } + if (is_core_switch) { + sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, + new Boolean(true)); + } + } + /* Handle a role reply message we received from the switch. Since * netty serializes message dispatch we don't need to synchronize * against other receive operations from the same switch, so no need @@ -950,7 +994,7 @@ public class Controller implements IFloodlightProviderService, if (state.hsState.equals(HandshakeState.START)) { state.hsState = HandshakeState.HELLO; - sendHelloConfiguration(); + sendHandShakeMessage(OFType.FEATURES_REQUEST); } else { throw new SwitchStateException("Unexpected HELLO from " + sw); @@ -960,7 +1004,9 @@ public class Controller implements IFloodlightProviderService, OFEchoReply reply = (OFEchoReply) factory.getMessage(OFType.ECHO_REPLY); reply.setXid(m.getXid()); - sw.write(reply, null); + List<OFMessage> msglist = new ArrayList<OFMessage>(1); + msglist.add(reply); + channel.write(msglist); break; case ECHO_REPLY: break; @@ -968,15 +1014,16 @@ public class Controller implements IFloodlightProviderService, if (log.isTraceEnabled()) log.trace("Features Reply from {}", sw); - sw.setFeaturesReply((OFFeaturesReply) m); if (state.hsState.equals(HandshakeState.HELLO)) { sendFeatureReplyConfiguration(); + state.featuresReply = (OFFeaturesReply) m; state.hsState = HandshakeState.FEATURES_REPLY; // uncomment to enable "dumb" switches like cbench // state.hsState = HandshakeState.READY; // addSwitch(sw); } else { // return results to rest api caller + sw.setFeaturesReply((OFFeaturesReply) m); sw.deliverOFFeaturesReply(m); } break; @@ -1036,14 +1083,15 @@ public class Controller implements IFloodlightProviderService, state.firstRoleReplyReceived = true; sw.deliverRoleRequestNotSupported(error.getXid()); synchronized(roleChanger) { - if (sw.role == null && Controller.this.role==Role.SLAVE) { + if (sw.getRole() == null && + Controller.this.role==Role.SLAVE) { // the switch doesn't understand role request // messages and the current controller role is // slave. We need to disconnect the switch. // @see RoleChanger for rationale sw.getChannel().close(); } - else if (sw.role == null) { + else if (sw.getRole() == null) { // Controller's role is master: add to // active // TODO: check if clearing flow table is @@ -1090,9 +1138,10 @@ public class Controller implements IFloodlightProviderService, String em = "Unexpected STATS_REPLY from " + sw; throw new SwitchStateException(em); } - sw.deliverStatisticsReply(m); - if (sw.hasAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE)) { - processSwitchDescReply(); + if (sw == null) { + processSwitchDescReply((OFStatisticsReply) m); + } else { + sw.deliverStatisticsReply(m); } break; case PORT_STATUS: @@ -1106,41 +1155,44 @@ public class Controller implements IFloodlightProviderService, } if (shouldHandleMessage) { - sw.getListenerReadLock().lock(); - try { - if (sw.isConnected()) { - if (!state.hsState.equals(HandshakeState.READY)) { - log.debug("Ignoring message type {} received " + - "from switch {} before switch is " + - "fully configured.", m.getType(), sw); - } - // Check if the controller is in the slave role for the - // switch. If it is, then don't dispatch the message to - // the listeners. - // TODO: Should we dispatch messages that we expect to - // receive when we're in the slave role, e.g. port - // status messages? Since we're "hiding" switches from - // the listeners when we're in the slave role, then it - // seems a little weird to dispatch port status messages - // to them. On the other hand there might be special - // modules that care about all of the connected switches - // and would like to receive port status notifications. - else if (sw.getRole() == Role.SLAVE) { - // Don't log message if it's a port status message - // since we expect to receive those from the switch - // and don't want to emit spurious messages. - if (m.getType() != OFType.PORT_STATUS) { - log.debug("Ignoring message type {} received " + - "from switch {} while in the slave role.", - m.getType(), sw); + // WARNING: sw is null if handshake is not complete + if (!state.hsState.equals(HandshakeState.READY)) { + log.debug("Ignoring message type {} received " + + "from switch {} before switch is " + + "fully configured.", m.getType(), sw); + } else { + sw.getListenerReadLock().lock(); + try { + + if (sw.isConnected()) { + // Check if the controller is in the slave role for the + // switch. If it is, then don't dispatch the message to + // the listeners. + // TODO: Should we dispatch messages that we expect to + // receive when we're in the slave role, e.g. port + // status messages? Since we're "hiding" switches from + // the listeners when we're in the slave role, then it + // seems a little weird to dispatch port status messages + // to them. On the other hand there might be special + // modules that care about all of the connected switches + // and would like to receive port status notifications. + if (sw.getRole() == Role.SLAVE) { + // Don't log message if it's a port status message + // since we expect to receive those from the switch + // and don't want to emit spurious messages. + if (m.getType() != OFType.PORT_STATUS) { + log.debug("Ignoring message type {} received " + + "from switch {} while in the slave role.", + m.getType(), sw); + } + } else { + handleMessage(sw, m, null); } - } else { - handleMessage(sw, m, null); } } - } - finally { - sw.getListenerReadLock().unlock(); + finally { + sw.getListenerReadLock().unlock(); + } } } } @@ -1390,7 +1442,7 @@ public class Controller implements IFloodlightProviderService, protected void addSwitch(IOFSwitch sw, boolean shouldClearFlowMods) { // TODO: is it safe to modify the HashMap without holding // the old switch's lock? - OFSwitchImpl oldSw = (OFSwitchImpl) this.activeSwitches.put(sw.getId(), sw); + IOFSwitch oldSw = this.activeSwitches.put(sw.getId(), sw); if (sw == oldSw) { // Note == for object equality, not .equals for value log.info("New add switch for pre-existing switch {}", sw); @@ -1854,8 +1906,11 @@ public class Controller implements IFloodlightProviderService, IOFMessageListener>>(); this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>(); this.haListeners = new CopyOnWriteArraySet<IHAListener>(); + this.switchBindingMap = + new ConcurrentHashMap<String, IOFSwitchDriver>(); + this.switchDescSortedList = new ArrayList<String>(); this.activeSwitches = new ConcurrentHashMap<Long, IOFSwitch>(); - this.connectedSwitches = new HashSet<OFSwitchImpl>(); + this.connectedSwitches = new HashSet<IOFSwitch>(); this.controllerNodeIPsCache = new HashMap<String, String>(); this.updates = new LinkedBlockingQueue<IUpdate>(); this.factory = new BasicFactory(); @@ -2050,4 +2105,29 @@ public class Controller implements IFloodlightProviderService, public boolean getAlwaysClearFlowsOnSwAdd() { return this.alwaysClearFlowsOnSwAdd; } + + @Override + public void addOFSwitchDriver(String description, IOFSwitchDriver driver) { + IOFSwitchDriver existingDriver = switchBindingMap.get(description); + if (existingDriver != null) { + log.warn("Failed to add OFSwitch driver for {}, " + + "already registered", description); + return; + } + switchBindingMap.put(description, driver); + + // Sort so we match the longest string first + int index = -1; + for (String desc : switchDescSortedList) { + if (description.compareTo(desc) < 0) { + index = switchDescSortedList.indexOf(desc); + switchDescSortedList.add(index, description); + break; + } + } + if (index == -1) { // append to list + switchDescSortedList.add(description); + } + } + } diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java index ad5a3772fa6e47ae6f1356d93455d597b1a36530..9a1f071f849569afb930b02d2728699878c489f3 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java +++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java @@ -17,6 +17,9 @@ package net.floodlightcontroller.core.internal; +import org.openflow.protocol.OFFeaturesReply; +import org.openflow.protocol.statistics.OFDescriptionStatistics; + /** * Wrapper class to hold state for the OpenFlow switch connection * @author readams @@ -53,6 +56,10 @@ class OFChannelState { protected volatile HandshakeState hsState = HandshakeState.START; protected boolean hasGetConfigReply = false; protected boolean hasDescription = false; + protected boolean switchBindingDone = false; + + protected OFFeaturesReply featuresReply = null; + protected OFDescriptionStatistics description = null; // The firstRoleReplyRecevied flag indicates if we have received the // first role reply message on this connection (in response to the diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java index 83fc182dc2bb3af03283fdc72a9229dd4f3458e5..0909709c2c5460c51f20bd87a0246e760b655d3f 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java +++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java @@ -129,12 +129,12 @@ public class OFSwitchImpl implements IOFSwitch { protected long datapathId; public static IOFSwitchFeatures switchFeatures; - protected static final ThreadLocal<Map<OFSwitchImpl,List<OFMessage>>> local_msg_buffer = - new ThreadLocal<Map<OFSwitchImpl,List<OFMessage>>>() { - @Override - protected Map<OFSwitchImpl,List<OFMessage>> initialValue() { - return new HashMap<OFSwitchImpl,List<OFMessage>>(); - } + protected static final ThreadLocal<Map<IOFSwitch,List<OFMessage>>> local_msg_buffer = + new ThreadLocal<Map<IOFSwitch,List<OFMessage>>>() { + @Override + protected Map<IOFSwitch,List<OFMessage>> initialValue() { + return new HashMap<IOFSwitch,List<OFMessage>>(); + } }; // for managing our map sizes @@ -214,7 +214,7 @@ public class OFSwitchImpl implements IOFSwitch { @Override public void write(OFMessage m, FloodlightContext bc) throws IOException { - Map<OFSwitchImpl,List<OFMessage>> msg_buffer_map = local_msg_buffer.get(); + Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get(); List<OFMessage> msg_buffer = msg_buffer_map.get(this); if (msg_buffer == null) { msg_buffer = new ArrayList<OFMessage>(); @@ -569,7 +569,7 @@ public class OFSwitchImpl implements IOFSwitch { @Override public void flush() { - Map<OFSwitchImpl,List<OFMessage>> msg_buffer_map = local_msg_buffer.get(); + Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get(); List<OFMessage> msglist = msg_buffer_map.get(this); if ((msglist != null) && (msglist.size() > 0)) { try { @@ -583,8 +583,8 @@ public class OFSwitchImpl implements IOFSwitch { } public static void flush_all() { - Map<OFSwitchImpl,List<OFMessage>> msg_buffer_map = local_msg_buffer.get(); - for (OFSwitchImpl sw : msg_buffer_map.keySet()) { + Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get(); + for (IOFSwitch sw : msg_buffer_map.keySet()) { sw.flush(); } } @@ -634,7 +634,7 @@ public class OFSwitchImpl implements IOFSwitch { * RoleChanger can check for timeouts. * @return transaction id of the role request message that was sent */ - protected int sendNxRoleRequest(Role role, long cookie) + public int sendNxRoleRequest(Role role, long cookie) throws IOException { synchronized(pendingRoleRequests) { // Convert the role enum to the appropriate integer constant used @@ -713,7 +713,7 @@ public class OFSwitchImpl implements IOFSwitch { explanation="The switch sent an unexpected HA role reply", recommendation=HA_CHECK_SWITCH) }) - protected void deliverRoleReply(int xid, Role role) { + public void deliverRoleReply(int xid, Role role) { synchronized(pendingRoleRequests) { PendingRoleRequestEntry head = pendingRoleRequests.poll(); if (head == null) { @@ -755,7 +755,7 @@ public class OFSwitchImpl implements IOFSwitch { * @param xid * @return */ - protected boolean checkFirstPendingRoleRequestXid (int xid) { + public boolean checkFirstPendingRoleRequestXid (int xid) { synchronized(pendingRoleRequests) { PendingRoleRequestEntry head = pendingRoleRequests.peek(); if (head == null) @@ -771,7 +771,7 @@ public class OFSwitchImpl implements IOFSwitch { * @param cookie * @return */ - protected boolean checkFirstPendingRoleRequestCookie(long cookie) { + public boolean checkFirstPendingRoleRequestCookie(long cookie) { synchronized(pendingRoleRequests) { PendingRoleRequestEntry head = pendingRoleRequests.peek(); if (head == null) @@ -788,7 +788,7 @@ public class OFSwitchImpl implements IOFSwitch { * Otherwise we ignore it. * @param xid */ - protected void deliverRoleRequestNotSupported(int xid) { + public void deliverRoleRequestNotSupported(int xid) { synchronized(pendingRoleRequests) { PendingRoleRequestEntry head = pendingRoleRequests.poll(); this.role = null; @@ -857,4 +857,10 @@ public class OFSwitchImpl implements IOFSwitch { public byte getTables() { return tables; } + + + @Override + public void setFloodlightProvider(Controller controller) { + floodlightProvider = controller; + } } diff --git a/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java b/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java index 6378136e9f5022f55b10db866a497d5484c2f3ec..008e54232cfbe0bf2dd47e20f3690b11d57ad42e 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java +++ b/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java @@ -133,12 +133,12 @@ public class RoleChanger { TIMEOUT } // The set of switches to work on - public Collection<OFSwitchImpl> switches; + public Collection<IOFSwitch> switches; public Role role; public Type type; // the time when the task should run as nanoTime() public long deadline; - public RoleChangeTask(Collection<OFSwitchImpl> switches, Role role, long deadline) { + public RoleChangeTask(Collection<IOFSwitch> switches, Role role, long deadline) { this.switches = switches; this.role = role; this.type = Type.REQUEST; @@ -209,14 +209,14 @@ public class RoleChanger { } - public synchronized void submitRequest(Collection<OFSwitchImpl> switches, Role role) { + public synchronized void submitRequest(Collection<IOFSwitch> switches, Role role) { long deadline = System.nanoTime(); // Grrr. stupid DelayQueue. Make sre we have at least 10ms between // role request messages. if (deadline - lastSubmitTime < 10 * 1000*1000) deadline = lastSubmitTime + 10 * 1000*1000; // make a copy of the list - ArrayList<OFSwitchImpl> switches_copy = new ArrayList<OFSwitchImpl>(switches); + ArrayList<IOFSwitch> switches_copy = new ArrayList<IOFSwitch>(switches); RoleChangeTask req = new RoleChangeTask(switches_copy, role, deadline); pendingTasks.put(req); lastSubmitTime = deadline; @@ -237,7 +237,7 @@ public class RoleChanger { explanation="An I/O error occurred while attempting to change " + "the switch HA role.", recommendation=LogMessageDoc.CHECK_SWITCH) - protected void sendRoleRequest(Collection<OFSwitchImpl> switches, + protected void sendRoleRequest(Collection<IOFSwitch> switches, Role role, long cookie) { // There are three cases to consider: // @@ -267,9 +267,9 @@ public class RoleChanger { // controller in its list of controllers. Eventually (hopefully, if // things are configured correctly) it will walk down its list of // controllers and connect to the current master controller. - Iterator<OFSwitchImpl> iter = switches.iterator(); + Iterator<IOFSwitch> iter = switches.iterator(); while(iter.hasNext()) { - OFSwitchImpl sw = iter.next(); + IOFSwitch sw = iter.next(); try { Boolean supportsNxRole = (Boolean) sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE); @@ -308,9 +308,9 @@ public class RoleChanger { explanation="Timed out waiting for the switch to respond to " + "a request to change the HA role.", recommendation=LogMessageDoc.CHECK_SWITCH) - protected void verifyRoleReplyReceived(Collection<OFSwitchImpl> switches, + protected void verifyRoleReplyReceived(Collection<IOFSwitch> switches, long cookie) { - for (OFSwitchImpl sw: switches) { + for (IOFSwitch sw: switches) { if (sw.checkFirstPendingRoleRequestCookie(cookie)) { sw.getChannel().close(); log.warn("Timeout while waiting for role reply from switch {}." diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java index ad29a947fbed2a3af94e24259fe58701f7c5e778..e161825a6ad5bea2c23732c3f898d03f25fcb0fe 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java @@ -97,9 +97,13 @@ public interface IDeviceService extends IFloodlightService { * the given source device. The source device is important since * there could be ambiguity in the destination device without the * attachment point information. + * Search for a device in a given entity class. This is the same as + * the lookup process for destination devices. * - * @param source the source device. The returned destination will be - * in the same entity class as the source. + * Only the key fields as defined by the reference entity class will + * be important in this search. All key fields MUST be supplied. + * + * @param entityClass The entity class in which to perform the lookup. * @param macAddress The MAC address for the destination * @param vlan the VLAN if available * @param ipv4Address The IP address if available. @@ -109,10 +113,10 @@ public interface IDeviceService extends IFloodlightService { * @throws IllegalArgumentException if not all key fields of the * source's {@link IEntityClass} are specified. */ - public IDevice findDestDevice(IDevice source, - long macAddress, Short vlan, - Integer ipv4Address) - throws IllegalArgumentException; + public IDevice findClassDevice(IEntityClass entityClass, + long macAddress, Short vlan, + Integer ipv4Address) + throws IllegalArgumentException; /** * Get an unmodifiable collection view over all devices currently known. @@ -158,14 +162,13 @@ public interface IDeviceService extends IFloodlightService { /** * Find devices that match the provided query. Only the index for - * the class of the specified reference device will be searched. + * the specified class will be searched. * Any fields that are null will not be included in the query. If * there is an index for the query, then it will be performed * efficiently using the index. Otherwise, there will be a full scan * of the device list. * - * @param reference The reference device to refer to when finding - * entity classes. + * @param entityClass The entity class in which to perform the query * @param macAddress The MAC address * @param vlan the VLAN * @param ipv4Address the ipv4 address @@ -175,7 +178,7 @@ public interface IDeviceService extends IFloodlightService { * @see IDeviceService#queryClassDevices(Long, * Short, Integer, Long, Integer) */ - public Iterator<? extends IDevice> queryClassDevices(IDevice reference, + public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass, Long macAddress, Short vlan, Integer ipv4Address, diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java index 033d0c11e5c824db6da6fd8a0b64ece435fdb7fe..9f836b1c8c6d7b162d693da0dfc8093dbd3fd82c 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java @@ -345,7 +345,7 @@ IFlowReconcileListener, IInfoProvider, IHAListener { } @Override - public IDevice findDestDevice(IDevice source, long macAddress, + public IDevice findClassDevice(IEntityClass entityClass, long macAddress, Short vlan, Integer ipv4Address) throws IllegalArgumentException { if (vlan != null && vlan.shortValue() <= 0) @@ -354,13 +354,13 @@ IFlowReconcileListener, IInfoProvider, IHAListener { ipv4Address = null; Entity e = new Entity(macAddress, vlan, ipv4Address, null, null, null); - if (source == null || - !allKeyFieldsPresent(e, source.getEntityClass().getKeyFields())) { + if (entityClass == null || + !allKeyFieldsPresent(e, entityClass.getKeyFields())) { throw new IllegalArgumentException("Not all key fields and/or " + " no source device specified. Required fields: " + entityClassifier.getKeyFields()); } - return findDestByEntity(source, e); + return findDestByEntity(entityClass, e); } @Override @@ -421,13 +421,12 @@ IFlowReconcileListener, IInfoProvider, IHAListener { } @Override - public Iterator<? extends IDevice> queryClassDevices(IDevice reference, + public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass, Long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort) { - IEntityClass entityClass = reference.getEntityClass(); ArrayList<Iterator<Device>> iterators = new ArrayList<Iterator<Device>>(); ClassState classState = getClassState(entityClass); @@ -604,7 +603,7 @@ IFlowReconcileListener, IInfoProvider, IHAListener { Entity dstEntity = getEntityFromFlowMod(ofm.ofmWithSwDpid, false); Device dstDevice = null; if (dstEntity != null) { - dstDevice = findDestByEntity(srcDevice, dstEntity); + dstDevice = findDestByEntity(srcDevice.getEntityClass(), dstEntity); if (dstDevice != null) fcStore.put(ofm.cntx, CONTEXT_DST_DEVICE, dstDevice); } @@ -769,7 +768,7 @@ IFlowReconcileListener, IInfoProvider, IHAListener { Device dstDevice = null; if (dstEntity != null) { dstDevice = - findDestByEntity(srcDevice, dstEntity); + findDestByEntity(srcDevice.getEntityClass(), dstEntity); if (dstDevice != null) fcStore.put(cntx, CONTEXT_DST_DEVICE, dstDevice); } @@ -980,13 +979,13 @@ IFlowReconcileListener, IInfoProvider, IHAListener { * @param dstEntity the entity to look up * @return an {@link Device} or null if no device is found. */ - protected Device findDestByEntity(IDevice source, + protected Device findDestByEntity(IEntityClass reference, Entity dstEntity) { // Look up the fully-qualified entity to see if it // exists in the primary entity index Long deviceKey = primaryIndex.findByEntity(dstEntity); - + if (deviceKey == null) { // This could happen because: // 1) no destination known, or a broadcast destination @@ -996,7 +995,7 @@ IFlowReconcileListener, IInfoProvider, IHAListener { // For the second case, we'll need to match up the // destination device with the class of the source // device. - ClassState classState = getClassState(source.getEntityClass()); + ClassState classState = getClassState(reference); if (classState.classIndex == null) { return null; } diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowCache.java b/src/main/java/net/floodlightcontroller/flowcache/FlowCache.java new file mode 100644 index 0000000000000000000000000000000000000000..9e3afe548f80d91f783764c066e344afbee0ca77 --- /dev/null +++ b/src/main/java/net/floodlightcontroller/flowcache/FlowCache.java @@ -0,0 +1,87 @@ +package net.floodlightcontroller.flowcache; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.openflow.protocol.OFMatchWithSwDpid; + +import net.floodlightcontroller.core.FloodlightContext; +import net.floodlightcontroller.core.IOFSwitch; +import net.floodlightcontroller.devicemanager.SwitchPort; +import net.floodlightcontroller.core.module.FloodlightModuleContext; +import net.floodlightcontroller.core.module.FloodlightModuleException; +import net.floodlightcontroller.core.module.IFloodlightModule; +import net.floodlightcontroller.core.module.IFloodlightService; + +public class FlowCache implements IFloodlightModule, IFlowCacheService { + + @Override + public void submitFlowCacheQuery(FCQueryObj query) {} + + @Override + public void deleteFlowCacheBySwitch(long switchDpid) {} + + @Override + public void updateFlush() {} + + @Override + public boolean addFlow(String appInstName, OFMatchWithSwDpid ofm, + Long cookie, long srcSwDpid, + short inPort, short priority, byte action) { + return true; + } + + @Override + public boolean addFlow(FloodlightContext cntx, OFMatchWithSwDpid ofm, + Long cookie, SwitchPort swPort, + short priority, byte action) { + return true; + } + + @Override + public boolean moveFlowToDifferentApplInstName(OFMatchReconcile ofMRc) { + return true; + } + + @Override + public void deleteAllFlowsAtASourceSwitch(IOFSwitch sw) {} + + @Override + public void querySwitchFlowTable(long swDpid) {} + + // IFloodlightModule + + @Override + public Collection<Class<? extends IFloodlightService>> getModuleServices() { + Collection<Class<? extends IFloodlightService>> l = + new ArrayList<Class<? extends IFloodlightService>>(); + l.add(IFlowCacheService.class); + return l; + } + + @Override + public Map<Class<? extends IFloodlightService>, IFloodlightService> + getServiceImpls() { + Map<Class<? extends IFloodlightService>, + IFloodlightService> m = + new HashMap<Class<? extends IFloodlightService>, + IFloodlightService>(); + m.put(IFlowCacheService.class, this); + return m; + } + + @Override + public Collection<Class<? extends IFloodlightService>> + getModuleDependencies() { + return null; + } + + @Override + public void init(FloodlightModuleContext context) + throws FloodlightModuleException {} + + @Override + public void startUp(FloodlightModuleContext context) {} +} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java index d5d323d75f3c27da63a4d452cbee78c82aafac84..98f0f88804bebd8f39f3fac5044db84cc4a8dbed 100644 --- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java +++ b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java @@ -60,9 +60,9 @@ public class FlowReconcileManager String controllerPktInCounterName; protected SimpleCounter lastPacketInCounter; - protected static int MAX_SYSTEM_LOAD_PER_SECOND = 50000; + protected static int MAX_SYSTEM_LOAD_PER_SECOND = 10000; /** a minimum flow reconcile rate so that it won't stave */ - protected static int MIN_FLOW_RECONCILE_PER_SECOND = 1000; + protected static int MIN_FLOW_RECONCILE_PER_SECOND = 200; /** once per second */ protected static int FLOW_RECONCILE_DELAY_MILLISEC = 10; @@ -251,6 +251,9 @@ public class FlowReconcileManager packetInName); } + protected void updateFlush() { + // No-OP + } /** * Feed the flows into the flow reconciliation pipeline. * @return true if more flows to be reconciled @@ -309,6 +312,8 @@ public class FlowReconcileManager } } flowReconcileThreadRunCount++; + // Flush the flowCache counters. + updateFlush(); } else { if (logger.isTraceEnabled()) { logger.trace("No flow to be reconciled."); diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowCacheService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowCacheService.java index 8e44ed3303d054e78b6e40107f7ea0fbeb1ac2a5..4082ef6f982ae07c6f05a75d980b31df7cb27492 100644 --- a/src/main/java/net/floodlightcontroller/flowcache/IFlowCacheService.java +++ b/src/main/java/net/floodlightcontroller/flowcache/IFlowCacheService.java @@ -84,15 +84,6 @@ public interface IFlowCacheService extends IFloodlightService { */ public void submitFlowCacheQuery(FCQueryObj query); - /** - * Deactivates all flows in the flow cache for which the source switch - * matches the given switchDpid. Note that the flows are NOT deleted - * from the cache. - * - * @param switchDpid Data-path identifier of the source switch - */ - public void deactivateFlowCacheBySwitch(long switchDpid); - /** * Deletes all flows in the flow cache for which the source switch * matches the given switchDpid. @@ -101,6 +92,12 @@ public interface IFlowCacheService extends IFloodlightService { */ public void deleteFlowCacheBySwitch(long switchDpid); + /** + * Flush Local Counter Updates + * + */ + public void updateFlush(); + /** * Add a flow to the flow-cache - called when a flow-mod is about to be * written to a set of switches. If it returns false then it should not diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java index be71dd1c4e774be390438a59db7489736c38d962..45e02915901cb759c3dd6b76efb439e4e14e344d 100644 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java +++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java @@ -127,6 +127,10 @@ IFloodlightModule, IInfoProvider, IHAListener { protected static Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class); // Names of table/fields for links in the storage API + private static final String TOPOLOGY_TABLE_NAME = "controller_topologyconfig"; + private static final String TOPOLOGY_ID = "id"; + private static final String TOPOLOGY_AUTOPORTFAST = "autoportfast"; + private static final String LINK_TABLE_NAME = "controller_link"; private static final String LINK_ID = "id"; private static final String LINK_SRC_SWITCH = "src_switch_id"; @@ -194,7 +198,8 @@ IFloodlightModule, IInfoProvider, IHAListener { * Flag to indicate if automatic port fast is enabled or not. * Default is set to false -- Initialized in the init method as well. */ - boolean autoPortFastFeature = false; + public final boolean AUTOPORTFAST_DEFAULT= false; + boolean autoPortFastFeature = AUTOPORTFAST_DEFAULT; /** * Map from link to the most recent time it was verified functioning @@ -1723,6 +1728,12 @@ IFloodlightModule, IInfoProvider, IHAListener { @Override public void rowsModified(String tableName, Set<Object> rowKeys) { + + if (tableName.equals(TOPOLOGY_TABLE_NAME)) { + readTopologyConfigFromStorage(); + return; + } + Map<Long, IOFSwitch> switches = floodlightProvider.getSwitches(); ArrayList<IOFSwitch> updated_switches = new ArrayList<IOFSwitch>(); for(Object key: rowKeys) { @@ -1782,7 +1793,9 @@ IFloodlightModule, IInfoProvider, IHAListener { @Override public void rowsDeleted(String tableName, Set<Object> rowKeys) { - // Ignore delete events, the switch delete will do the right thing on it's own + // Ignore delete events, the switch delete will do the + // right thing on it's own. + readTopologyConfigFromStorage(); } // IFloodlightModule classes @@ -1882,12 +1895,17 @@ IFloodlightModule, IInfoProvider, IHAListener { return; } + storageSource.createTable(TOPOLOGY_TABLE_NAME, null); + storageSource.setTablePrimaryKeyName(TOPOLOGY_TABLE_NAME, TOPOLOGY_ID); + readTopologyConfigFromStorage(); + storageSource.createTable(LINK_TABLE_NAME, null); storageSource.setTablePrimaryKeyName(LINK_TABLE_NAME, LINK_ID); storageSource.deleteMatchingRows(LINK_TABLE_NAME, null); // Register for storage updates for the switch table try { storageSource.addListener(SWITCH_CONFIG_TABLE_NAME, this); + storageSource.addListener(TOPOLOGY_TABLE_NAME, this); } catch (StorageException ex) { log.error("Error in installing listener for " + "switch table {}", SWITCH_CONFIG_TABLE_NAME); @@ -2068,6 +2086,7 @@ IFloodlightModule, IInfoProvider, IHAListener { "to HA change from SLAVE->MASTER"); } clearAllLinks(); + readTopologyConfigFromStorage(); log.debug("Role Change to Master: Rescheduling discovery task."); discoveryTask.reschedule(1, TimeUnit.MICROSECONDS); } @@ -2103,4 +2122,21 @@ IFloodlightModule, IInfoProvider, IHAListener { public void setAutoPortFastFeature(boolean autoPortFastFeature) { this.autoPortFastFeature = autoPortFastFeature; } + + public void readTopologyConfigFromStorage() { + IResultSet topologyResult = storageSource.executeQuery(TOPOLOGY_TABLE_NAME, + null, null, null); + + if (topologyResult.next()) { + boolean apf = topologyResult.getBoolean(TOPOLOGY_AUTOPORTFAST); + autoPortFastFeature = apf; + } else { + this.autoPortFastFeature = AUTOPORTFAST_DEFAULT; + } + + if (autoPortFastFeature) + log.info("Setting autoportfast feature to ON"); + else + log.info("Setting autoportfast feature to OFF"); + } } diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java index 85ac6b8446eecb1594e861535b348fb8f57a00e4..752c7f82cb1604fe6480eb12d76b7ee60418d967 100644 --- a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java +++ b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java @@ -72,19 +72,19 @@ public class TopologyInstance { this.blockedPorts = new HashSet<NodePortTuple>(); this.blockedLinks = new HashSet<Link>(); } - + public TopologyInstance(Map<Long, Set<Short>> switchPorts, Map<NodePortTuple, Set<Link>> switchPortLinks) { this.switches = new HashSet<Long>(switchPorts.keySet()); this.switchPorts = new HashMap<Long, Set<Short>>(switchPorts); this.switchPortLinks = new HashMap<NodePortTuple, - Set<Link>>(switchPortLinks); + Set<Link>>(switchPortLinks); this.broadcastDomainPorts = new HashSet<NodePortTuple>(); this.tunnelPorts = new HashSet<NodePortTuple>(); this.blockedPorts = new HashSet<NodePortTuple>(); this.blockedLinks = new HashSet<Link>(); - + clusters = new HashSet<Cluster>(); switchClusterMap = new HashMap<Long, Cluster>(); } @@ -147,18 +147,20 @@ public class TopologyInstance { calculateBroadcastNodePortsInClusters(); // Step 4. print topology. - // printTopology(); + printTopology(); } public void printTopology() { - log.trace("-----------------------------------------------"); - log.trace("Links: {}",this.switchPortLinks); - log.trace("broadcastDomainPorts: {}", broadcastDomainPorts); - log.trace("tunnelPorts: {}", tunnelPorts); - log.trace("clusters: {}", clusters); - log.trace("destinationRootedTrees: {}", destinationRootedTrees); - log.trace("clusterBroadcastNodePorts: {}", clusterBroadcastNodePorts); - log.trace("-----------------------------------------------"); + if (log.isTraceEnabled()) { + log.trace("-----------------------------------------------"); + log.trace("Links: {}",this.switchPortLinks); + log.trace("broadcastDomainPorts: {}", broadcastDomainPorts); + log.trace("tunnelPorts: {}", tunnelPorts); + log.trace("clusters: {}", clusters); + log.trace("destinationRootedTrees: {}", destinationRootedTrees); + log.trace("clusterBroadcastNodePorts: {}", clusterBroadcastNodePorts); + log.trace("-----------------------------------------------"); + } } protected void addLinksToOpenflowDomains() { @@ -257,6 +259,8 @@ public class TopologyInstance { ClusterDFS currDFS = dfsList.get(currSw); // Get all the links corresponding to this switch + Set<Long> nodesInMyCluster = new HashSet<Long>(); + Set<Long> myCurrSet = new HashSet<Long>(); //Assign the DFS object with right values. currDFS.setVisited(true); @@ -296,13 +300,16 @@ public class TopologyInstance { } else if (!dstDFS.isVisited()) { // make a DFS visit currIndex = dfsTraverse(currDFS.getDfsIndex(), currIndex, dstSw, - dfsList, currSet); + dfsList, myCurrSet); if (currIndex < 0) return -1; // update lowpoint after the visit if (dstDFS.getLowpoint() < currDFS.getLowpoint()) currDFS.setLowpoint(dstDFS.getLowpoint()); + + nodesInMyCluster.addAll(myCurrSet); + myCurrSet.clear(); } // else, it is a node already visited with a higher // dfs index, just ignore. @@ -310,8 +317,8 @@ public class TopologyInstance { } } - // Add current node to currSet. - currSet.add(currSw); + nodesInMyCluster.add(currSw); + currSet.addAll(nodesInMyCluster); // Cluster computation. // If the node's lowpoint is greater than its parent's DFS index, @@ -431,9 +438,32 @@ public class TopologyInstance { public int compareTo(NodeDist o) { if (o.dist == this.dist) { - return (int)(o.node - this.node); + return (int)(this.node - o.node); } - return o.dist - this.dist; + return this.dist - o.dist; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + NodeDist other = (NodeDist) obj; + if (!getOuterType().equals(other.getOuterType())) + return false; + if (node == null) { + if (other.node != null) + return false; + } else if (!node.equals(other.node)) + return false; + return true; + } + + private TopologyInstance getOuterType() { + return TopologyInstance.this; } } @@ -465,13 +495,15 @@ public class TopologyInstance { for (Link link: c.links.get(cnode)) { Long neighbor; - + if (isDstRooted == true) neighbor = link.getSrc(); else neighbor = link.getDst(); - + // links directed toward cnode will result in this condition - // if (neighbor == cnode) continue; - + if (neighbor.equals(cnode)) continue; + + if (seen.containsKey(neighbor)) continue; + if (linkCost == null || linkCost.get(link)==null) w = 1; else w = linkCost.get(link); @@ -480,7 +512,13 @@ public class TopologyInstance { cost.put(neighbor, ndist); nexthoplinks.put(neighbor, link); //nexthopnodes.put(neighbor, cnode); - nodeq.add(new NodeDist(neighbor, ndist)); + NodeDist ndTemp = new NodeDist(neighbor, ndist); + // Remove an object that's already in there. + // Note that the comparison is based on only the node id, + // and not node id and distance. + nodeq.remove(ndTemp); + // add the current object to the queue. + nodeq.add(ndTemp); } } } @@ -744,7 +782,8 @@ public class TopologyInstance { public NodePortTuple getIncomingSwitchPort(long src, short srcPort, long dst, short dstPort) { - // Use this function to reinject traffic from a different port if needed. + // Use this function to reinject traffic from a + // different port if needed. return new NodePortTuple(src, srcPort); } @@ -768,8 +807,8 @@ public class TopologyInstance { } public NodePortTuple - getAllowedOutgoingBroadcastPort(long src, short srcPort, long dst, - short dstPort) { + getAllowedOutgoingBroadcastPort(long src, short srcPort, long dst, + short dstPort) { // TODO Auto-generated method stub return null; } @@ -780,3 +819,4 @@ public class TopologyInstance { return null; } } + diff --git a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule index 0225a2b25a00e0e13c491d4af6de790db232a072..07985a1268a9a66755c1745fc9696c9272c290ec 100644 --- a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule +++ b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule @@ -4,6 +4,7 @@ net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager net.floodlightcontroller.topology.TopologyManager net.floodlightcontroller.forwarding.Forwarding +net.floodlightcontroller.flowcache.FlowCache net.floodlightcontroller.flowcache.FlowReconcileManager net.floodlightcontroller.core.OFMessageFilterManager net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher diff --git a/src/main/resources/floodlightdefault.properties b/src/main/resources/floodlightdefault.properties index 56d42eb82b94eed17ac16d73f20f6e9bbf34dff0..5bb2e28832f44fd7c4db3984002c102f71bc7933 100644 --- a/src/main/resources/floodlightdefault.properties +++ b/src/main/resources/floodlightdefault.properties @@ -2,9 +2,14 @@ floodlight.modules = net.floodlightcontroller.storage.memory.MemoryStorageSource net.floodlightcontroller.core.FloodlightProvider,\ net.floodlightcontroller.threadpool.ThreadPool,\ net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\ +net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier,\ net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\ net.floodlightcontroller.firewall.Firewall,\ net.floodlightcontroller.forwarding.Forwarding,\ +net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager, \ +net.floodlightcontroller.topology.TopologyManager, \ +net.floodlightcontroller.flowcache.FlowCache, \ +net.floodlightcontroller.flowcache.FlowReconcileManager, \ net.floodlightcontroller.jython.JythonDebugInterface,\ net.floodlightcontroller.counter.CounterStore,\ net.floodlightcontroller.perfmon.PktInProcessingTime,\ diff --git a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java index 899f57834cfcd777d4c1a08104c3871822e8bd33..177c46dbb5bcd534d8f4426b4a24a0be012c5d44 100644 --- a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java +++ b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java @@ -21,7 +21,6 @@ import static org.easymock.EasyMock.*; import java.util.ArrayList; import java.util.Collection; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -39,6 +38,7 @@ import net.floodlightcontroller.core.IOFMessageFilterManagerService; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IListener.Command; import net.floodlightcontroller.core.IOFSwitch; +import net.floodlightcontroller.core.IOFSwitchDriver; import net.floodlightcontroller.core.IOFSwitchListener; import net.floodlightcontroller.core.OFMessageFilterManager; import net.floodlightcontroller.core.internal.Controller.IUpdate; @@ -64,6 +64,7 @@ import net.floodlightcontroller.test.FloodlightTestCase; import net.floodlightcontroller.threadpool.IThreadPoolService; import org.easymock.Capture; +import org.easymock.EasyMock; import org.jboss.netty.channel.Channel; import org.junit.Test; import org.openflow.protocol.OFError; @@ -83,6 +84,7 @@ import org.openflow.protocol.OFVendor; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; import org.openflow.protocol.factory.BasicFactory; +import org.openflow.protocol.statistics.OFDescriptionStatistics; import org.openflow.protocol.statistics.OFFlowStatisticsReply; import org.openflow.protocol.statistics.OFStatistics; import org.openflow.protocol.statistics.OFStatisticsType; @@ -94,7 +96,8 @@ import org.openflow.vendor.nicira.OFRoleReplyVendorData; * * @author David Erickson (daviderickson@cs.stanford.edu) */ -public class ControllerTest extends FloodlightTestCase { +public class ControllerTest extends FloodlightTestCase + implements IOFSwitchDriver { private Controller controller; private MockThreadPoolService tp; @@ -763,42 +766,45 @@ public class ControllerTest extends FloodlightTestCase { public void testCheckSwitchReady() { OFChannelState state = new OFChannelState(); Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state); - chdlr.sw = createMock(OFSwitchImpl.class); + Channel channel = createMock(Channel.class); + chdlr.channel = channel; + OFDescriptionStatistics desc = new OFDescriptionStatistics(); + OFFeaturesReply featuresReply = new OFFeaturesReply(); + featuresReply.setPorts(new ArrayList<OFPhysicalPort>()); // Wrong current state // Should not go to READY state.hsState = OFChannelState.HandshakeState.HELLO; - state.hasDescription = true; - state.hasGetConfigReply = true; - replay(chdlr.sw); // nothing called on sw + state.hasDescription = false; + state.hasGetConfigReply = false; + state.switchBindingDone = false; + expect(channel.getRemoteAddress()).andReturn(null).anyTimes(); + expect(channel.write(EasyMock.anyObject())).andReturn(null).anyTimes(); + replay(channel); chdlr.checkSwitchReady(); - verify(chdlr.sw); assertSame(OFChannelState.HandshakeState.HELLO, state.hsState); - reset(chdlr.sw); // Have only config reply state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY; state.hasDescription = false; state.hasGetConfigReply = true; - replay(chdlr.sw); + state.featuresReply = featuresReply; + state.switchBindingDone = false; chdlr.checkSwitchReady(); - verify(chdlr.sw); assertSame(OFChannelState.HandshakeState.FEATURES_REPLY, state.hsState); assertTrue(controller.connectedSwitches.isEmpty()); assertTrue(controller.activeSwitches.isEmpty()); - reset(chdlr.sw); // Have only desc reply state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY; state.hasDescription = true; + state.description = desc; state.hasGetConfigReply = false; - replay(chdlr.sw); + state.switchBindingDone = false; chdlr.checkSwitchReady(); - verify(chdlr.sw); assertSame(OFChannelState.HandshakeState.FEATURES_REPLY, state.hsState); assertTrue(controller.connectedSwitches.isEmpty()); assertTrue(controller.activeSwitches.isEmpty()); - reset(chdlr.sw); ////////////////////////////////////////// // Finally, everything is right. Should advance to READY @@ -806,19 +812,22 @@ public class ControllerTest extends FloodlightTestCase { controller.roleChanger = createMock(RoleChanger.class); state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY; state.hasDescription = true; + state.description = desc; state.hasGetConfigReply = true; + state.featuresReply = featuresReply; + state.switchBindingDone = false; // Role support disabled. Switch should be promoted to active switch // list. - setupSwitchForAddSwitch(chdlr.sw, 0L); - chdlr.sw.clearAllFlowMods(); - replay(controller.roleChanger, chdlr.sw); + // setupSwitchForAddSwitch(chdlr.sw, 0L); + // chdlr.sw.clearAllFlowMods(); + desc.setManufacturerDescription("test vendor"); + replay(controller.roleChanger); chdlr.checkSwitchReady(); - verify(controller.roleChanger, chdlr.sw); + verify(controller.roleChanger); assertSame(OFChannelState.HandshakeState.READY, state.hsState); assertSame(chdlr.sw, controller.activeSwitches.get(0L)); assertTrue(controller.connectedSwitches.contains(chdlr.sw)); assertTrue(state.firstRoleReplyReceived); - reset(chdlr.sw); reset(controller.roleChanger); controller.connectedSwitches.clear(); controller.activeSwitches.clear(); @@ -827,22 +836,77 @@ public class ControllerTest extends FloodlightTestCase { // Role support enabled. state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY; controller.role = Role.MASTER; - Capture<Collection<OFSwitchImpl>> swListCapture = - new Capture<Collection<OFSwitchImpl>>(); + Capture<Collection<IOFSwitch>> swListCapture = + new Capture<Collection<IOFSwitch>>(); controller.roleChanger.submitRequest(capture(swListCapture), same(Role.MASTER)); - replay(controller.roleChanger, chdlr.sw); + replay(controller.roleChanger); chdlr.checkSwitchReady(); - verify(controller.roleChanger, chdlr.sw); + verify(controller.roleChanger); assertSame(OFChannelState.HandshakeState.READY, state.hsState); assertTrue(controller.activeSwitches.isEmpty()); - assertTrue(controller.connectedSwitches.contains(chdlr.sw)); + assertFalse(controller.connectedSwitches.isEmpty()); assertTrue(state.firstRoleReplyReceived); - Collection<OFSwitchImpl> swList = swListCapture.getValue(); + Collection<IOFSwitch> swList = swListCapture.getValue(); assertEquals(1, swList.size()); - assertTrue("swList must contain this switch", swList.contains(chdlr.sw)); + } + + public class TestSwitchClass extends OFSwitchImpl { } + public class Test11SwitchClass extends OFSwitchImpl { + } + + @Test + public void testBindSwitchToDriver() { + controller.addOFSwitchDriver("test", this); + + OFChannelState state = new OFChannelState(); + Controller.OFChannelHandler chdlr = + controller.new OFChannelHandler(state); + OFSwitchImpl sw = new OFSwitchImpl(); + sw.stringId = "1"; + chdlr.sw = sw; + + // Swith should be bound of OFSwitchImpl (default) + state.hsState = OFChannelState.HandshakeState.HELLO; + state.hasDescription = true; + state.hasGetConfigReply = true; + state.switchBindingDone = false; + OFDescriptionStatistics desc = new OFDescriptionStatistics(); + desc.setManufacturerDescription("test switch"); + desc.setHardwareDescription("version 0.9"); + state.description = desc; + OFFeaturesReply featuresReply = new OFFeaturesReply(); + featuresReply.setPorts(new ArrayList<OFPhysicalPort>()); + state.featuresReply = featuresReply; + + chdlr.bindSwitchToDriver(); + assertTrue(chdlr.sw instanceof OFSwitchImpl); + assertTrue(!(chdlr.sw instanceof TestSwitchClass)); + + // Switch should be bound to TestSwitchImpl + chdlr.sw = sw; + state.switchBindingDone = false; + desc.setManufacturerDescription("test1 switch"); + desc.setHardwareDescription("version 1.0"); + state.description = desc; + state.featuresReply = featuresReply; + + chdlr.bindSwitchToDriver(); + assertTrue(chdlr.sw instanceof TestSwitchClass); + + // Switch should be bound to Test11SwitchImpl + chdlr.sw = sw; + state.switchBindingDone = false; + desc.setManufacturerDescription("test11 switch"); + desc.setHardwareDescription("version 1.1"); + state.description = desc; + state.featuresReply = featuresReply; + + chdlr.bindSwitchToDriver(); + assertTrue(chdlr.sw instanceof Test11SwitchClass); + } @Test public void testChannelDisconnected() throws Exception { @@ -935,6 +999,7 @@ public class ControllerTest extends FloodlightTestCase { expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true); chdlr.sw.deliverRoleRequestNotSupported(xid); expect(chdlr.sw.getChannel()).andReturn(ch).anyTimes(); + expect(chdlr.sw.getRole()).andReturn(null).anyTimes(); expect(ch.close()).andReturn(null); replay(ch, chdlr.sw); @@ -955,6 +1020,7 @@ public class ControllerTest extends FloodlightTestCase { expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true); chdlr.sw.deliverRoleRequestNotSupported(xid); expect(chdlr.sw.getChannel()).andReturn(ch).anyTimes(); + expect(chdlr.sw.getRole()).andReturn(null).anyTimes(); expect(ch.close()).andReturn(null); replay(ch, chdlr.sw); @@ -975,6 +1041,7 @@ public class ControllerTest extends FloodlightTestCase { chdlr.sw.deliverRoleRequestNotSupported(xid); setupSwitchForAddSwitch(chdlr.sw, 0L); chdlr.sw.clearAllFlowMods(); + expect(chdlr.sw.getRole()).andReturn(null).anyTimes(); replay(ch, chdlr.sw); chdlr.processOFMessage(msg); @@ -1252,4 +1319,16 @@ public class ControllerTest extends FloodlightTestCase { verifyPortChangedUpdateInQueue(sw); reset(sw); } + + @Override + public IOFSwitch getOFSwitchImpl(OFDescriptionStatistics description) { + String hw_desc = description.getHardwareDescription(); + if (hw_desc.equals("version 1.1")) { + return new Test11SwitchClass(); + } + if (hw_desc.equals("version 1.0")) { + return new TestSwitchClass(); + } + return null; + } } diff --git a/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java b/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java index 991afffc282aef54b03076582dc9cafcef6b1dc6..d7d981449d95d4e934d7610232f8977c5afa025a 100644 --- a/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java +++ b/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java @@ -32,7 +32,7 @@ public class RoleChangerTest { */ @Test public void testSendRoleRequestSlaveNotSupported() { - LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); + LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>(); // a switch that doesn't support role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); @@ -59,7 +59,7 @@ public class RoleChangerTest { */ @Test public void testSendRoleRequestMasterNotSupported() { - LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); + LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>(); // a switch that doesn't support role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); @@ -81,7 +81,7 @@ public class RoleChangerTest { */ @Test public void testSendRoleRequestErrorHandling () throws Exception { - LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); + LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>(); // a switch that supports role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); @@ -108,7 +108,7 @@ public class RoleChangerTest { */ @Test public void testSendRoleRequestSupported() throws Exception { - LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); + LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>(); // a switch that supports role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); @@ -136,7 +136,7 @@ public class RoleChangerTest { @Test public void testVerifyRoleReplyReceived() { - LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); + Collection<IOFSwitch> switches = new LinkedList<IOFSwitch>(); // Add a switch that has received a role reply OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); @@ -164,7 +164,7 @@ public class RoleChangerTest { @Test public void testRoleChangeTask() { @SuppressWarnings("unchecked") - Collection<OFSwitchImpl> switches = + Collection<IOFSwitch> switches = EasyMock.createMock(Collection.class); long now = System.nanoTime(); long dt1 = 10 * 1000*1000*1000L; @@ -186,7 +186,7 @@ public class RoleChangerTest { @Test public void testSubmitRequest() throws Exception { - LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); + LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>(); roleChanger.timeout = 500*1000*1000; // 500 ms // a switch that supports role requests diff --git a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java index e83fc583d53deb296b61432a892163eb6202f99d..301832f6a9400f29f28a0d7c6fa9c871e2ffc449 100644 --- a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java +++ b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java @@ -35,6 +35,7 @@ import net.floodlightcontroller.core.IHAListener; import net.floodlightcontroller.core.IInfoProvider; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; +import net.floodlightcontroller.core.IOFSwitchDriver; import net.floodlightcontroller.core.IOFSwitchFilter; import net.floodlightcontroller.core.IOFSwitchListener; import net.floodlightcontroller.core.IListener.Command; @@ -347,4 +348,11 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro // TODO Auto-generated method stub } + + @Override + public void addOFSwitchDriver(String desc, IOFSwitchDriver driver) { + // TODO Auto-generated method stub + + } + } diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java index e266d4a0a0d464493418de1d65b9244ce82bd381..430a1bdfafbbbe4bcac775af9fb0ed1a99b6cabe 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java @@ -738,7 +738,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { Device result = null; Iterator<? extends IDevice> dstiter = - deviceManager.queryClassDevices(device, null, null, ipaddr, + deviceManager.queryClassDevices(device.getEntityClass(), + null, null, ipaddr, null, null); if (dstiter.hasNext()) { result = (Device)dstiter.next(); @@ -832,10 +833,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase { new SwitchPort(5L, 1)}, d.getAttachmentPoints()); Iterator<? extends IDevice> diter = - deviceManager.queryClassDevices(d, null, null, 1, null, null); + deviceManager.queryClassDevices(d.getEntityClass(), + null, null, 1, null, null); assertTrue(diter.hasNext()); assertEquals(d.getDeviceKey(), diter.next().getDeviceKey()); - diter = deviceManager.queryClassDevices(d, null, null, 2, null, null); + diter = deviceManager.queryClassDevices(d.getEntityClass(), + null, null, 2, null, null); assertTrue(diter.hasNext()); assertEquals(d.getDeviceKey(), diter.next().getDeviceKey()); @@ -851,10 +854,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), new SwitchPort(5L, 1) }, d.getAttachmentPoints()); - diter = deviceManager.queryClassDevices(d, null, null, 2, null, null); + diter = deviceManager.queryClassDevices(d.getEntityClass(), + null, null, 2, null, null); assertTrue(diter.hasNext()); assertEquals(d.getDeviceKey(), diter.next().getDeviceKey()); - diter = deviceManager.queryClassDevices(d, null, null, 1, null, null); + diter = deviceManager.queryClassDevices(d.getEntityClass(), + null, null, 1, null, null); assertFalse(diter.hasNext()); d = deviceManager.findDevice(1L, null, null, null, null); @@ -908,7 +913,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { IDevice r = deviceManager.getDevice(d.getDeviceKey()); assertNull(r); Iterator<? extends IDevice> diter = - deviceManager.queryClassDevices(d, null, null, 1, null, null); + deviceManager.queryClassDevices(d.getEntityClass(), + null, null, 1, null, null); assertFalse(diter.hasNext()); r = deviceManager.findDevice(1L, null, null, null, null); @@ -1299,7 +1305,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.learnDeviceByEntity(entity4); Iterator<? extends IDevice> iter = - deviceManager.queryClassDevices(d, null, + deviceManager.queryClassDevices(d.getEntityClass(), null, (short)1, 1, null, null); int count = 0; while (iter.hasNext()) { @@ -1308,7 +1314,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { } assertEquals(1, count); - iter = deviceManager.queryClassDevices(d, null, + iter = deviceManager.queryClassDevices(d.getEntityClass(), null, (short)3, 3, null, null); count = 0; while (iter.hasNext()) { @@ -1317,7 +1323,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { } assertEquals(1, count); - iter = deviceManager.queryClassDevices(d, null, + iter = deviceManager.queryClassDevices(d.getEntityClass(), null, (short)1, 3, null, null); count = 0; while (iter.hasNext()) { @@ -1327,7 +1333,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEquals(0, count); deviceManager.learnDeviceByEntity(entity5); - iter = deviceManager.queryClassDevices(d, null, + iter = deviceManager.queryClassDevices(d.getEntityClass(), null, (short)4, 3, null, null); count = 0; while (iter.hasNext()) { @@ -1480,15 +1486,15 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // Now look up destination devices - assertEquals(d1, deviceManager.findDestDevice(d2, + assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(), entity1.getMacAddress(), entity1.getVlan(), entity1.getIpv4Address())); - assertEquals(d1, deviceManager.findDestDevice(d2, + assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(), entity1.getMacAddress(), entity1.getVlan(), null)); - assertEquals(null, deviceManager.findDestDevice(d2, + assertEquals(null, deviceManager.findClassDevice(d2.getEntityClass(), entity1.getMacAddress(), (short) -1, 0)); diff --git a/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java b/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java index 042782804e7772b6a805ca00bf6db4fc279820a5..0dcbb357e3c5fa81483f6663422d3654a224a0e5 100644 --- a/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java +++ b/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java @@ -36,7 +36,7 @@ public class FlowReconcileMgrTest extends FloodlightTestCase { OFStatisticsRequest ofStatsRequest; protected int NUM_FLOWS_PER_THREAD = 100; - protected int NUM_THREADS = 100; + protected int NUM_THREADS = 20; @Before public void setUp() throws Exception { @@ -330,7 +330,7 @@ public class FlowReconcileMgrTest extends FloodlightTestCase { flowReconcileMgr.controllerPktInCounterName)) .andReturn(newCnt) .times(1); - long initPktInCount = 10000; + long initPktInCount = 1000; newCnt.increment(currentTime, initPktInCount); replay(counterStore); @@ -338,15 +338,15 @@ public class FlowReconcileMgrTest extends FloodlightTestCase { verify(counterStore); /** Now the lastPacketInCounter has been set. - * lastCounter = 100,000 and newCounter = 300,000, t = 1 second - * packetInRate = 200,000/sec. - * capacity should be 500k - 200k = 300k + * lastCounter = 1,000 and newCounter = 3,000, t = 1 second + * packetInRate = 2,000/sec. + * capacity should be 10k - 2k = 8k */ reset(counterStore); newCnt = (SimpleCounter)SimpleCounter.createCounter( currentTime, CounterType.LONG); currentTime = new Date(currentTime.getTime() + 200); - long nextPktInCount = 30000; + long nextPktInCount = 3000; newCnt.increment(currentTime, nextPktInCount); expect(counterStore.getCounter( @@ -365,17 +365,6 @@ public class FlowReconcileMgrTest extends FloodlightTestCase { assertEquals(expectedCap, capacity); } - private class FlowReconcileWorker implements Runnable { - @Override - public void run() { - OFMatchReconcile ofmRc = new OFMatchReconcile(); - // push large number of flows to be reconciled. - for (int i = 0; i < NUM_FLOWS_PER_THREAD; i++) { - flowReconcileMgr.reconcileFlow(ofmRc); - } - } - } - /** Verify the flows are sent to the reconcile pipeline in order. */ @SuppressWarnings("unchecked") @@ -491,10 +480,21 @@ public class FlowReconcileMgrTest extends FloodlightTestCase { } while (flowReconcileMgr.flowQueue.size() != totalFlows) { Date currTime = new Date(); - assertTrue((currTime.getTime() - startTime.getTime()) < 2000); + assertTrue((currTime.getTime() - startTime.getTime()) < 1000); } // Make sure all flows are in the queue. assertEquals(totalFlows, flowReconcileMgr.flowQueue.size()); } + + private class FlowReconcileWorker implements Runnable { + @Override + public void run() { + OFMatchReconcile ofmRc = new OFMatchReconcile(); + // push large number of flows to be reconciled. + for (int i = 0; i < NUM_FLOWS_PER_THREAD; i++) { + flowReconcileMgr.reconcileFlow(ofmRc); + } + } + } } diff --git a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java index 616d4377c6058d8a79008b2c4dabc3cd9236efe3..d1bcf2b16e89a55bff0469271a74e6c53894c0b2 100644 --- a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java +++ b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java @@ -8,11 +8,14 @@ import java.util.Date; import java.util.List; import java.util.Map; import java.util.concurrent.Future; +import java.util.concurrent.locks.Lock; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IFloodlightProviderService.Role; +import net.floodlightcontroller.core.internal.Controller; +import net.floodlightcontroller.threadpool.IThreadPoolService; import org.jboss.netty.channel.Channel; import org.openflow.protocol.OFFeaturesReply; @@ -346,4 +349,64 @@ public class OFMessageDamperMockSwitch implements IOFSwitch { return 0; } + @Override + public int sendNxRoleRequest(Role role, long cookie) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public boolean checkFirstPendingRoleRequestCookie(long cookie) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void setChannel(Channel channel) { + // TODO Auto-generated method stub + + } + + @Override + public void setFloodlightProvider(Controller controller) { + // TODO Auto-generated method stub + + } + + @Override + public void setThreadPoolService(IThreadPoolService threadPool) { + // TODO Auto-generated method stub + + } + + @Override + public void deliverRoleReply(int xid, Role role) { + // TODO Auto-generated method stub + + } + + @Override + public void deliverRoleRequestNotSupported(int xid) { + // TODO Auto-generated method stub + + } + + @Override + public Lock getListenerReadLock() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean checkFirstPendingRoleRequestXid(int xid) { + // TODO Auto-generated method stub + return false; + } + + @Override + public Lock getListenerWriteLock() { + // TODO Auto-generated method stub + return null; + } + } \ No newline at end of file