/*
* Copyright (c) 2011,2013 Big Switch Networks, Inc.
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html
*
* 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.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Originally created by David Erickson, Stanford University
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS
* IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package org.sdnplatform.core.web;
import java.lang.Thread.State;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.openflow.protocol.OFFeaturesReply;
import org.openflow.protocol.statistics.OFStatistics;
import org.openflow.protocol.statistics.OFStatisticsType;
import org.openflow.util.HexString;
import org.restlet.resource.Get;
import org.sdnplatform.core.IControllerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Return switch statistics information for all switches
* @author readams
*/
public class AllSwitchStatisticsResource extends SwitchResourceBase {
protected static Logger log =
LoggerFactory.getLogger(AllSwitchStatisticsResource.class);
@Get("json")
public Map<String, Object> retrieve() {
String statType = (String) getRequestAttributes().get("statType");
return retrieveInternal(statType);
}
public Map<String, Object> retrieveInternal(String statType) {
HashMap<String, Object> model = new HashMap<String, Object>();
OFStatisticsType type = null;
REQUESTTYPE rType = null;
if (statType.equals("port")) {
type = OFStatisticsType.PORT;
rType = REQUESTTYPE.OFSTATS;
} else if (statType.equals("queue")) {
type = OFStatisticsType.QUEUE;
rType = REQUESTTYPE.OFSTATS;
} else if (statType.equals("flow")) {
type = OFStatisticsType.FLOW;
rType = REQUESTTYPE.OFSTATS;
} else if (statType.equals("aggregate")) {
type = OFStatisticsType.AGGREGATE;
rType = REQUESTTYPE.OFSTATS;
} else if (statType.equals("desc")) {
type = OFStatisticsType.DESC;
rType = REQUESTTYPE.OFSTATS;
} else if (statType.equals("table")) {
type = OFStatisticsType.TABLE;
rType = REQUESTTYPE.OFSTATS;
} else if (statType.equals("features")) {
rType = REQUESTTYPE.OFFEATURES;
} else {
return model;
}
IControllerService controllerProvider =
(IControllerService)getContext().getAttributes().
get(IControllerService.class.getCanonicalName());
Long[] switchDpids = controllerProvider.getSwitches().keySet().toArray(new Long[0]);
List<GetConcurrentStatsThread> activeThreads = new ArrayList<GetConcurrentStatsThread>(switchDpids.length);
List<GetConcurrentStatsThread> pendingRemovalThreads = new ArrayList<GetConcurrentStatsThread>();
GetConcurrentStatsThread t;
for (Long l : switchDpids) {
t = new GetConcurrentStatsThread(l, rType, type);
activeThreads.add(t);
t.start();
}
// Join all the threads after the timeout. Set a hard timeout
// of 12 seconds for the threads to finish. If the thread has not
// finished the switch has not replied yet and therefore we won't
// add the switch's stats to the reply.
for (int iSleepCycles = 0; iSleepCycles < 12; iSleepCycles++) {
for (GetConcurrentStatsThread curThread : activeThreads) {
if (curThread.getState() == State.TERMINATED) {
if (rType == REQUESTTYPE.OFSTATS) {
model.put(HexString.toHexString(curThread.getSwitchId()), curThread.getStatisticsReply());
} else if (rType == REQUESTTYPE.OFFEATURES) {
model.put(HexString.toHexString(curThread.getSwitchId()), curThread.getFeaturesReply());
}
pendingRemovalThreads.add(curThread);
}
}
// remove the threads that have completed the queries to the switches
for (GetConcurrentStatsThread curThread : pendingRemovalThreads) {
activeThreads.remove(curThread);
}
// clear the list so we don't try to double remove them
pendingRemovalThreads.clear();
// if we are done finish early so we don't always get the worst case
if (activeThreads.isEmpty()) {
break;
}
// sleep for 1 s here
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log.error("Interrupted while waiting for statistics", e);
}
}
return model;
}
protected class GetConcurrentStatsThread extends Thread {
private List<OFStatistics> switchReply;
private long switchId;
private OFStatisticsType statType;
private REQUESTTYPE requestType;
private OFFeaturesReply featuresReply;
public GetConcurrentStatsThread(long switchId, REQUESTTYPE requestType, OFStatisticsType statType) {
this.switchId = switchId;
this.requestType = requestType;
this.statType = statType;
this.switchReply = null;
this.featuresReply = null;
}
public List<OFStatistics> getStatisticsReply() {
return switchReply;
}
public OFFeaturesReply getFeaturesReply() {
return featuresReply;
}
public long getSwitchId() {
return switchId;
}
public void run() {
if ((requestType == REQUESTTYPE.OFSTATS) && (statType != null)) {
switchReply = getSwitchStatistics(switchId, statType);
} else if (requestType == REQUESTTYPE.OFFEATURES) {
featuresReply = getSwitchFeaturesReply(switchId);
}
}
}
}