/**
* 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 net.floodlightcontroller.core.test;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.HAListenerTypeMarker;
import net.floodlightcontroller.core.HARole;
import net.floodlightcontroller.core.IControllerCompletionListener;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IHAListener;
import net.floodlightcontroller.core.IInfoProvider;
import net.floodlightcontroller.core.IListener.Command;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.RoleInfo;
import net.floodlightcontroller.core.internal.Controller.IUpdate;
import net.floodlightcontroller.core.internal.Controller.ModuleLoaderState;
import net.floodlightcontroller.core.internal.RoleManager;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.core.util.ListenerDispatcher;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFType;
import net.floodlightcontroller.packet.Ethernet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author David Erickson (daviderickson@cs.stanford.edu)
*/
public class MockFloodlightProvider implements IFloodlightModule, IFloodlightProviderService {
private final static Logger log = LoggerFactory.getLogger(MockFloodlightProvider.class);
protected ConcurrentMap<OFType, ListenerDispatcher<OFType,IOFMessageListener>> listeners;
protected ListenerDispatcher<HAListenerTypeMarker, IHAListener> haListeners;
private HARole role;
private final boolean useAsyncUpdates;
private volatile ExecutorService executorService;
private volatile Future<?> mostRecentUpdateFuture;
// paag
private ConcurrentLinkedQueue<IControllerCompletionListener> completionListeners;
/**
*
*/
public MockFloodlightProvider(boolean useAsyncUpdates) {
listeners = new ConcurrentHashMap<OFType, ListenerDispatcher<OFType,
IOFMessageListener>>();
haListeners =
new ListenerDispatcher<HAListenerTypeMarker, IHAListener>();
completionListeners =
new ConcurrentLinkedQueue<IControllerCompletionListener>();
role = null;
this.useAsyncUpdates = useAsyncUpdates;
}
public MockFloodlightProvider() {
this(false);
}
@Override
public synchronized void addOFMessageListener(OFType type,
IOFMessageListener listener) {
ListenerDispatcher<OFType, IOFMessageListener> ldd =
listeners.get(type);
if (ldd == null) {
ldd = new ListenerDispatcher<OFType, IOFMessageListener>();
listeners.put(type, ldd);
}
ldd.addListener(type, listener);
}
@Override
public synchronized void removeOFMessageListener(OFType type,
IOFMessageListener listener) {
ListenerDispatcher<OFType, IOFMessageListener> ldd =
listeners.get(type);
if (ldd != null) {
ldd.removeListener(listener);
}
}
/**
* @return the listeners
*/
@Override
public Map<OFType, List<IOFMessageListener>> getListeners() {
Map<OFType, List<IOFMessageListener>> lers =
new HashMap<OFType, List<IOFMessageListener>>();
for(Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> e :
listeners.entrySet()) {
lers.put(e.getKey(), e.getValue().getOrderedListeners());
}
return Collections.unmodifiableMap(lers);
}
public void clearListeners() {
this.listeners.clear();
}
public void dispatchMessage(IOFSwitch sw, OFMessage msg) {
dispatchMessage(sw, msg, new FloodlightContext());
}
public void dispatchMessage(IOFSwitch sw, OFMessage msg, FloodlightContext bc) {
List<IOFMessageListener> theListeners = listeners.get(msg.getType()).getOrderedListeners();
if (theListeners != null) {
Command result = Command.CONTINUE;
Iterator<IOFMessageListener> it = theListeners.iterator();
if (OFType.PACKET_IN.equals(msg.getType())) {
OFPacketIn pi = (OFPacketIn)msg;
Ethernet eth = new Ethernet();
eth.deserialize(pi.getData(), 0, pi.getData().length);
IFloodlightProviderService.bcStore.put(bc,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
eth);
}
while (it.hasNext() && !Command.STOP.equals(result)) {
result = it.next().receive(sw, msg, bc);
}
}
// paag
for (IControllerCompletionListener listener:completionListeners)
listener.onMessageConsumed(sw, msg, bc);
}
@Override
public void handleOutgoingMessage(IOFSwitch sw, OFMessage m) {
FloodlightContext bc = new FloodlightContext();
List<IOFMessageListener> msgListeners = null;
if (listeners.containsKey(m.getType())) {
msgListeners = listeners.get(m.getType()).getOrderedListeners();
}
if (msgListeners != null) {
for (IOFMessageListener listener : msgListeners) {
if (Command.STOP.equals(listener.receive(sw, m, bc))) {
break;
}
}
}
}
public void handleOutgoingMessages(IOFSwitch sw, List<OFMessage> msglist, FloodlightContext bc) {
for (OFMessage m:msglist) {
handleOutgoingMessage(sw, m);
}
}
@Override
public void run() {
logListeners();
if (useAsyncUpdates)
executorService = Executors.newSingleThreadExecutor();
}
public void shutdown() {
if (executorService != null) {
executorService.shutdownNow();
executorService = null;
mostRecentUpdateFuture = null;
}
}
@Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Collection<Class<? extends IFloodlightService>> services =
new ArrayList<Class<? extends IFloodlightService>>(1);
services.add(IFloodlightProviderService.class);
return services;
}
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService>
getServiceImpls() {
Map<Class<? extends IFloodlightService>,
IFloodlightService> m =
new HashMap<Class<? extends IFloodlightService>,
IFloodlightService>();
m.put(IFloodlightProviderService.class, this);
return m;
}
@Override
public Collection<Class<? extends IFloodlightService>>
getModuleDependencies() {
return null;
}
@Override
public void init(FloodlightModuleContext context) throws FloodlightModuleException {
// do nothing.
}
@Override
public void startUp(FloodlightModuleContext context) {
// do nothing.
}
@Override
public void addInfoProvider(String type, IInfoProvider provider) {
// do nothing.
}
@Override
public void removeInfoProvider(String type, IInfoProvider provider) {
// do nothing.
}
@Override
public Map<String, Object> getControllerInfo(String type) {
// mock up something
Map<String, Object> summary = new HashMap<String, Object>();
summary.put("test-summary-1", 2);
summary.put("test-summary-2", 5);
return summary;
}
@Override
public void addUpdateToQueue(final IUpdate update) {
if (useAsyncUpdates) {
mostRecentUpdateFuture = executorService.submit(new Runnable() {
@Override
public void run() {
update.dispatch();
}
});
} else {
update.dispatch();
}
}
public void waitForUpdates(long timeout, TimeUnit unit) throws InterruptedException {
long timeoutNanos = unit.toNanos(timeout);
long start = System.nanoTime();
for (;;) {
Future<?> future = mostRecentUpdateFuture;
if ((future == null) || future.isDone())
break;
Thread.sleep(100);
long now = System.nanoTime();
if (now > start + timeoutNanos) {
fail("Timeout waiting for update tasks to complete");
}
}
}
@Override
public void addHAListener(IHAListener listener) {
haListeners.addListener(null,listener);
}
@Override
public void removeHAListener(IHAListener listener) {
haListeners.removeListener(listener);
}
@Override
public HARole getRole() {
/* DISABLE THIS CHECK FOR NOW. OTHER UNIT TESTS NEED TO BE UPDATED
* FIRST
if (this.role == null)
throw new IllegalStateException("You need to call setRole on "
+ "MockFloodlightProvider before calling startUp on "
+ "other modules");
*/
return this.role;
}
@Override
public void setRole(HARole role, String roleChangeDescription) {
this.role = role;
}
/**
* Dispatches a new role change notification
* @param oldRole
* @param newRole
*/
public void transitionToActive() {
IUpdate update = new IUpdate() {
@Override
public void dispatch() {
for (IHAListener rl : haListeners.getOrderedListeners()) {
rl.transitionToActive();
}
}
};
addUpdateToQueue(update);
}
@Override
public Map<String, String> getControllerNodeIPs() {
return null;
}
@Override
public long getSystemStartTime() {
return 0;
}
private void logListeners() {
for (Map.Entry<OFType,
ListenerDispatcher<OFType,
IOFMessageListener>> entry
: listeners.entrySet()) {
OFType type = entry.getKey();
ListenerDispatcher<OFType, IOFMessageListener> ldd =
entry.getValue();
StringBuffer sb = new StringBuffer();
sb.append("OFListeners for ");
sb.append(type);
sb.append(": ");
for (IOFMessageListener l : ldd.getOrderedListeners()) {
sb.append(l.getName());
sb.append(",");
}
log.debug(sb.toString());
}
}
@Override
public RoleInfo getRoleInfo() {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, Long> getMemory() {
Map<String, Long> m = new HashMap<String, Long>();
m.put("total", 1000000000L);
m.put("free", 20000000L);
return m;
}
@Override
public Long getUptime() {
return 1000000L;
}
@Override
public void handleMessage(IOFSwitch sw, OFMessage m,
FloodlightContext bContext) {
// do nothing
}
@Override
public RoleManager getRoleManager() {
return null;
}
@Override
public ModuleLoaderState getModuleLoaderState() {
return null;
}
@Override
public String getControllerId() {
return null;
}
// paag
@Override
public void addCompletionListener(IControllerCompletionListener listener) {
completionListeners.add(listener);
}
// paag
@Override
public void removeCompletionListener(IControllerCompletionListener listener) {
completionListeners.remove(listener);
}
}