package edu.usc.enl.dynamicmeasurement.floodlight; import edu.usc.enl.dynamicmeasurement.model.WildcardPattern; import net.floodlightcontroller.core.IOFSwitch; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFStatisticsRequest; import org.openflow.protocol.statistics.OFFlowStatisticsReply; import org.openflow.protocol.statistics.OFFlowStatisticsRequest; import org.openflow.protocol.statistics.OFStatistics; import org.openflow.protocol.statistics.OFStatisticsType; import java.util.*; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * Created with IntelliJ IDEA. * User: masoud * Date: 10/18/13 * Time: 3:57 PM <br/> * This class is responsible to fetch counters from a single switch */ class RuleFetcherThreadMethod implements Runnable { private static final long INT_MASK = ((1l << 32) - 1); private final IOFSwitch iofSwitch; /** * Raw OpenFlow Stats Reply messages */ private List<OFFlowStatisticsReply> stats; /** * Fetched rules will be saved in this data structure. * The data structure is passed in the constructor and is usually kept in the SwitchData objects */ private Map<WildcardPattern, WildcardPattern> fetchedRules; /** * Keeps track of last fetched rules to decrease their weight from the new ones if anything is common */ private Map<WildcardPattern, WildcardPattern> lastFetchedRules; private int epoch; public RuleFetcherThreadMethod(IOFSwitch iofSwitch, int capacity, Map<WildcardPattern, WildcardPattern> fetchedRules, Map<WildcardPattern, WildcardPattern> lastFetchedRules) { this.iofSwitch = iofSwitch; this.stats = new ArrayList<>(capacity); this.fetchedRules = fetchedRules; this.lastFetchedRules = lastFetchedRules; } public static void fetch(IOFSwitch sw, List<OFFlowStatisticsReply> stats) { List<OFStatistics> values = null; Future<List<OFStatistics>> future; // Statistics request object for getting flows OFStatisticsRequest req = new OFStatisticsRequest(); req.setStatisticType(OFStatisticsType.FLOW); int requestLength = req.getLengthU(); OFFlowStatisticsRequest specificReq = new OFFlowStatisticsRequest(); specificReq.setMatch(new OFMatch().setWildcards(0xffffffff)); specificReq.setOutPort(OFPort.OFPP_NONE.getValue()); specificReq.setTableId((byte) 0xff); req.setStatistics(Collections.singletonList((OFStatistics) specificReq)); requestLength += specificReq.getLength(); req.setLengthU(requestLength); try { future = sw.queryStatistics(req); values = future.get(2, TimeUnit.SECONDS); //FIXME: is 2 the right number? if (values != null) { // System.out.println("got in"); for (OFStatistics stat : values) { stats.add((OFFlowStatisticsReply) stat); } } else { PeriodicReport.log.warn("Got null flow list from " + sw); } } catch (Exception e) { PeriodicReport.log.error("Failure retrieving statistics from switch " + sw, e); } } @Override public void run() { fetchStats(iofSwitch); } public Collection<OFFlowStatisticsReply> getStats() { return stats; } /** * @param sw the switch object that we wish to get flows from * a list of OFFlowStatisticsReply objects or essentially flows */ public void fetchStats(IOFSwitch sw) { stats.clear(); fetch(sw, stats); // Map<WildcardPattern, WildcardPattern> testOldSaved = new HashMap<>(fetchedRules); fetchedRules.clear(); for (OFFlowStatisticsReply statisticsReply : stats) { int wildcardNum = WildcardPattern.TOTAL_LENGTH - statisticsReply.getMatch().getNetworkSourceMaskLen(); long l = statisticsReply.getMatch().getNetworkSource(); WildcardPattern pattern = new WildcardPattern((l & INT_MASK) >>> wildcardNum, wildcardNum, statisticsReply.getByteCount()); fetchedRules.put(pattern, pattern); } // testOldSaved.keySet().removeAll(fetchedRules.keySet()); // for (WildcardPattern wildcardPattern : testOldSaved.keySet()) { // System.out.println("saved "+wildcardPattern+ " but not found it! "); // } for (WildcardPattern newRule : fetchedRules.values()) { WildcardPattern oldRule = lastFetchedRules.get(newRule); if (oldRule != null) { double weight = newRule.getWeight() - oldRule.getWeight(); oldRule.setWeight(newRule.getWeight()); newRule.setWeight(weight); } else { lastFetchedRules.put(newRule, newRule); } } lastFetchedRules.keySet().retainAll(fetchedRules.keySet()); if (PeriodicReport.log.isInfoEnabled()) { printReport(); } } /** * Print all stats received (just for debugging) */ private void printReport() { PeriodicReport.log.info("report"); Collections.sort(stats, new Comparator<OFFlowStatisticsReply>() { @Override public int compare(OFFlowStatisticsReply o1, OFFlowStatisticsReply o2) { return Integer.compare(o1.getMatch().getNetworkSource(), o2.getMatch().getNetworkSource()); } }); PeriodicReport.log.info(iofSwitch + "->"); int i = 0; for (OFFlowStatisticsReply reply : stats) { PeriodicReport.log.info("\t " + i + ": " + reply.getMatch() + "," + reply.getByteCount()); i++; } } public int getEpoch() { return epoch; } public void setEpoch(int epoch) { this.epoch = epoch; } }