diff --git a/src/main/java/net/floodlightcontroller/odin/applications/ShowStatistics.java b/src/main/java/net/floodlightcontroller/odin/applications/ShowStatistics.java new file mode 100644 index 00000000..c8f5019f --- /dev/null +++ b/src/main/java/net/floodlightcontroller/odin/applications/ShowStatistics.java @@ -0,0 +1,106 @@ +package net.floodlightcontroller.odin.applications; + +import java.net.InetAddress; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import net.floodlightcontroller.odin.master.OdinApplication; +import net.floodlightcontroller.odin.master.OdinClient; +import net.floodlightcontroller.util.MACAddress; + +public class ShowStatistics extends OdinApplication { + +// IMPORTANT: this application only works if all the agents in the +//poolfile are activated before the end of the INITIAL_INTERVAL. +// Otherwise, the application looks for an object that does not exist +//and gets stopped + +// this interval is for allowing the agents to connect to the controller +private final int INITIAL_INTERVAL = 30000; // in ms + +// this interval this interval is the period for showing the statistics +private final int REPORTING_PERIOD = 15000; // in ms + +HashSet clients; + + @Override + public void run() { + try { + Thread.sleep(INITIAL_INTERVAL); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + while (true) { + try { + Thread.sleep(REPORTING_PERIOD); + clients = new HashSet(getClients()); + /* + * If a handoff has happened during the statistic gathering period, + * it may happen that a client appears in the statistics of two agents + * because it has been handed off from one agent to another + */ + + System.out.println("[ShowStatistics] List of Agents:"); //JOSE + + // for each Agent + for (InetAddress agentAddr: getAgents()) { + + System.out.println("[ShowStatistics] Agent: " + agentAddr); + + // Transmission statistics + System.out.println("[ShowStatistics] Last ping heard from agent " + agentAddr + " " + getLastHeardFromAgent(agentAddr)); + + Map> vals_tx = getTxStatsFromAgent(agentAddr); // all the clients who have statistics + + // Reception statistics + Map> vals_rx = getRxStatsFromAgent(agentAddr); + + for (OdinClient oc: clients) { // all the clients currently associated + // NOTE: the clients currently associated MAY NOT be the same as the clients who have statistics + + System.out.println("\n[ShowStatistics] 1" + agentAddr); + + // for each STA associated to the Agent + for (Entry> vals_entry_rx: vals_rx.entrySet()) { + + MACAddress staHwAddr = vals_entry_rx.getKey(); + if (oc.getMacAddress().equals(staHwAddr) && oc.getIpAddress() != null && !oc.getIpAddress().getHostAddress().equals("0.0.0.0")) { + System.out.println("\tUplink station MAC: " + staHwAddr + " IP: " + oc.getIpAddress().getHostAddress()); + System.out.println("\t\tnum packets: " + vals_entry_rx.getValue().get("packets")); + System.out.println("\t\tavg rate: " + vals_entry_rx.getValue().get("avg_rate") + " kbps"); + System.out.println("\t\tavg signal: " + vals_entry_rx.getValue().get("avg_signal") + " dBm"); + System.out.println("\t\tavg length: " + vals_entry_rx.getValue().get("avg_len_pkt") + " bytes"); + System.out.println("\t\tair time: " + vals_entry_rx.getValue().get("air_time") + " ms"); + System.out.println("\t\tinit time: " + vals_entry_rx.getValue().get("first_received") + " sec"); + System.out.println("\t\tend time: " + vals_entry_rx.getValue().get("last_received") + " sec"); + System.out.println(""); + } + } + // for each STA associated to the Agent + for (Entry> vals_entry_tx: vals_tx.entrySet()) { + MACAddress staHwAddr = vals_entry_tx.getKey(); + if (oc.getMacAddress().equals(staHwAddr) && oc.getIpAddress() != null && !oc.getIpAddress().getHostAddress().equals("0.0.0.0")) { + System.out.println("\tDownlink station MAC: " + staHwAddr + " IP: " + oc.getIpAddress().getHostAddress()); + System.out.println("\t\tnum packets: " + vals_entry_tx.getValue().get("packets")); + System.out.println("\t\tavg rate: " + vals_entry_tx.getValue().get("avg_rate") + " kbps"); + System.out.println("\t\tavg signal: " + vals_entry_tx.getValue().get("avg_signal") + " dBm"); + System.out.println("\t\tavg length: " + vals_entry_tx.getValue().get("avg_len_pkt") + " bytes"); + System.out.println("\t\tair time: " + vals_entry_tx.getValue().get("air_time") + " ms"); + System.out.println("\t\tinit time: " + vals_entry_tx.getValue().get("first_received") + " sec"); + System.out.println("\t\tend time: " + vals_entry_tx.getValue().get("last_received") + " sec"); + System.out.println(""); + } + + } + } + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/net/floodlightcontroller/odin/master/IOdinAgent.java b/src/main/java/net/floodlightcontroller/odin/master/IOdinAgent.java index 78aba9ad..5157f92c 100644 --- a/src/main/java/net/floodlightcontroller/odin/master/IOdinAgent.java +++ b/src/main/java/net/floodlightcontroller/odin/master/IOdinAgent.java @@ -39,6 +39,14 @@ public interface IOdinAgent { */ public Set getLvapsLocal (); + /** + * Retrieve Tx-stats from the OdinAgent. + * + * @return A map of stations' MAC addresses to a map + * of properties and values. + */ + public Map> getTxStats (); + /** * Retrive Rx-stats from the OdinAgent. diff --git a/src/main/java/net/floodlightcontroller/odin/master/IOdinMasterToApplicationInterface.java b/src/main/java/net/floodlightcontroller/odin/master/IOdinMasterToApplicationInterface.java index 8538bcaa..c9608c0e 100644 --- a/src/main/java/net/floodlightcontroller/odin/master/IOdinMasterToApplicationInterface.java +++ b/src/main/java/net/floodlightcontroller/odin/master/IOdinMasterToApplicationInterface.java @@ -35,6 +35,10 @@ interface IOdinMasterToApplicationInterface { */ OdinClient getClientFromHwAddress (String pool, MACAddress clientHwAddress); + long getLastHeardFromAgent (String pool, InetAddress agentAddr); + + Map> getTxStatsFromAgent (String pool, InetAddress agentAddr); + Map> getRxStatsFromAgent (String pool, InetAddress agentAddr); /** diff --git a/src/main/java/net/floodlightcontroller/odin/master/OdinAgent.java b/src/main/java/net/floodlightcontroller/odin/master/OdinAgent.java index 4852fa3e..3b03fffc 100644 --- a/src/main/java/net/floodlightcontroller/odin/master/OdinAgent.java +++ b/src/main/java/net/floodlightcontroller/odin/master/OdinAgent.java @@ -55,6 +55,7 @@ class OdinAgent implements IOdinAgent { // OdinAgent Handler strings. Wi5: We introduce handlers to manage APs channels private static final String READ_HANDLER_TABLE = "table"; + private static final String READ_HANDLER_TXSTATS = "txstats"; private static final String READ_HANDLER_RXSTATS = "rxstats"; private static final String READ_HANDLER_SPECTRAL_SCAN = "spectral_scan"; private static final String READ_HANDLER_CHANNEL = "channel"; @@ -68,7 +69,8 @@ class OdinAgent implements IOdinAgent { private static final String WRITE_HANDLER_CHANNEL_SWITCH_ANNOUNCEMENT = "channel_switch_announcement"; private static final String ODIN_AGENT_ELEMENT = "odinagent"; - private final int RX_STAT_NUM_PROPERTIES = 5; + private final int TX_STAT_NUM_PROPERTIES = 7; + private final int RX_STAT_NUM_PROPERTIES = 7; private final int ODIN_AGENT_PORT = 6777; @@ -168,6 +170,42 @@ public Set getLvapsLocal() { return clientList; } + /** + * Retrieve Tx-stats from the OdinAgent. + * + * @return A map of stations' MAC addresses to a map of properties and + * values. + */ + public Map> getTxStats() { + String stats = invokeReadHandler(READ_HANDLER_TXSTATS); + + Map> ret = new HashMap>(); + + /* + * We basically get rows like this MAC_ADDR1 prop1: prop2: + * MAC_ADDR2 prop1: prop2: + */ + String arr[] = stats.split("\n"); + for (String elem : arr) { + String row[] = elem.split(" "); + + if (row.length != TX_STAT_NUM_PROPERTIES + 1) { + continue; + } + + MACAddress eth = MACAddress.valueOf(row[0].toLowerCase()); + + Map innerMap = new HashMap(); + + for (int i = 1; i < TX_STAT_NUM_PROPERTIES + 1; i += 1) { + innerMap.put(row[i].split(":")[0], row[i].split(":")[1]); + } + + ret.put(eth, Collections.unmodifiableMap(innerMap)); + } + + return Collections.unmodifiableMap(ret); + } /** * Retrive Rx-stats from the OdinAgent. diff --git a/src/main/java/net/floodlightcontroller/odin/master/OdinApplication.java b/src/main/java/net/floodlightcontroller/odin/master/OdinApplication.java index cde96ee6..994e238a 100644 --- a/src/main/java/net/floodlightcontroller/odin/master/OdinApplication.java +++ b/src/main/java/net/floodlightcontroller/odin/master/OdinApplication.java @@ -78,6 +78,26 @@ protected final OdinClient getClientFromHwAddress (MACAddress clientHwAddress) { return odinApplicationInterfaceToMaster.getClientFromHwAddress(pool, clientHwAddress); } + /** Retreive LastHeard from the agent + * + * @param agentAddr InetAddress of the agent + * + * @return timestamp of the last ping heard from the agent + */ + protected final long getLastHeardFromAgent (InetAddress agentAddr) { + return odinApplicationInterfaceToMaster.getLastHeardFromAgent(pool, agentAddr); + } + + /** + * Retreive TxStats from the agent + * + * @param agentAddr InetAddress of the agent + * + * @return Key-Value entries of each recorded statistic for each client + */ + protected final Map> getTxStatsFromAgent (InetAddress agentAddr) { + return odinApplicationInterfaceToMaster.getTxStatsFromAgent(pool, agentAddr); + } /** * Retreive RxStats from the agent diff --git a/src/main/java/net/floodlightcontroller/odin/master/OdinMaster.java b/src/main/java/net/floodlightcontroller/odin/master/OdinMaster.java index afd6c0c3..d40d0141 100644 --- a/src/main/java/net/floodlightcontroller/odin/master/OdinMaster.java +++ b/src/main/java/net/floodlightcontroller/odin/master/OdinMaster.java @@ -462,7 +462,35 @@ public OdinClient getClientFromHwAddress (String pool, MACAddress clientHwAddres return (client != null && poolManager.getPoolForClient(client).equals(pool)) ? client : null; } + + /** + * Retreive LastHeard from the agent + * + * @param pool that the invoking application corresponds to + * @param agentAddr InetAddress of the agent + * + * @return timestamp of the last ping heard from the agent + */ + @Override + public long getLastHeardFromAgent (String pool, InetAddress agentAddr) { + return agentManager.getAgent(agentAddr).getLastHeard(); + } + + /** + * Retreive TxStats from the agent + * + * @param pool that the invoking application corresponds to + * @param agentAddr InetAddress of the agent + * + * @return Key-Value entries of each recorded statistic for each client + */ + @Override + public Map> getTxStatsFromAgent (String pool, InetAddress agentAddr) { + return agentManager.getAgent(agentAddr).getTxStats(); + } + + /** * Retreive RxStats from the agent * diff --git a/src/main/java/net/floodlightcontroller/odin/master/StubOdinAgent.java b/src/main/java/net/floodlightcontroller/odin/master/StubOdinAgent.java index 51c568a5..c11f6beb 100644 --- a/src/main/java/net/floodlightcontroller/odin/master/StubOdinAgent.java +++ b/src/main/java/net/floodlightcontroller/odin/master/StubOdinAgent.java @@ -17,6 +17,7 @@ * channel to map the physical Wi-Fi channel used by the access point. * * @author Lalith Suresh + * */ class StubOdinAgent implements IOdinAgent { @@ -37,7 +38,12 @@ public void addClientLvap(OdinClient oc) { public InetAddress getIpAddress() { return ipAddr; } - + + @Override + public Map> getTxStats() { + return null; + } + @Override public Map> getRxStats() { return null;