diff --git a/src/main/java/net/floodlightcontroller/odin/applications/SmartApSelection.java b/src/main/java/net/floodlightcontroller/odin/applications/SmartApSelection.java index cc3494bf..dddffd99 100644 --- a/src/main/java/net/floodlightcontroller/odin/applications/SmartApSelection.java +++ b/src/main/java/net/floodlightcontroller/odin/applications/SmartApSelection.java @@ -8,6 +8,7 @@ import java.util.Map.Entry; import java.util.Set; import java.util.Arrays; +import java.util.ArrayList; import java.io.File; import java.io.PrintStream; import java.math.*; @@ -56,16 +57,17 @@ public class SmartApSelection extends OdinApplication { /** * Flow detection */ - private final String IPSrcAddress; // Handle a IPSrcAddress or all IPSrcAddress ("*") - private final String IPDstAddress; // Handle a IPDstAddress or all IPDstAddress ("*") - private final int protocol; // Handle a protocol or all protocol ("*") - private final int SrcPort; // Handle a SrcPort or all SrcPort ("*") - private final int DstPort; // Handle a DstPort or all DstPort ("*") + private final String IPSrcAddress; // Handle a IPSrcAddress or all IPSrcAddress ("*") + private final String IPDstAddress; // Handle a IPDstAddress or all IPDstAddress ("*") + private final int protocol; // Handle a protocol or all protocol ("*") + private final int SrcPort; // Handle a SrcPort or all SrcPort ("*") + private final int DstPort; // Handle a DstPort or all DstPort ("*") Map flowsReceived = new HashMap (); + // Initialize the variables public SmartApSelection () { - this.IPSrcAddress = "*"; + this.IPSrcAddress = "*"; // The controller will handle subscriptions from every IP source accress this.IPDstAddress = "*"; this.protocol = 0; this.SrcPort = 0; @@ -74,18 +76,19 @@ public SmartApSelection () { /** * Register flow detection + * Configure the detection of flows */ private void initDetection () { - OdinEventFlowDetection oefd = new OdinEventFlowDetection(); - oefd.setFlowDetection(this.IPSrcAddress, this.IPSrcAddress, this.protocol, this.SrcPort, this.DstPort); - FlowDetectionCallback cb = new FlowDetectionCallback() { - @Override - public void exec(OdinEventFlowDetection oefd, FlowDetectionCallbackContext cntx) { - handler(oefd, cntx); - } - }; - /* Before executing this line, make sure the agents declared in poolfile are started */ - registerFlowDetection(oefd, cb); + OdinEventFlowDetection oefd = new OdinEventFlowDetection(); + oefd.setFlowDetection(this.IPSrcAddress, this.IPSrcAddress, this.protocol, this.SrcPort, this.DstPort); + FlowDetectionCallback cb = new FlowDetectionCallback() { + @Override + public void exec(OdinEventFlowDetection oefd, FlowDetectionCallbackContext cntx) { + handler(oefd, cntx); + } + }; + /* Before executing this line, make sure the agents declared in poolfile are started */ + registerFlowDetection(oefd, cb); } /** * Condition for a hand off @@ -104,7 +107,9 @@ public void exec(OdinEventFlowDetection oefd, FlowDetectionCallbackContext cntx) @Override public void run() { System.out.println("[SmartAPSelection] Start"); - this.SMARTAP_PARAMS = getSmartApSelectionParams(); + this.SMARTAP_PARAMS = getSmartApSelectionParams(); // Import the parameters of Poolfile, using this function of Odin Master + + // Wait a period in order to let the user start the agents try { System.out.println("[SmartAPSelection] Sleep for " + SMARTAP_PARAMS.time_to_start); Thread.sleep(SMARTAP_PARAMS.time_to_start); @@ -112,10 +117,10 @@ public void run() { e.printStackTrace(); } - // Write on file integration + // Integration of write on file functionality PrintStream ps = null; - if(SMARTAP_PARAMS.filename.length()>0){ + if(SMARTAP_PARAMS.filename.length()>0){ // check that the parameter exists File f = new File(SMARTAP_PARAMS.filename); try { ps = new PrintStream(f); @@ -123,12 +128,13 @@ public void run() { e.printStackTrace(); } } - agents = getAgents(); + + agents = getAgents(); // Fill the array of agents num_agents = agents.size(); // Number of agents channels = new int[num_agents]; // Array to store the channels in use - int[] channelsAux = new int[num_agents]; - + int[] channelsAux = new int[num_agents]; // Array of the channels in use by the auxiliary interfaces of each AP + // Add this information to the log file ps.println("[SmartAPSelection] Log file " + SMARTAP_PARAMS.filename); // Log in file ps.println("[SmartAPSelection] Parameters:"); ps.println("\tTime_to_start: " + SMARTAP_PARAMS.time_to_start); @@ -143,11 +149,12 @@ public void run() { ps.println("\tTxpowerSTA: " + SMARTAP_PARAMS.thReqSTA); ps.println("\tFilename: " + SMARTAP_PARAMS.filename); + // Array created to show the line with the names of the APs String showAPsLine = "\033[K\r[SmartAPSelection] "; - try { // Create Ip to compare with clients not assigned + try { // Create IP to compare with clients not assigned nullAddr = InetAddress.getByName("0.0.0.0"); - vipAPAddr = InetAddress.getByName(getVipAPIpAddress()); + vipAPAddr = InetAddress.getByName(getVipAPIpAddress()); // VIP AP } catch (UnknownHostException e) { e.printStackTrace(); } @@ -162,7 +169,7 @@ public void run() { int chann = getChannelFromAgent(agentAddr); //System.out.println("[SmartAPSelection] = Channels " + Arrays.toString(channels)); - Arrays.sort(channelsAux); + Arrays.sort(channelsAux); // ordered list of channels used by the main interface of the APs. A channel is only added once //System.out.println("[SmartAPSelection] = Search for "+chann+": " + Arrays.binarySearch(channelsAux, chann)); if(Arrays.binarySearch(channelsAux, chann) < 0){// if already in array, not necessary to add it @@ -182,24 +189,26 @@ public void run() { ind_aux++; } ps.println("[SmartAPSelection]"); - ps.flush(); + ps.flush(); // write in the log file (empty the buffer) vals_rx = new String[num_channels][num_agents]; // Matrix to store the results from agents Map rssiData = new HashMap (); // Map to store RSSI for each STA in all APs Map handoffDate = new HashMap (); // Map to store last handoff for each STA FIXME: Maybe create struct - Map ffData = new HashMap (); // Map to store Throughput available for each STA in all APs System.out.print("\033[2J"); // Clear screen and cursor to 0,0 char[] progressChar = new char[] { '-', '\\', '|', '/' }; int progressIndex = 0; + // From this moment, the detected flows are taken into account initDetection (); // Register flow detection + // Main loop while (true) { try { - Thread.sleep(100); + Thread.sleep(100); // milliseconds + // restart the clients hashset in order to see if there are new STAs clients = new HashSet(getClients()); int num_clients = clients.size(); // Number of STAs @@ -215,7 +224,9 @@ public void run() { System.out.print("\033[K\r\n\033[K\r\n\033[K\r\n\033[K\r\n\033[K\r\n\033[K\r\n\033[K\r\n\033[K\r\n\033[K\r\n\033[0;0H"); // Clear lines above and return to console 0,0 continue; } - int[] clientsChannels = new int[num_clients]; // Array with the indexes of channels, better performance in data process + + // if there are clients + int[] clientsChannels = new int[num_clients]; // Array with the indexes of channels of the STAs, better performance in data process // Various indexes @@ -228,7 +239,7 @@ public void run() { System.out.println("\033[K\r[SmartAPSelection]"); - + // For each STA, fill the array for (OdinClient oc: clients) { // Create array with client channels and their indexes for better data processing ind_aux = 0; @@ -251,8 +262,7 @@ public void run() { time = System.currentTimeMillis(); - //For each channel used in owned APs - + //For each channel used in our APs for (int channel = 0 ; channel < num_channels ; ++channel) { if(channels[channel]==0) @@ -260,13 +270,17 @@ public void run() { int agent = 0; scanningAgents.clear(); + + // For each agent, request the statistics for (InetAddress agentAddr: agents) { // Request statistics result = requestScannedStationsStatsFromAgent(agentAddr, channels[channel], SCANNED_SSID); + // Check if the request has been successful scanningAgents.put(agentAddr, result); } + // sleep during the scanning try { Thread.sleep(SMARTAP_PARAMS.scanning_interval + SMARTAP_PARAMS.added_time); } @@ -274,13 +288,16 @@ public void run() { e.printStackTrace(); } + // Recover the information after the scanning for (InetAddress agentAddr: agents) { // Reception statistics - if (scanningAgents.get(agentAddr) == 0) { + if (scanningAgents.get(agentAddr) == 0) { // Busy agent System.out.println("\033[K\r[SmartAPSelection] Agent BUSY during scanning operation"); continue; } + + // Agent non busy, so we recover the information vals_rx[channel][agent] = getScannedStaRssiFromAgent(agentAddr); agent++; } @@ -294,8 +311,7 @@ public void run() { client_index = 0; ind_aux = 0; - // For each client associated - + // For each STA (client) associated, store the RSSI value with which the APs "see" it for (OdinClient oc: clients) { MACAddress eth = oc.getMacAddress(); // client MAC @@ -310,30 +326,31 @@ public void run() { Double[] client_average_dBm = new Double[num_agents]; + // get the stored RSSI averaged value (historical data) client_average_dBm = rssiData.get(eth); if (client_average_dBm == null){// First time STA is associated client_average_dBm = new Double[num_agents]; - Arrays.fill(client_average_dBm,-99.9); - client_average_dBm[ind_aux] = rssi; + Arrays.fill(client_average_dBm,-99.9); // first, we put -99.9 everywhere + client_average_dBm[ind_aux] = rssi; // put the last value instead of -99.9 - }else{ + } else { + // Recalculate the new average if((client_average_dBm[ind_aux]!=-99.9)&&(client_average_dBm[ind_aux]!=null)){ if(rssi!=-99.9){ - Double client_signal = Math.pow(10.0, (rssi) / 10.0); // Linear power Double client_average = Math.pow(10.0, (client_average_dBm[ind_aux]) / 10.0); // Linear power average - client_average = client_average*(1-SMARTAP_PARAMS.weight) + client_signal*SMARTAP_PARAMS.weight; + client_average = client_average*(1-SMARTAP_PARAMS.weight) + client_signal*SMARTAP_PARAMS.weight; // use the "alpha" parameter (weight) to calculate the new value client_average_dBm[ind_aux] = Double.valueOf((double)Math.round(1000*Math.log10(client_average))/100); //Average power in dBm with 2 decimals - } }else{ + // It is the first time we have data of this STA in this AP client_average_dBm[ind_aux] = rssi; } } - rssiData.put(eth,client_average_dBm); + rssiData.put(eth,client_average_dBm); // Store all the data } client_index++; } @@ -346,10 +363,12 @@ public void run() { // Now comparation and handoff if it's needed time = System.currentTimeMillis(); - ps.println(time + " ms"); // Log in file + ps.println(time + " ms"); // Log file + // Array with the IP addresses of the Agents InetAddress[] agentsArray = agents.toArray(new InetAddress[0]); + // Write to screen the updated value of the averaged RSSI for (OdinClient oc: clients) { client_index = 0; @@ -361,12 +380,13 @@ public void run() { InetAddress clientAddr = oc.getIpAddress(); InetAddress agentAddr = oc.getLvap().getAgent().getIpAddress(); - if(clientAddr.equals(nullAddr))// If client not assigned, next one + if(clientAddr.equals(nullAddr))// If client not assigned, go to next one (associated, but without IP address) continue; System.out.println("\033[K\r[SmartAPSelection] \t\t\t\tClient " + clientAddr + " in agent " + agentAddr); ps.println("\tClient " + clientAddr + " in agent " + agentAddr); // Log in file + // Recover the information client_dBm = rssiData.get(eth); if (client_dBm != null){// Array with rssi @@ -375,7 +395,7 @@ public void run() { Double currentRssi = null; - for(ind_aux = 1; ind_aux < client_dBm.length; ind_aux++){//Get max position, VIP AP not considered + for(ind_aux = 1; ind_aux < client_dBm.length; ind_aux++){//Get the index of the AP where the STA has the highest RSSI, VIP AP not considered if((client_dBm[ind_aux]>maxRssi)&&(!vipAPAddr.equals(agentsArray[ind_aux]))){ maxRssi=client_dBm[ind_aux]; @@ -386,8 +406,7 @@ public void run() { // Printf with colours System.out.print("\033[K\r[SmartAPSelection] "); - - + // write to the screen the information with colours for(ind_aux = 0; ind_aux < client_dBm.length; ind_aux++){ if(agentsArray[ind_aux].equals(agentAddr)){ // Current AP @@ -410,40 +429,49 @@ public void run() { if(agentsArray[ind_aux].equals(vipAPAddr)){ System.out.print("[\033[48;5;94m" + String.format("%.2f",client_dBm[ind_aux]) + "\033[00m]"); // Orange }else{ - System.out.print("["+ String.format("%.2f",client_dBm[ind_aux]) +"]"); // + System.out.print("["+ String.format("%.2f",client_dBm[ind_aux]) +"]"); // No color } ps.println("\t\t[WorseAP] Rssi in agent " + agentsArray[ind_aux] + ": " + client_dBm[ind_aux] + " dBm"); // Log in file } } } // End prinft with colours - if(!SMARTAP_PARAMS.mode.equals("FF")){ // In BALANCER mode, it will assign STAs to APs always with higher RSSI than threshold, so there is not ping pong effect - if (!agentsArray[client_index].equals(agentAddr)){ // Change to the best RSSI - //If Rssi threshold is reached, handoff + + // this is used for all the modes except FF. If you also want a threshold in FF mode, substitute the next line with if(true){ + //if(!SMARTAP_PARAMS.mode.equals("FF")){ // In BALANCER mode, it will assign STAs to APs always with higher RSSI than threshold, so there is not ping pong effect + if(true){ // In BALANCER mode, it will assign STAs to APs always with higher RSSI than threshold, so there is not ping pong effect + if (!agentsArray[client_index].equals(agentAddr)){ // If the agent to which the STA is associated is not the one with the highest RSSI, change to the best RSSI + + //If Rssi threshold is reached, check hystheresis if(currentRssiSMARTAP_PARAMS.hysteresis_threshold)){ handoffClientToAp(eth,agentsArray[client_index]); - handoffDate.put(eth,Long.valueOf(System.currentTimeMillis())); + handoffDate.put(eth,Long.valueOf(System.currentTimeMillis())); // store the time for checking the hysteresis next time System.out.println(" - Handoff >--->--->---> "+agentsArray[client_index]); ps.println("\t\t[Action] Handoff to agent: " + agentsArray[client_index]); // Log in file }else{ - System.out.println(" - No Handoff: Hysteresis time not reached"); - ps.println("\t\t[No Action] No Handoff: Hysteresis time not reached"); // Log in file + System.out.println(" - No Handoff: Hysteresis time not expired"); + ps.println("\t\t[No Action] No Handoff: Hysteresis time not expired"); // Log in file } + }else{ + // The threshold is not reached if(SMARTAP_PARAMS.mode.equals("RSSI")){ System.out.println(" - No Handoff: Rssi Threshold not reached"); ps.println("\t\t[No Action] No Handoff: Rssi Threshold not reached"); // Log in file }else if(SMARTAP_PARAMS.mode.equals("DETECTOR")){ System.out.println(" - Assigned by DETECTOR"); ps.println("\t\t[No Action] No Handoff: Assigned by DETECTOR"); // Log in file + }else if(SMARTAP_PARAMS.mode.equals("FF")){ + System.out.println(" - Assigned by FF"); + ps.println("\t\t[No Action] No Handoff: Assigned by FF"); // Log in file }else{ System.out.println(" - Assigned by BALANCER"); ps.println("\t\t[No Action] No Handoff: Assigned by BALANCER"); // Log in file @@ -454,18 +482,20 @@ public void run() { ps.println("\t\t[No Action] There is no better Rssi heard"); // Log in file } } + + // FF mode if(SMARTAP_PARAMS.mode.equals("FF")){ // Calculate FF data - System.out.println(""); + System.out.println("\033[K\r[SmartAPSelection]"); ind_aux = 0; Double[] TH_av = new Double[num_agents]; for (InetAddress agentAddrFF: agents) { - if(oc.getLvap().getAgent().getIpAddress().equals(agentAddrFF)){ // If associated + if(oc.getLvap().getAgent().getIpAddress().equals(agentAddrFF)){ // If the STA is associated to this agent, use the real statistics // Reception statistics Map> vals_rx_FF = getRxStatsFromAgent(agentAddrFF); - Map vals_entry_rx = vals_rx_FF.get(eth); + Map vals_entry_rx = vals_rx_FF.get(eth); // Look for the statistics corresponding to this client (using the eth address) if(vals_entry_rx != null){ //System.out.println("\033[K\r[SmartAPSelection] avg rate: " + vals_entry_rx.get("avg_rate") + " kbps"); Double clientRate = Double.parseDouble(vals_entry_rx.get("avg_rate")); @@ -478,7 +508,7 @@ public void run() { TH_av[ind_aux] = 0.0; } - }else{ // Not associated + }else{ // if the STA is NOT associated to this agent, estimate the available throughput double txpowerAP = Math.pow(10.0, (getTxPowerFromAgent(agentAddrFF)) / 10.0); double txpowerSTA = Math.pow(10.0, (SMARTAP_PARAMS.txpowerSTA) / 10.0); double rssiDL = client_dBm[ind_aux]+10.0*Math.log10(txpowerAP/txpowerSTA); @@ -504,10 +534,10 @@ public void run() { if(SMARTAP_PARAMS.mode.equals("FF")){ // Show FF results and handoff if necessary System.out.println("\033[K\r[SmartAPSelection] ===================="); System.out.println(showAPsLine + " - FF Throughput available [Mbps]\033[00m"); - + + // obtain the FF values for each client on each AP for (OdinClient oc: clients) { - - + ind_aux = 0; client_index = 0; MACAddress eth = oc.getMacAddress(); // client MAC InetAddress clientAddr = oc.getIpAddress(); @@ -523,96 +553,144 @@ public void run() { //System.out.println("\033[K\r[SmartAPSelection] th_avFF= "+Arrays.toString(th_avFF)); Double maxFF = calculateFittingnessFactor(SMARTAP_PARAMS.thReqSTA,th_avFF[0]); // Start with first Th_av Double currentTh_av = null; - System.out.println("\033[K\r[SmartAPSelection] ff[0]="+maxFF); + System.out.print("\033[K\r[SmartAPSelection] ff["+ind_aux+"]=" + String.format("%.3f",maxFF) + " "); + + ArrayList th_list = new ArrayList(); // To sort FF + th_list.add(0); // First FF + for(ind_aux = 1; ind_aux < th_avFF.length; ind_aux++){//Get max position and calculate FF Double currentFF = calculateFittingnessFactor(SMARTAP_PARAMS.thReqSTA,th_avFF[ind_aux]); - - if(currentFF>maxFF){ - maxFF=currentFF; - client_index = ind_aux; - } - System.out.println("\033[K\r[SmartAPSelection] ff["+ind_aux+"]="+currentFF); + boolean added_FF = false; + + for(int ind_list = 0; ind_list < th_list.size(); ind_list++){ + + if(currentFF>th_list.get(ind_list)){ + maxFF=currentFF; + client_index = ind_aux; + th_list.add(ind_list,ind_aux); + added_FF = true; + break; + } + } + if(!added_FF) + th_list.add(ind_aux); // Not max FF + + System.out.print("ff["+ind_aux+"]=" + String.format("%.3f",currentFF) + " "); } - + System.out.println(""); System.out.print("\033[K\r[SmartAPSelection] "); - + + // Print the results with colours for(ind_aux = 0; ind_aux < th_avFF.length; ind_aux++){ if(agentsArray[ind_aux].equals(agentAddr)){ // Current AP currentTh_av = th_avFF[ind_aux]; - System.out.print("[ \033[48;5;29;1m" + String.format("%.2f",th_avFF[ind_aux]/1000.0) + "\033[00m]"); // Dark Green - ps.println("\t\t[Associated] Throughput in agent " + agentsArray[ind_aux] + ": " + th_avFF[ind_aux] + " kbps"); // Log in file + if(currentTh_av!=0.0){ + System.out.print("[\033[48;5;29;1m" + String.format("%.2f",th_avFF[ind_aux]/1000.0) + "\033[00m]"); // Dark Green + ps.println("\t\t[Associated] Throughput in agent " + agentsArray[ind_aux] + ": " + th_avFF[ind_aux] + " kbps"); // Log in file + }else{ + System.out.print("[\033[48;5;29;1m" + "-----" + "\033[00m]"); // Dark Green + ps.println("\t\t[Associated] No packets received"); // Log in file + } }else{ if(ind_aux==client_index){ // Max - System.out.print("[ \033[48;5;88m" + String.format("%.2f",th_avFF[ind_aux]/1000.0) + "\033[00m]"); // Dark red + System.out.print("[\033[48;5;88m" + String.format("%.2f",th_avFF[ind_aux]/1000.0) + "\033[00m]"); // Dark red ps.println("\t\t[BetterAP] Throughput in agent " + agentsArray[ind_aux] + ": " + th_avFF[ind_aux] + " kbps"); // Log in file }else{ - System.out.print("[ "+ String.format("%.2f",th_avFF[ind_aux]/1000.0) +"]"); // + System.out.print("["+ String.format("%.2f",th_avFF[ind_aux]/1000.0) +"]"); // ps.println("\t\t[WorseAP] Throughput in agent " + agentsArray[ind_aux] + ": " + th_avFF[ind_aux] + " kbps"); // Log in file } } } - if (!agentsArray[client_index].equals(agentAddr)){ // Change to the best FF - - Long handoffTime = handoffDate.get(eth); - - //If Time threshold is reached, handoff - if((handoffTime==null)||((System.currentTimeMillis()-handoffTime.longValue())/1000>SMARTAP_PARAMS.hysteresis_threshold)){ - - if(!(currentTh_av==0.0)){ - handoffClientToAp(eth,agentsArray[client_index]); - handoffDate.put(eth,Long.valueOf(System.currentTimeMillis())); - System.out.println("\033[0;1m - Handoff >--->--->---> "+agentsArray[client_index]+"\033[00m"); - ps.println("\t\t[Action] Handoff to agent: " + agentsArray[client_index]); // Log in file - }else{ - System.out.println(""); // No rate received - } - }else{ - System.out.println("\033[0;1m - No Handoff: Hysteresis time not reached\033[00m"); - ps.println("\t\t[No Action] No Handoff: Hysteresis time not reached"); // Log in file - } - - }else{ - System.out.println(""); // Best AP already - ps.println("\t\t[No Action] There is no better FF"); // Log in file - } + + for(int ind_list = 0; ind_list < th_list.size(); ind_list++){ + + client_index = th_list.get(ind_list); + + // Order the handoff to the AP with the highest FF + if (!agentsArray[client_index].equals(agentAddr)){ // Change to the best FF + + //If Rssi threshold is reached, check hystheresis + Double[] client_dBm = rssiData.get(eth); + Double currentRssi = client_dBm[client_index]; + if(currentRssiSMARTAP_PARAMS.hysteresis_threshold)){ + + // make sure that you have received at least one packet + if(!(currentTh_av==0.0)){ + handoffClientToAp(eth,agentsArray[client_index]); + handoffDate.put(eth,Long.valueOf(System.currentTimeMillis())); + System.out.println("\033[0;1m - Handoff >--->--->---> "+agentsArray[client_index]+"\033[00m"); + ps.println("\t\t[Action] Handoff to agent: " + agentsArray[client_index]); // Log in file + break; + }else{ + System.out.println(""); // No packets received + ps.println("\t\t[No Action] No packets received"); // Log in file + break; + } + }else{ + System.out.println("\033[0;1m - No Handoff: Hysteresis time not reached\033[00m"); + ps.println("\t\t[No Action] No Handoff: Hysteresis time not reached"); // Log in file + break; + } + }else{ + //System.out.println(" - No Handoff: Rssi Threshold not reached"); + ps.println("\t\t[No Action] No Handoff: Rssi Threshold not reached, try next FF"); // Log in file + continue; + } + }else{ + System.out.println(""); // Best AP already + ps.println("\t\t[No Action] There is no better FF"); // Log in file + break; + } + } } + System.out.println("\033[K\r[SmartAPSelection]"); System.out.println("\033[K\r[SmartAPSelection] ===================="); } + + // BALANCER and JAIN-BALANCER modes if((SMARTAP_PARAMS.mode.equals("BALANCER"))||(SMARTAP_PARAMS.mode.equals("JAIN-BALANCER"))){ - Map assignedClients = new HashMap (); // Array with the balancer decission + Map assignedClients = new HashMap (); // Array with the balancer decission MAC of the STA - IP of the AP System.out.println("\033[K\r[SmartAPSelection] ===================="); - if(SMARTAP_PARAMS.mode.equals("JAIN-BALANCER")){ - - System.out.println(showAPsLine + " - Jain's Fairness index Balancer\033[00m"); - System.out.print("\033[K\r[SmartAPSelection] "); - assignedClients = jainsFairnessIndex(rssiData, agentsArray, clients, SMARTAP_PARAMS.signal_threshold); // More complex algorithm - - }else{ - - System.out.println(showAPsLine + " - Balancer\033[00m"); - System.out.print("\033[K\r[SmartAPSelection] "); - assignedClients = simpleBalancerAlgorithm(rssiData, agentsArray, clients, SMARTAP_PARAMS.signal_threshold); // Very simple balancer algorithm - System.out.println(""); - - } + if(SMARTAP_PARAMS.mode.equals("JAIN-BALANCER")){ + + System.out.println(showAPsLine + " - Jain's Fairness index Balancer\033[00m"); + System.out.print("\033[K\r[SmartAPSelection] "); + assignedClients = jainsFairnessIndex(rssiData, agentsArray, clients, SMARTAP_PARAMS.signal_threshold); // More complex algorithm + }else{ + + System.out.println(showAPsLine + " - Balancer\033[00m"); + System.out.print("\033[K\r[SmartAPSelection] "); + assignedClients = simpleBalancerAlgorithm(rssiData, agentsArray, clients, SMARTAP_PARAMS.signal_threshold); // Very simple balancer algorithm + System.out.println(""); + } + + // for each STA for which a handoff has been ordered for(MACAddress eth:assignedClients.keySet()){ Long handoffTime = handoffDate.get(eth); System.out.print("\033[K\r[SmartAPSelection] "); OdinClient clientHandoff = getClientFromHwAddress(eth); + // Check hysteresis if((handoffTime==null)||((System.currentTimeMillis()-handoffTime.longValue())/1000>SMARTAP_PARAMS.hysteresis_threshold)){ InetAddress assignedAgent = assignedClients.get(eth); + + // Do the handoff if(getClientFromHwAddress(eth)!=null){ handoffClientToAp(eth,assignedAgent); handoffDate.put(eth,Long.valueOf(System.currentTimeMillis())); @@ -622,13 +700,15 @@ public void run() { }else{ - System.out.print("No Handoff "+clientHandoff.getIpAddress()+": Hysteresis time not reached"); - ps.println("\t\t[No Action] No Handoff: Hysteresis time not reached"); // Log in file + System.out.print("No Handoff "+clientHandoff.getIpAddress()+": Hysteresis time not expired"); + ps.println("\t\t[No Action] No Handoff: Hysteresis time not expired"); // Log in file } System.out.println(""); } } + + // DETECTOR mode if(SMARTAP_PARAMS.mode.equals("DETECTOR")){ // If a flow is detected, the STA is moved to the VIP AP FIXME minimum rssi System.out.println("\033[K\r[SmartAPSelection] ===================="); System.out.println(showAPsLine + " - DETECTOR - AP VIP: "+vipAPAddr+"\033[00m"); @@ -651,12 +731,16 @@ public void run() { if((System.currentTimeMillis()-cntx.timeStamp)>30000){ // Clean flow after 30 sec flowsReceived.remove(clientAddr); System.out.print("\033[K\r\t[Flow] Clean flow from client " + clientAddr + " - Handoff\n"); - handoffClientToAp(eth,cntx.lastAgentAddr); + handoffClientToAp(eth,cntx.lastAgentAddr); // send the STA back to the AP where it was before the handoff to the VIP AP }else{ InetAddress agentAddr = oc.getLvap().getAgent().getIpAddress(); if(!vipAPAddr.equals(agentAddr)){ Double[] client_dBm = rssiData.get(eth); + + // Check if the signal level is above the threshold if(client_dBm[vip_index]>SMARTAP_PARAMS.signal_threshold){ + + // move the STA to the VIP AP System.out.print("\033[K\r\t[Flow] Detected flow from client " + clientAddr + " - Handoff\n"); cntx.lastAgentAddr = agentAddr; flowsReceived.put(clientAddr,cntx); @@ -672,14 +756,14 @@ public void run() { System.out.print("\033[K\r\t[Flow] No flow for client "+clientAddr+"\n"); }*/ } - for(OdinClient oc:getClientsFromAgent(vipAPAddr)){ // In case STA is associated before the app stars + + // A new STA may have associated to the VIP AP. Remove it from there. This can be improved. FIXME + for(OdinClient oc:getClientsFromAgent(vipAPAddr)){ // In case STA is associated before the app starts MACAddress eth = oc.getMacAddress(); // client MAC InetAddress clientAddr = oc.getIpAddress(); // client IP if(!flowsReceived.containsKey(clientAddr)){ - - handoffClientToAp(eth,nonVipAPAddr); - + handoffClientToAp(eth,nonVipAPAddr); } } } @@ -763,36 +847,36 @@ private double[] getTransmissionTime(double avgRate){ // Returns transmission ti } } private double getOFDMRates(double SNR){ // Returns ODFM rates to calculate THavg - - double result = 0.0; - - if(SNR>21.0){ // If higher value not reached, we use the next lower values - result = 54000.0; - return result; - }else if (SNR>=20.0){ - result = 48000.0; - return result; - }else if (SNR>=16.0){ - result = 36000.0; - return result; - }else if (SNR>=12.0){ - result = 24000.0; - return result; - }else if (SNR>=9.0){ - result = 18000.0; - return result; - }else if (SNR>=7.0){ - result = 12000.0; - return result; - }else if (SNR>=5.0){ - result = 9000.0; - return result; - }else if (SNR>=4.0){ - result = 6000.0; - return result; - }else { // Less than 4 dB => 0.0 - return result; - } + + double result = 0.0; + + if(SNR>21.0){ // If higher value not reached, we use the next lower values + result = 54000.0; + return result; + }else if (SNR>=20.0){ + result = 48000.0; + return result; + }else if (SNR>=16.0){ + result = 36000.0; + return result; + }else if (SNR>=12.0){ + result = 24000.0; + return result; + }else if (SNR>=9.0){ + result = 18000.0; + return result; + }else if (SNR>=7.0){ + result = 12000.0; + return result; + }else if (SNR>=5.0){ + result = 9000.0; + return result; + }else if (SNR>=4.0){ + result = 6000.0; + return result; + }else { // Less than 4 dB => 0.0 + return result; + } } private double calculateFittingnessFactor(double Rreq, double Rb){ @@ -891,18 +975,18 @@ private Map simpleBalancerAlgorithm(Map jainsFairnessIndex(Map rssiData, InetAddress[] agentsArray, HashSet clients, Double threshold){ // Print load in each AP and returns array of agents to assign int ind_aux = 0; - int agent_index = 0; + int agent_index = 0; int[] numStasPerAgent = new int[agentsArray.length]; boolean orderHandoff = false; Map arrayHandoff = new HashMap (); - Map agentIndex = new HashMap (); - + Map agentIndex = new HashMap (); + HashSet clients_Balancer; int num_clients = clients.size(); @@ -988,104 +1075,104 @@ private Map jainsFairnessIndex(MapmaxFI)&&(client_dBm[agentIndex.get(agentAddrBalancer)]>SMARTAP_PARAMS.signal_threshold)){ - maxFI = fairnessIndex[agentIndex.get(agentAddrBalancer)]; - index_maxFI = agentIndex.get(agentAddrBalancer); - } - } - - ind_aux = 0; - - System.out.print("\033[K\r[SmartAPSelection] "); - for (Double fair_index: fairnessIndex) { - - if(ind_aux==agent_index_assoc){ // Green - System.out.print("[\033[48;5;29;1m " + String.format("%.2f",fair_index)+" \033[00m]"); - }else if(ind_aux==index_maxFI){ // Red - System.out.print("[\033[48;5;88m " + String.format("%.2f",fair_index)+" \033[00m]"); - }else{ // Other - System.out.print("[ " + String.format("%.2f",fair_index)+" ]"); - } - ind_aux++; + }else{ // numSTAs changed + + agent_index = agentIndex.get(agentAddrBalancer); + + for(int stas: numStasPerAgent){ + + if(agent_index == ind_aux){ + sum = sum + Math.pow(stas+1, 2); + }else if(agent_index_assoc == ind_aux){ + sum = sum + Math.pow(stas-1, 2); + }else{ + sum = sum + Math.pow(stas, 2); } - System.out.print(" - "+clientAddr); - if((client_dBm[index_maxFI]>SMARTAP_PARAMS.signal_threshold)&&(index_maxFI!=agent_index_assoc)){ - arrayHandoff.put(eth,agentsArray[index_maxFI]); - System.out.println("\033[0;1m - Handoff ordered\033[00m"); - break; // FIXME: allow several handoffs ordered at the same time - }else{ - System.out.println(""); - } + + ind_aux++; + + } + + fairnessIndex[agentIndex.get(agentAddrBalancer)] = num_clients / (num_agents*sum); + } - } - + if((fairnessIndex[agentIndex.get(agentAddrBalancer)]>maxFI)&&(client_dBm[agentIndex.get(agentAddrBalancer)]>SMARTAP_PARAMS.signal_threshold)){ + maxFI = fairnessIndex[agentIndex.get(agentAddrBalancer)]; + index_maxFI = agentIndex.get(agentAddrBalancer); + } + } + + ind_aux = 0; + + System.out.print("\033[K\r[SmartAPSelection] "); + for (Double fair_index: fairnessIndex) { + + if(ind_aux==agent_index_assoc){ // Green + System.out.print("[\033[48;5;29;1m " + String.format("%.2f",fair_index)+" \033[00m]"); + }else if(ind_aux==index_maxFI){ // Red + System.out.print("[\033[48;5;88m " + String.format("%.2f",fair_index)+" \033[00m]"); + }else{ // Other + System.out.print("[ " + String.format("%.2f",fair_index)+" ]"); + } + ind_aux++; + } + System.out.print(" - "+clientAddr); + if((client_dBm[index_maxFI]>SMARTAP_PARAMS.signal_threshold)&&(index_maxFI!=agent_index_assoc)){ + arrayHandoff.put(eth,agentsArray[index_maxFI]); + System.out.println("\033[0;1m - Handoff ordered\033[00m"); + break; // FIXME: allow several handoffs ordered at the same time + }else{ + System.out.println(""); + } + } + } + return arrayHandoff; } }