diff --git a/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java b/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java index df542f03f42c2e6c8a49ab2aa2043e3a85ab8c44..b6d55406202a0b1f1264d866d5f670ef01e2b344 100644 --- a/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java +++ b/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java @@ -66,6 +66,7 @@ public class FloodlightProvider implements IFloodlightModule { dependencies.add(IPktInProcessingTimeService.class); dependencies.add(IRestApiService.class); dependencies.add(ICounterStoreService.class); + dependencies.add(IDebugCounterService.class); dependencies.add(IFlowCacheService.class); dependencies.add(IThreadPoolService.class); return dependencies; diff --git a/src/main/java/net/floodlightcontroller/core/OFSwitchBase.java b/src/main/java/net/floodlightcontroller/core/OFSwitchBase.java index 8fa298ddc3bd96fb260373b0757291725f6833ff..65265ca0caae46d6424d5bc1974ea030c1d8459d 100644 --- a/src/main/java/net/floodlightcontroller/core/OFSwitchBase.java +++ b/src/main/java/net/floodlightcontroller/core/OFSwitchBase.java @@ -231,7 +231,12 @@ public abstract class OFSwitchBase implements IOFSwitch { this.write(msglist); } - private void write(List<OFMessage> msglist) throws IOException { + /** + * Not callable by writers, but allow IOFSwitch implementation to override + * @param msglist + * @throws IOException + */ + public void write(List<OFMessage> msglist) throws IOException { this.channel.write(msglist); } @@ -398,7 +403,7 @@ public abstract class OFSwitchBase implements IOFSwitch { this.iofMsgListenersMap.put(xid, caller); List<OFMessage> msglist = new ArrayList<OFMessage>(1); msglist.add(request); - this.channel.write(msglist); + this.write(msglist); return; } @@ -409,7 +414,7 @@ public abstract class OFSwitchBase implements IOFSwitch { this.statsFutureMap.put(request.getXid(), future); List<OFMessage> msglist = new ArrayList<OFMessage>(1); msglist.add(request); - this.channel.write(msglist); + this.write(msglist); return future; } @@ -518,10 +523,10 @@ public abstract class OFSwitchBase implements IOFSwitch { try { List<OFMessage> msglist = new ArrayList<OFMessage>(1); msglist.add(fm); - channel.write(msglist); + write(msglist); msglist = new ArrayList<OFMessage>(1); msglist.add(barrierMsg); - channel.write(msglist); + write(msglist); } catch (Exception e) { log.error("Failed to clear all flows on switch " + this, e); } @@ -639,7 +644,7 @@ public abstract class OFSwitchBase implements IOFSwitch { this.featuresFutureMap.put(request.getXid(), future); List<OFMessage> msglist = new ArrayList<OFMessage>(1); msglist.add(request); - this.channel.write(msglist); + this.write(msglist); return future; } diff --git a/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java b/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java index 45ef6e9978fdebf82e3476dd8dfe6b94552499b4..c4d3419eb20c4822a16746fe44c9c7466d4caeff 100644 --- a/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java +++ b/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java @@ -1,7 +1,7 @@ /** -* Copyright 2011, Big Switch Networks, Inc. +* 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 @@ -18,6 +18,9 @@ package net.floodlightcontroller.core.web; import net.floodlightcontroller.core.module.ModuleLoaderResource; +import net.floodlightcontroller.debugcounter.DebugCounterGetResource; +import net.floodlightcontroller.debugcounter.DebugCounterResetResource; +import net.floodlightcontroller.debugcounter.DebugCounterStateResource; import net.floodlightcontroller.restserver.RestletRoutable; import org.restlet.Context; @@ -60,6 +63,9 @@ public class CoreWebRoutable implements RestletRoutable { router.attach("/role/json", ControllerRoleResource.class); router.attach("/health/json", HealthCheckResource.class); router.attach("/system/uptime/json", SystemUptimeResource.class); + router.attach("/debugcounter/{param}/json", DebugCounterGetResource.class); + router.attach("/debugcounter/reset/{param}/json", DebugCounterResetResource.class); + router.attach("/debugcounter/{moduleCounterName}/{state}/json", DebugCounterStateResource.class); return router; } } diff --git a/src/main/java/net/floodlightcontroller/counter/CounterStore.java b/src/main/java/net/floodlightcontroller/counter/CounterStore.java index df01fab08b2c5309ddbf3ca23626fbd74d8fab7f..bfe3b963f82b61bc0529005e4edd5b1f0b4d5164 100644 --- a/src/main/java/net/floodlightcontroller/counter/CounterStore.java +++ b/src/main/java/net/floodlightcontroller/counter/CounterStore.java @@ -297,7 +297,7 @@ public class CounterStore implements IFloodlightModule, ICounterStoreService { if (eth != null) { l3type = eth.getEtherType(); - if (l3type == (short)0x0800) { + if (eth.getPayload() instanceof IPv4) { IPv4 ipV4 = (IPv4)eth.getPayload(); l4type = ipV4.getProtocol(); } @@ -413,7 +413,7 @@ public class CounterStore implements IFloodlightModule, ICounterStoreService { CounterType.LONG)); // L4 counters - if (l3type == (short)0x0800) { + if (eth.getPayload() instanceof IPv4) { // resolve protocol alias IPv4 ipV4 = (IPv4)eth.getPayload(); diff --git a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounter.java b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounter.java index 0b6555e039ad1ad637cef884e83cfbe28ee95a0c..7aed59a8f30fa7385b3d8ab7e766392b921b2c85 100644 --- a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounter.java +++ b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounter.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.List; @@ -39,7 +40,7 @@ public class DebugCounter implements IFloodlightModule, IDebugCounterService { /** * Global debug-counter storage across all threads. These are - * updated from the local per thread counters by the update FIXME method. + * updated from the local per thread counters by the flush counters method. */ protected ConcurrentHashMap<String, AtomicLong> debugCounters = new ConcurrentHashMap<String, AtomicLong>(); @@ -73,6 +74,12 @@ public class DebugCounter implements IFloodlightModule, IDebugCounterService { this.counterDesc = desc; this.ctype = ctype; } + + public String getModuleCounterName() { return moduleCounterName; } + public String getCounterDesc() { return counterDesc; } + public CounterType getCtype() { return ctype; } + public String getModuleName() { return moduleName; } + public String getCounterName() { return counterName; } } /** @@ -82,11 +89,22 @@ public class DebugCounter implements IFloodlightModule, IDebugCounterService { new ConcurrentHashMap<String, List<CounterInfo>>(); /** - * fast cache for counter names that are currently active + * fast global cache for counter names that are currently active */ Set<String> currentCounters = Collections.newSetFromMap( new ConcurrentHashMap<String,Boolean>()); + /** + * Thread local cache for counter names that are currently active. + */ + protected final ThreadLocal<Set<String>> threadlocalCurrentCounters = + new ThreadLocal<Set<String>>() { + @Override + protected Set<String> initialValue() { + return new HashSet<String>(); + } + }; + //******************************* // IDebugCounterService //******************************* @@ -118,31 +136,27 @@ public class DebugCounter implements IFloodlightModule, IDebugCounterService { a.add(new CounterInfo(moduleCounterName, counterDescription, counterType)); // create counter in global map - debugCounters.put(moduleCounterName, new AtomicLong()); - - // create counter in local thread map - Map<String, MutableLong> thismap = this.threadlocalCounters.get(); - MutableLong ml = thismap.get(moduleCounterName); - if (ml == null) { - thismap.put(moduleCounterName, new MutableLong()); - } - - // finally add to cache if it is meant to be always counted + // and add to counter name cache if it is meant to be always counted if (counterType == CounterType.ALWAYS_COUNT) { currentCounters.add(moduleCounterName); + debugCounters.put(moduleCounterName, new AtomicLong()); } return true; } @Override public void updateCounter(String moduleCounterName) { - if (currentCounters.contains(moduleCounterName)) { - Map<String, MutableLong> thismap = this.threadlocalCounters.get(); - MutableLong ml = thismap.get(moduleCounterName); - if (ml == null) { + Map<String, MutableLong> thismap = this.threadlocalCounters.get(); + MutableLong ml = thismap.get(moduleCounterName); + if (ml == null) { + // check locally to see if this counter should be created or not + Set<String> thisset = this.threadlocalCurrentCounters.get(); + if (thisset.contains(moduleCounterName)) { ml = new MutableLong(); + ml.increment(); thismap.put(moduleCounterName, ml); } + } else { ml.increment(); } } @@ -150,64 +164,169 @@ public class DebugCounter implements IFloodlightModule, IDebugCounterService { @Override public void flushCounters() { Map<String, MutableLong> thismap = this.threadlocalCounters.get(); + ArrayList<String> deleteKeys = new ArrayList<String>(); for (String key : thismap.keySet()) { MutableLong curval = thismap.get(key); long delta = curval.get(); if (delta > 0) { - debugCounters.get(key).addAndGet(delta); - curval.set(0); + AtomicLong ctr = debugCounters.get(key); + if (ctr == null) { + // The global counter does not exist possibly because it has been + // disabled. It should thus be removed from the thread-local + // map (the counter) and set (the counter name). Removing it + // from the threadlocal set ensures that the counter will not be + // recreated (see updateCounter) + Set<String> thisset = this.threadlocalCurrentCounters.get(); + thisset.remove(key); + deleteKeys.add(key); + } else { + ctr.addAndGet(delta); + curval.set(0); + } } } + for (String dkey : deleteKeys) + thismap.remove(dkey); + + // At this point it is also possible that the threadlocal map/set does not + // include a counter that has been enabled and is present in the global + // currentCounters set. If so we need to sync such state so that the + // thread local counter can be created (in the updateCounter method) + Set<String> thisset = this.threadlocalCurrentCounters.get(); + if (thisset.size() != currentCounters.size()) { + thisset.addAll(currentCounters); + } } @Override public void resetCounter(String moduleCounterName) { - // TODO Auto-generated method stub - + if (debugCounters.containsKey(moduleCounterName)) { + debugCounters.get(moduleCounterName).set(0); + } } @Override public void resetAllCounters() { - // TODO Auto-generated method stub - + for (AtomicLong v : debugCounters.values()) { + v.set(0); + } } @Override public void resetAllModuleCounters(String moduleName) { - // TODO Auto-generated method stub - + List<CounterInfo> cil = moduleCounters.get(moduleName); + if (cil != null) { + for (CounterInfo ci : cil) { + if (debugCounters.containsKey(ci.moduleCounterName)) { + debugCounters.get(ci.moduleCounterName).set(0); + } + } + } else { + if (log.isDebugEnabled()) + log.debug("No module found with name {}", moduleName); + } } @Override public void enableCtrOnDemand(String moduleCounterName) { - // TODO Auto-generated method stub - + currentCounters.add(moduleCounterName); + debugCounters.putIfAbsent(moduleCounterName, new AtomicLong()); } @Override public void disableCtrOnDemand(String moduleCounterName) { - // TODO Auto-generated method stub - + String[] temp = moduleCounterName.split("-"); + if (temp.length < 2) { + log.error("moduleCounterName {} not recognized", moduleCounterName); + return; + } + String moduleName = temp[0]; + List<CounterInfo> cil = moduleCounters.get(moduleName); + for (CounterInfo ci : cil) { + if (ci.moduleCounterName.equals(moduleCounterName) && + ci.ctype == CounterType.COUNT_ON_DEMAND) { + currentCounters.remove(moduleCounterName); + debugCounters.remove(moduleCounterName); + return; + } + } } @Override public DebugCounterInfo getCounterValue(String moduleCounterName) { - // TODO Auto-generated method stub + if (!debugCounters.containsKey(moduleCounterName)) return null; + long counterValue = debugCounters.get(moduleCounterName).longValue(); + + String[] temp = moduleCounterName.split("-"); + if (temp.length < 2) { + log.error("moduleCounterName {} not recognized", moduleCounterName); + return null; + } + String moduleName = temp[0]; + List<CounterInfo> cil = moduleCounters.get(moduleName); + for (CounterInfo ci : cil) { + if (ci.moduleCounterName.equals(moduleCounterName)) { + DebugCounterInfo dci = new DebugCounterInfo(); + dci.counterInfo = ci; + dci.counterValue = counterValue; + return dci; + } + } return null; } @Override public List<DebugCounterInfo> getAllCounterValues() { - // TODO Auto-generated method stub - return null; + List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>(); + for (List<CounterInfo> cil : moduleCounters.values()) { + for (CounterInfo ci : cil) { + AtomicLong ctr = debugCounters.get(ci.moduleCounterName); + if (ctr != null) { + DebugCounterInfo dci = new DebugCounterInfo(); + dci.counterInfo = ci; + dci.counterValue = ctr.longValue(); + dcilist.add(dci); + } + } + } + return dcilist; } @Override - public List<DebugCounterInfo> getModuleCounterValues() { - // TODO Auto-generated method stub - return null; + public List<DebugCounterInfo> getModuleCounterValues(String moduleName) { + List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>(); + if (moduleCounters.containsKey(moduleName)) { + List<CounterInfo> cil = moduleCounters.get(moduleName); + for (CounterInfo ci : cil) { + AtomicLong ctr = debugCounters.get(ci.moduleCounterName); + if (ctr != null) { + DebugCounterInfo dci = new DebugCounterInfo(); + dci.counterInfo = ci; + dci.counterValue = ctr.longValue(); + dcilist.add(dci); + } + } + } + return dcilist; } + @Override + public boolean containsMCName(String moduleCounterName) { + if (debugCounters.containsKey(moduleCounterName)) return true; + // it is possible that the counter may be disabled + for (List<CounterInfo> cil : moduleCounters.values()) { + for (CounterInfo ci : cil) { + if (ci.moduleCounterName.equals(moduleCounterName)) + return true; + } + } + return false; + } + + @Override + public boolean containsModName(String moduleName) { + return (moduleCounters.containsKey(moduleName)) ? true : false; + } //******************************* // Internal Methods @@ -223,42 +342,39 @@ public class DebugCounter implements IFloodlightModule, IDebugCounterService { } } + //******************************* + // IFloodlightModule + //******************************* - //******************************* - // IFloodlightModule - //******************************* + @Override + public Collection<Class<? extends IFloodlightService>> getModuleServices() { + Collection<Class<? extends IFloodlightService>> l = + new ArrayList<Class<? extends IFloodlightService>>(); + l.add(IDebugCounterService.class); + return l; + } - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IDebugCounterService.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(IDebugCounterService.class, this); + return m; + } - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { - Map<Class<? extends IFloodlightService>, IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(); - m.put(IDebugCounterService.class, this); - return m; - } + @Override + public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { + return null; + } - @Override - public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - // TODO Auto-generated method stub - return null; - } + @Override + public void init(FloodlightModuleContext context) throws FloodlightModuleException { - @Override - public void init(FloodlightModuleContext context) throws FloodlightModuleException { - // TODO Auto-generated method stub + } - } + @Override + public void startUp(FloodlightModuleContext context) { - @Override - public void startUp(FloodlightModuleContext context) { - // TODO Auto-generated method stub - } + } } diff --git a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterGetResource.java b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterGetResource.java new file mode 100644 index 0000000000000000000000000000000000000000..395e00c102201f4eb49f8ddea69c76a3297cd2a3 --- /dev/null +++ b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterGetResource.java @@ -0,0 +1,130 @@ +package net.floodlightcontroller.debugcounter; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.floodlightcontroller.debugcounter.IDebugCounterService.DebugCounterInfo; + +import org.restlet.resource.Get; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Return the debug counter data for the get rest-api call + * + * URI must be in one of the following forms: + * "http://{controller-hostname}:8080/wm/core/debugcounter/{param}/json + * + * where {param} must be one of (no quotes): + * "all" returns value/info on all active counters. + * "{moduleName}" returns value/info on all active counters for the specified module. + * "{moduleCounterName}" returns value/info for specific counter if it is enabled. + * + * @author Saurav + */ +public class DebugCounterGetResource extends DebugCounterResourceBase { + protected static Logger logger = + LoggerFactory.getLogger(DebugCounterGetResource.class); + + /** + * The output JSON model that contains the counter information + */ + public static class DebugCounterInfoOutput { + public Map<String, DebugCounterInfo> counterMap; + public String error; + + DebugCounterInfoOutput() { + counterMap = new HashMap<String, DebugCounterInfo>(); + error = null; + } + public Map<String, DebugCounterInfo> getCounterMap() { + return counterMap; + } + + public String getError() { + return error; + } + + } + + public enum Option { + ALL, ONE_MODULE, ONE_MODULE_COUNTER, ERROR_BAD_MODULE_NAME, ERROR_BAD_PARAM, + ERROR_BAD_MODULE_COUNTER_NAME + } + + @Get("json") + public DebugCounterInfoOutput handleCounterInfoQuery() { + DebugCounterInfoOutput output = new DebugCounterInfoOutput(); + Option choice = Option.ERROR_BAD_PARAM; + + String param = (String)getRequestAttributes().get("param"); + if (param == null) { + param = "all"; + choice = Option.ALL; + } else if (param.equals("all")) { + choice = Option.ALL; + } else if (param.contains("-")) { + // differentiate between disabled and non-existing counters + boolean isRegistered = debugCounter.containsMCName(param); + if (isRegistered) { + choice = Option.ONE_MODULE_COUNTER; + } else { + choice = Option.ERROR_BAD_MODULE_COUNTER_NAME; + } + } else { + boolean isRegistered = debugCounter.containsModName(param); + if (isRegistered) { + choice = Option.ONE_MODULE; + } else { + choice = Option.ERROR_BAD_MODULE_NAME; + } + } + + switch (choice) { + case ALL: + poplulateAllCounters(debugCounter.getAllCounterValues(), output); + break; + case ONE_MODULE: + populateModuleCounters(debugCounter.getModuleCounterValues(param), output); + break; + case ONE_MODULE_COUNTER: + populateSingleCounter(debugCounter.getCounterValue(param), output); + break; + case ERROR_BAD_MODULE_NAME: + output.error = "Module name has no corresponding registered counters"; + break; + case ERROR_BAD_MODULE_COUNTER_NAME: + output.error = "Counter not registered"; + break; + case ERROR_BAD_PARAM: + output.error = "Bad param"; + } + + return output; + } + + private void populateSingleCounter(DebugCounterInfo debugCounterInfo, + DebugCounterInfoOutput output) { + if (debugCounterInfo != null) + output.counterMap.put(debugCounterInfo.counterInfo.moduleCounterName, + debugCounterInfo); + } + + private void populateModuleCounters(List<DebugCounterInfo> moduleCounterValues, + DebugCounterInfoOutput output) { + for (DebugCounterInfo dci : moduleCounterValues) { + populateSingleCounter(dci, output); + } + } + + private void poplulateAllCounters(List<DebugCounterInfo> allCounterValues, + DebugCounterInfoOutput output) { + for (DebugCounterInfo dci : allCounterValues) { + populateSingleCounter(dci, output); + } + } + + + +} diff --git a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResetResource.java b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResetResource.java new file mode 100644 index 0000000000000000000000000000000000000000..2833f487766683eb3cbb7dbdf3ccdc5ed05ade4e --- /dev/null +++ b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResetResource.java @@ -0,0 +1,98 @@ +package net.floodlightcontroller.debugcounter; + +import org.restlet.resource.Get; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Reset debug counter values + * + * URI must be in one of the following forms: + * "http://{controller-hostname}:8080/wm/core/debugcounter/reset/{param}/json + * + * where {param} must be one of (no quotes): + * "all" resets all active counters. + * "{moduleName}" resets all active counters for the specified module. + * "{moduleCounterName}" resets specific counter if it is enabled. + * + * @author Saurav + */ +public class DebugCounterResetResource extends DebugCounterResourceBase { + protected static Logger logger = + LoggerFactory.getLogger(DebugCounterGetResource.class); + + public enum Option { + ALL, ONE_MODULE, ONE_MODULE_COUNTER, ERROR_BAD_MODULE_NAME, ERROR_BAD_PARAM, + ERROR_BAD_MODULE_COUNTER_NAME + } + + public static class ResetOutput { + String error; + + public ResetOutput() { + error = null; + } + + public String getError() { + return error; + } + + } + + @Get("json") + public ResetOutput handleCounterResetCmd() { + Option choice = Option.ERROR_BAD_PARAM; + ResetOutput output = new ResetOutput(); + + String param = (String)getRequestAttributes().get("param"); + if (param == null) { + param = "all"; + choice = Option.ALL; + } else if (param.equals("all")) { + choice = Option.ALL; + } else if (param.contains("-")) { + // differentiate between disabled and non-existing counters + boolean isRegistered = debugCounter.containsMCName(param); + if (isRegistered) { + choice = Option.ONE_MODULE_COUNTER; + } else { + choice = Option.ERROR_BAD_MODULE_COUNTER_NAME; + } + } else { + boolean isRegistered = debugCounter.containsModName(param); + if (isRegistered) { + choice = Option.ONE_MODULE; + } else { + choice = Option.ERROR_BAD_MODULE_NAME; + } + } + + switch (choice) { + case ALL: + debugCounter.resetAllCounters(); + output.error = "None"; + break; + case ONE_MODULE: + debugCounter.resetAllModuleCounters(param); + output.error = "None"; + break; + case ONE_MODULE_COUNTER: + debugCounter.resetCounter(param); + output.error = "None"; + break; + case ERROR_BAD_MODULE_NAME: + output.error = "Module name has no corresponding registered counters"; + break; + case ERROR_BAD_MODULE_COUNTER_NAME: + output.error = "Counter not registered"; + break; + case ERROR_BAD_PARAM: + output.error = "Bad param"; + } + + return output; + } + + + +} diff --git a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResourceBase.java b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResourceBase.java new file mode 100644 index 0000000000000000000000000000000000000000..9edd47473a75564334c217b240002612d31e6219 --- /dev/null +++ b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResourceBase.java @@ -0,0 +1,16 @@ +package net.floodlightcontroller.debugcounter; + +import org.restlet.resource.ResourceException; +import org.restlet.resource.ServerResource; + +public class DebugCounterResourceBase extends ServerResource { + + protected IDebugCounterService debugCounter; + + @Override + protected void doInit() throws ResourceException { + super.doInit(); + debugCounter = (IDebugCounterService)getContext().getAttributes(). + get(IDebugCounterService.class.getCanonicalName()); + } +} diff --git a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterStateResource.java b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterStateResource.java new file mode 100644 index 0000000000000000000000000000000000000000..40f56d1f2d14bcf94ff2b7ec1fa30d825beea1cf --- /dev/null +++ b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterStateResource.java @@ -0,0 +1,63 @@ +package net.floodlightcontroller.debugcounter; + +import org.restlet.resource.Get; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Enable/disable on-demand counters + * + * URI must be in one of the following forms: + * "http://{controller-hostname}:8080/wm/core/debugcounter/{moduleCounterName}/{state}/json + * + * where {state} must be one of (no quotes): + * "enable" enables counter {moduleCounterName} if it is an on-demand counter. + * "disable" disables counter {moduleCounterName} if it is an on-demand counter. + * + * @author Saurav + */ +public class DebugCounterStateResource extends DebugCounterResourceBase { + + protected static Logger logger = + LoggerFactory.getLogger(DebugCounterStateResource.class); + + public static class StateOutput { + String error; + + public StateOutput() { + error = null; + } + + public String getError() { + return error; + } + + } + + @Get("json") + public StateOutput handleCounterStateCmd() { + StateOutput output = new StateOutput(); + + String state = (String)getRequestAttributes().get("state"); + String moduleCounterName = (String)getRequestAttributes().get("moduleCounterName"); + + if (!moduleCounterName.contains("-")) { + output.error = "Specified moduleCounterName is not of type " + + "<moduleName>-<counterName>."; + return output; + } + + if ( !(state.equals("enable") || state.equals("disable")) ) { + output.error = "State must be either enable or disable"; + return output; + } + + if (state.equals("enable")) { + debugCounter.enableCtrOnDemand(moduleCounterName); + } else { + debugCounter.disableCtrOnDemand(moduleCounterName); + } + output.error = "None"; + return output; + } +} diff --git a/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java b/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java index 6e10e13acd96e0a1c07794511657d7227a8a08d2..18fab72cbb7bfe43035377d720b0718b7d4e1331 100644 --- a/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java +++ b/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java @@ -7,7 +7,8 @@ import java.util.List; public interface IDebugCounterService extends IFloodlightService { /** - * Different counter types. + * Different counter types. Counters that are meant to be counted on demand + * need to be separately enabled/disabled. */ public enum CounterType { ALWAYS_COUNT, @@ -15,8 +16,15 @@ public interface IDebugCounterService extends IFloodlightService { } public class DebugCounterInfo { - CounterInfo counterinfo; + CounterInfo counterInfo; Long counterValue; + + public CounterInfo getCounterInfo() { + return counterInfo; + } + public Long getCounterValue() { + return counterValue; + } } /** @@ -28,6 +36,7 @@ public interface IDebugCounterService extends IFloodlightService { * @param moduleCounterName the counter name which MUST be have the following * syntax: <module name>-<counter name> * eg.: linkdiscovery-incoming + * There should be only a single '-' in the name * @param counterDescription a descriptive string that gives more information * of what the counter is measuring. For example, * "Measures the number of incoming packets seen by @@ -43,34 +52,108 @@ public interface IDebugCounterService extends IFloodlightService { CounterType counterType); /** - * Increments the counter by 1. + * Increments the counter by 1, if the counter is meant to be always counted, + * or if the counter has been enabled for counting. * @param moduleCounterName the registered counter name. */ public void updateCounter(String moduleCounterName); /** - * Update the global counter map with values from the thread local maps + * Update the global counter map with values from the thread local maps. This + * method is not intended for use by any module. It's typical usage is from + * floodlight core. As far as the modules are concerned, this should happen + * automatically for their counters. */ public void flushCounters(); /** - * - * @param moduleCounterName + * Resets the value of the counter to zero if it is currently enabled. Note + * that with live traffic, it is not necessary that the counter will display + * zero with a get call as it may get updated between the reset and get calls. + * @param moduleCounterName the registered counter name. */ public void resetCounter(String moduleCounterName); + /** + * Resets the values of all counters that are currently enabled to zero. + */ public void resetAllCounters(); + /** + * Resets the values of all counters that are currently active and belong + * to a module with the given 'moduleName'. The moduleName MUST be the + * part of the moduleCounterName with which the counters were registered. + * eg. if 'linkdiscovery-incoming' and 'linkdiscovery-lldpeol' are two counters + * the module name is 'linkdiscovery' + * @param moduleName + */ public void resetAllModuleCounters(String moduleName); + /** + * This method applies only to CounterType.COUNT_ON_DEMAND. It is used to + * enable counting on the counter. Note that this step is necessary to start + * counting for these counter types - merely registering the counter is not + * enough (as is the case for CounterType.ALWAYS_COUNT). Note that newly + * enabled counter starts from an initial value of zero. + * + * @param moduleCounterName the registered counter name. + */ public void enableCtrOnDemand(String moduleCounterName); + /** + * This method applies only to CounterType.ALWAYS_COUNT. It is used to disable + * counting on this counter. Note that disabling a counter results in a loss + * of the counter value. When re-enabled the counter will restart from zero. + * + * @param moduleCounterName the registered counter name. + */ public void disableCtrOnDemand(String moduleCounterName); + /** + * Get counter value and associated information for a specific counter if it + * is active. + * + * @param moduleCounterName + * @return DebugCounterInfo or null if the counter could not be found + */ public DebugCounterInfo getCounterValue(String moduleCounterName); + /** + * Get counter values and associated information for all active counters + * + * @return the list of values/info or an empty list + */ public List<DebugCounterInfo> getAllCounterValues(); - public List<DebugCounterInfo> getModuleCounterValues(); + /** + * Get counter values and associated information for all active counters associated + * with a module. + * + * @param moduleName + * @return the list of values/info or an empty list + */ + public List<DebugCounterInfo> getModuleCounterValues(String moduleName); + + /** + * Convenience method to figure out if the the given 'moduleCounterName' corresponds + * to a registered moduleCounterName or not. Note that the counter may or + * may not be enabled for counting, but if it is registered the method will + * return true. + * + * @param param + * @return false if moduleCounterName is not a registered counter + */ + public boolean containsMCName(String moduleCounterName); + + /** + * Convenience method to figure out if the the given 'moduleName' corresponds + * to a registered moduleName or not. Note that the module may or may not have + * a counter enabled for counting, but if it is registered the method will + * return true. + * + * @param param + * @return false if moduleName is not a registered counter + */ + public boolean containsModName(String moduleName); } diff --git a/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java b/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java index 3807f9d96f5d9571e2ed3f3f5ca4c422697592b8..5e5ffbba2f3de68af207d63c08909451bd032186 100644 --- a/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java +++ b/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java @@ -15,28 +15,24 @@ public class NullDebugCounter implements IFloodlightModule, IDebugCounterService public boolean registerCounter(String moduleCounterName, String counterDescription, CounterType counterType) { - // TODO Auto-generated method stub return false; } @Override public Collection<Class<? extends IFloodlightService>> getModuleServices() { - // TODO Auto-generated method stub return null; } @Override public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { - // TODO Auto-generated method stub return null; } @Override public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - // TODO Auto-generated method stub return null; } @@ -45,74 +41,72 @@ public class NullDebugCounter implements IFloodlightModule, IDebugCounterService void init(FloodlightModuleContext context) throws FloodlightModuleException { - // TODO Auto-generated method stub } @Override public void startUp(FloodlightModuleContext context) { - // TODO Auto-generated method stub } @Override public void updateCounter(String moduleCounterName) { - // TODO Auto-generated method stub } @Override public void flushCounters() { - // TODO Auto-generated method stub } @Override public void resetCounter(String moduleCounterName) { - // TODO Auto-generated method stub } @Override public void resetAllCounters() { - // TODO Auto-generated method stub } @Override public void resetAllModuleCounters(String moduleName) { - // TODO Auto-generated method stub } @Override public void enableCtrOnDemand(String moduleCounterName) { - // TODO Auto-generated method stub } @Override public void disableCtrOnDemand(String moduleCounterName) { - // TODO Auto-generated method stub } @Override public DebugCounterInfo getCounterValue(String moduleCounterName) { - // TODO Auto-generated method stub return null; } @Override public List<DebugCounterInfo> getAllCounterValues() { - // TODO Auto-generated method stub return null; } @Override - public List<DebugCounterInfo> getModuleCounterValues() { - // TODO Auto-generated method stub + public List<DebugCounterInfo> getModuleCounterValues(String moduleName) { return null; } + @Override + public boolean containsMCName(String moduleCounterName) { + return false; + } + + @Override + public boolean containsModName(String moduleName) { + return false; + } + } diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java index 52ebdf0493fcdc5e60e595df0273d761810e8d1d..8861f33214e5c55f086c2074d367ac0e9ced4969 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java @@ -759,10 +759,10 @@ IFlowReconcileListener, IInfoProvider, IHAListener { logger.debug("Could not instantiate REST API"); } - registerLinkDiscoveryDebugCounters(); + registerDeviceManagerDebugCounters(); } - private void registerLinkDiscoveryDebugCounters() { + private void registerDeviceManagerDebugCounters() { if (debugCounters == null) { logger.error("Debug Counter Service not found."); debugCounters = new NullDebugCounter(); @@ -857,10 +857,10 @@ IFlowReconcileListener, IInfoProvider, IHAListener { * @param srcDevice */ private void snoopDHCPClientName(Ethernet eth, Device srcDevice) { - if (eth.getEtherType() != Ethernet.TYPE_IPv4) + if (! (eth.getPayload() instanceof IPv4) ) return; IPv4 ipv4 = (IPv4) eth.getPayload(); - if (ipv4.getProtocol() != IPv4.PROTOCOL_UDP) + if (! (ipv4.getPayload() instanceof UDP) ) return; UDP udp = (UDP) ipv4.getPayload(); if (!(udp.getPayload() instanceof DHCP)) diff --git a/src/main/java/net/floodlightcontroller/firewall/Firewall.java b/src/main/java/net/floodlightcontroller/firewall/Firewall.java index c6a4fd763df1df46babb4b92fef411070365d7c8..21dc8aed6ca937f3123e9a00971ee8b0fc13fd80 100644 --- a/src/main/java/net/floodlightcontroller/firewall/Firewall.java +++ b/src/main/java/net/floodlightcontroller/firewall/Firewall.java @@ -595,7 +595,7 @@ public class Firewall implements IFirewallService, IOFMessageListener, // the case to determine if we have L2 broadcast + L3 unicast // don't allow this broadcast packet if such is the case (malformed // packet) - if (eth.getEtherType() == Ethernet.TYPE_IPv4 + if ((eth.getPayload() instanceof IPv4) && this.IPIsBroadcast(((IPv4) eth.getPayload()) .getDestinationAddress()) == false) { allowBroadcast = false; diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java index fbd05a10ecff1fe93022bb4180cd5a087355aacb..624bcc6edf1cdf741c0320e048fac9a8bf32b4af 100644 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java +++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java @@ -544,7 +544,7 @@ public class LinkDiscoveryManager implements IOFMessageListener, Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - if (eth.getEtherType() == Ethernet.TYPE_BSN) { + if (eth.getPayload() instanceof BSN) { BSN bsn = (BSN) eth.getPayload(); if (bsn == null) return Command.STOP; if (bsn.getPayload() == null) return Command.STOP; @@ -553,7 +553,7 @@ public class LinkDiscoveryManager implements IOFMessageListener, if (bsn.getPayload() instanceof LLDP == false) return Command.CONTINUE; return handleLldp((LLDP) bsn.getPayload(), sw, pi.getInPort(), false, cntx); - } else if (eth.getEtherType() == Ethernet.TYPE_LLDP) { + } else if (eth.getPayload() instanceof LLDP) { return handleLldp((LLDP) eth.getPayload(), sw, pi.getInPort(), true, cntx); } else if (eth.getEtherType() < 1500) { long destMac = eth.getDestinationMAC().toLong(); @@ -770,6 +770,7 @@ public class LinkDiscoveryManager implements IOFMessageListener, removeFromMaintenanceQueue(nptDst); // Consume this message + debugCounters.updateCounter("linkdiscovery-lldpeol"); return Command.STOP; } @@ -2267,6 +2268,8 @@ public class LinkDiscoveryManager implements IOFMessageListener, } debugCounters.registerCounter(getName() + "-" + "incoming", "All incoming packets seen by this module", CounterType.ALWAYS_COUNT); + debugCounters.registerCounter(getName() + "-" + "lldpeol", + "End of Life for LLDP packets", CounterType.COUNT_ON_DEMAND); } // **************************************************** diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java index b7bc2de3a7fa329d224a8d1509e03800af52d3d1..0521cd9a71438864bfd375c32fb6893d13754df1 100644 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java +++ b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java @@ -69,6 +69,7 @@ import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.SwitchPort; import net.floodlightcontroller.packet.ARP; import net.floodlightcontroller.packet.Ethernet; +import net.floodlightcontroller.packet.ICMP; import net.floodlightcontroller.packet.IPacket; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.packet.TCP; @@ -194,7 +195,7 @@ public class LoadBalancer implements IFloodlightModule, if (eth.isBroadcast() || eth.isMulticast()) { // handle ARP for VIP - if (eth.getEtherType() == Ethernet.TYPE_ARP) { + if (pkt instanceof ARP) { // retrieve arp to determine target IP address ARP arpRequest = (ARP) eth.getPayload(); @@ -219,17 +220,17 @@ public class LoadBalancer implements IFloodlightModule, IPClient client = new IPClient(); client.ipAddress = ip_pkt.getSourceAddress(); client.nw_proto = ip_pkt.getProtocol(); - if (client.nw_proto == IPv4.PROTOCOL_TCP) { + if (ip_pkt.getPayload() instanceof TCP) { TCP tcp_pkt = (TCP) ip_pkt.getPayload(); client.srcPort = tcp_pkt.getSourcePort(); client.targetPort = tcp_pkt.getDestinationPort(); } - if (client.nw_proto == IPv4.PROTOCOL_UDP) { + if (ip_pkt.getPayload() instanceof UDP) { UDP udp_pkt = (UDP) ip_pkt.getPayload(); client.srcPort = udp_pkt.getSourcePort(); client.targetPort = udp_pkt.getDestinationPort(); } - if (client.nw_proto == IPv4.PROTOCOL_ICMP) { + if (ip_pkt.getPayload() instanceof ICMP) { client.srcPort = 8; client.targetPort = 0; } @@ -268,6 +269,8 @@ public class LoadBalancer implements IFloodlightModule, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); // retrieve original arp to determine host configured gw IP address + if (! (eth.getPayload() instanceof ARP)) + return; ARP arpRequest = (ARP) eth.getPayload(); // have to do proxy arp reply since at this point we cannot determine the requesting application type diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java index 1904a58c61af16431fb43426cae27755950f79a2..e0e39729874fa23024b89050c670ed7b68ef8825 100644 --- a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java +++ b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java @@ -766,10 +766,10 @@ public class TopologyManager implements floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); floodlightProvider.addHAListener(this); addRestletRoutable(); - registerLinkDiscoveryDebugCounters(); + registerTopologyDebugCounters(); } - private void registerLinkDiscoveryDebugCounters() { + private void registerTopologyDebugCounters() { if (debugCounters == null) { log.error("Debug Counter Service not found."); debugCounters = new NullDebugCounter(); @@ -968,7 +968,7 @@ public class TopologyManager implements IFloodlightProviderService.bcStore. get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - if (eth.getEtherType() == Ethernet.TYPE_BSN) { + if (eth.getPayload() instanceof BSN) { BSN bsn = (BSN) eth.getPayload(); if (bsn == null) return Command.STOP; if (bsn.getPayload() == null) return Command.STOP; diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/NoOp.java b/src/main/java/net/floodlightcontroller/virtualnetwork/NoOp.java index 862f30ffb162f7b20bcf6dd0ece6ca95d4d5b76c..9533056297b1b5ac0d10120040b27356b3808283 100644 --- a/src/main/java/net/floodlightcontroller/virtualnetwork/NoOp.java +++ b/src/main/java/net/floodlightcontroller/virtualnetwork/NoOp.java @@ -24,16 +24,17 @@ import org.restlet.resource.Put; import org.restlet.resource.ServerResource; public class NoOp extends ServerResource { - /** - * Does nothing and returns 200 OK with a status message - * @return status: ok - */ - @Get - @Put - @Post - @Delete - public String noOp(String postdata) { - setStatus(Status.SUCCESS_OK); + /** + * Does nothing and returns 200 OK with a status message + * + * @return status: ok + */ + @Get + @Put + @Post + @Delete + public String noOp(String postdata) { + setStatus(Status.SUCCESS_OK); return "{\"status\":\"ok\"}"; - } + } }