Skip to content

Commit

Permalink
Merge branch 'Development'
Browse files Browse the repository at this point in the history
Merging Development branch. This version includes functionalities for client scanning by means of a secondary wireless interface.
  • Loading branch information
luissequeira committed Apr 25, 2017
2 parents 257a2f9 + b1ee7fd commit cb4a5ee
Show file tree
Hide file tree
Showing 10 changed files with 314 additions and 13 deletions.
2 changes: 1 addition & 1 deletion odin_client_list
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20:68:3F:60:2A:F2 192.168.1.12 00:1B:B3:67:6B:12 odin-wi5-labtel
20:68:3F:60:2A:F2 192.168.1.12 00:1B:B3:67:6B:12 wi5-demo
6 changes: 3 additions & 3 deletions poolfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Pool-1
NAME pool-1
NODES 192.168.1.5 192.168.1.6
NETWORKS odin-wi5-labtel
APPLICATIONS net.floodlightcontroller.odin.applications.HandoverMultichannel
NODES 192.168.1.9 192.168.1.10
NETWORKS wi5-demo
APPLICATIONS net.floodlightcontroller.odin.applications.ShowStatistics

# Pool-2
#NAME pool-2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class HandoverMultichannel extends OdinApplication {
private final int INTERVAL = 60000; // time before running the application. This leaves you some time for starting the agents

public HandoverMultichannel () {
this.HYSTERESIS_THRESHOLD = 30000;
this.HYSTERESIS_THRESHOLD = 15000;
this.IDLE_CLIENT_THRESHOLD = 180000; // Must to be bigger than HYSTERESIS_THRESHOLD
this.SIGNAL_STRENGTH_THRESHOLD = 0;
}
Expand All @@ -40,8 +40,8 @@ private void init () {
OdinEventSubscription oes = new OdinEventSubscription();
/* FIXME: Add something in order to subscribe more than one STA */
//oes.setSubscription("40:A5:EF:E5:93:DF", "signal", Relation.GREATER_THAN, 0); // One client
//oes.setSubscription("*", "signal", Relation.GREATER_THAN, 0); // All clients
oes.setSubscription("24:FD:52:E7:60:6E", "signal", Relation.GREATER_THAN, 0); // white laptop
oes.setSubscription("*", "signal", Relation.GREATER_THAN, 0); // All clients
//oes.setSubscription("24:FD:52:E7:60:6E", "signal", Relation.GREATER_THAN, 0); // white laptop

NotificationCallback cb = new NotificationCallback() {
@Override
Expand All @@ -61,7 +61,7 @@ public void run() {
} catch (InterruptedException e){
e.printStackTrace();
}
//asigmentChannel();
//assigmentChannel();
init ();
}

Expand Down Expand Up @@ -182,7 +182,7 @@ public MobilityStats (long signalStrength, long lastHeard, long assignmentTimest
}
}
private void asigmentChannel () {
private void assigmentChannel () {
for (InetAddress agentAddr: getAgents()) {
log.info("HandoverMultichannel: Agent IP: " + agentAddr.getHostAddress());
if (agentAddr.getHostAddress().equals("192.168.1.7")){
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
package net.floodlightcontroller.odin.applications;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.floodlightcontroller.odin.master.OdinApplication;

import net.floodlightcontroller.odin.master.NotificationCallback;
import net.floodlightcontroller.odin.master.NotificationCallbackContext;
import net.floodlightcontroller.odin.master.OdinClient;
import net.floodlightcontroller.odin.master.OdinEventSubscription;
import net.floodlightcontroller.odin.master.OdinMaster;
import net.floodlightcontroller.odin.master.OdinEventSubscription.Relation;
import net.floodlightcontroller.util.MACAddress;

public class MobilityManager extends OdinApplication {
protected static Logger log = LoggerFactory.getLogger(MobilityManager.class);
/* A table including each client and its mobility statistics */
private ConcurrentMap<MACAddress, MobilityStats> clientMap = new ConcurrentHashMap<MACAddress, MobilityStats> ();
private final long HYSTERESIS_THRESHOLD; // milliseconds
private final long IDLE_CLIENT_THRESHOLD; // Must to be bigger than HYSTERESIS_THRESHOLD (milliseconds)
private final long SIGNAL_STRENGTH_THRESHOLD; // Signal strength threshold
private final long SIGNAL_THRESHOLD; // Signal threshold (milliseconds)
private final int SCANNING_TIME; // Time (milliseconds) for scanning in another agent
private final String STA; // Handle a mac or all STAs ("*")
private final String VALUE; // Parameter to measure (signal, noise, rate, etc.)
private boolean scan; // For testing only once

public MobilityManager () {
this.HYSTERESIS_THRESHOLD = 15000;
this.IDLE_CLIENT_THRESHOLD = 180000;
this.SIGNAL_STRENGTH_THRESHOLD = 0;
this.SIGNAL_THRESHOLD = 215;
this.SCANNING_TIME = 1000;
this.STA = "*";
this.VALUE = "signal";
this.scan = true;
}

/**
* Register subscriptions
*/
private void init () {
OdinEventSubscription oes = new OdinEventSubscription();
/* FIXME: Add something in order to subscribe more than one STA */
oes.setSubscription(this.STA, this.VALUE, Relation.LESSER_THAN, this.SIGNAL_THRESHOLD);
NotificationCallback cb = new NotificationCallback() {
@Override
public void exec(OdinEventSubscription oes, NotificationCallbackContext cntx) {
if (scan == true) // For testing only once
handler(oes, cntx);
}
};
/* Before executing this line, make sure the agents declared in poolfile are started */
registerSubscription(oes, cb);
}

@Override
public void run() {
/* When the application runs, you need some time to start the agents */
this.giveTime(30000);
//this.channelAssignment();
//this.giveTime(10000);
//setAgentTimeout(10000);
init ();
}

/**
* This method will handoff a client in the event of its
* agent having failed.
*
* @param oes
* @param cntx
*/
private void handler (OdinEventSubscription oes, NotificationCallbackContext cntx) {
OdinClient client = getClientFromHwAddress(cntx.clientHwAddress);
long lastScanningResult = 0;
/* The client is not registered in Odin, exit */
if (client == null)
return;
long currentTimestamp = System.currentTimeMillis();
// Assign mobility stats object if not already done
// add an entry in the clientMap table for this client MAC
// put the statistics in the table: value of the parameter, timestamp, timestamp, agent, scanning result
if (!clientMap.containsKey(cntx.clientHwAddress)) {
clientMap.put(cntx.clientHwAddress, new MobilityStats(cntx.value, currentTimestamp, currentTimestamp, cntx.agent.getIpAddress(), cntx.value));
}
// get the statistics of that client
MobilityStats stats = clientMap.get(cntx.clientHwAddress);

/* Now, handoff */

// The client is associated to Odin (it has an LVAP), but it does not have an associated agent
// If client hasn't been assigned an agent, associate it to the current AP
if (client.getLvap().getAgent() == null) {
log.info("MobilityManager: client hasn't been asigned an agent: handing off client " + cntx.clientHwAddress
+ " to agent " + stats.agentAddr + " at " + System.currentTimeMillis());
handoffClientToAp(cntx.clientHwAddress, stats.agentAddr);
updateStatsWithReassignment (stats, cntx.value, currentTimestamp, stats.agentAddr, stats.scanningResult);
return;
}

// Check for out-of-range client
// a client has sent nothing during a certain time
if ((currentTimestamp - stats.lastHeard) > IDLE_CLIENT_THRESHOLD) {
log.info("MobilityManager: client with MAC address " + cntx.clientHwAddress
+ " was idle longer than " + IDLE_CLIENT_THRESHOLD/1000 + " sec -> Reassociating it to agent " + stats.agentAddr);
handoffClientToAp(cntx.clientHwAddress, stats.agentAddr);
updateStatsWithReassignment (stats, cntx.value, currentTimestamp, stats.agentAddr, stats.scanningResult);
return;
}

// If this notification is from the agent that's hosting the client's LVAP scan, update MobilityStats and handoff.
if (client.getLvap().getAgent().getIpAddress().equals(cntx.agent.getIpAddress())) {
// Don't bother if we're not within hysteresis period
if (currentTimestamp - stats.assignmentTimestamp < HYSTERESIS_THRESHOLD)
return;
/* Scan and update statistics */
for (InetAddress agentAddr: getAgents()) { // FIXME: scan for nearby agents only
if (cntx.agent.getIpAddress().equals(agentAddr)) {
log.info("MobilityManager: Do not Scan client " + cntx.clientHwAddress + " in agent " + agentAddr + " and channel " + getChannelFromAgent(agentAddr));
continue; // Skip same AP
}
else {
log.info("MobilityManager: Scanning client " + cntx.clientHwAddress + " in agent " + agentAddr + " and channel " + getChannelFromAgent(cntx.agent.getIpAddress()));
lastScanningResult = scanClientFromAgent(agentAddr, cntx.clientHwAddress, getChannelFromAgent(cntx.agent.getIpAddress()), this.SCANNING_TIME);
//scan = false; // For testing only once
if (lastScanningResult >= stats.signalStrength) {
//if (lastScanningResult >= 50) { // testing
updateStatsWithReassignment(stats, lastScanningResult, currentTimestamp, agentAddr, lastScanningResult);
}
else {
updateStatsWithReassignment(stats, cntx.value, currentTimestamp, stats.agentAddr, stats.scanningResult);
}
log.info("MobilityManager: Scaned client " + cntx.clientHwAddress + " in agent " + agentAddr + " and channel " + getChannelFromAgent(cntx.agent.getIpAddress()) + " with power " + lastScanningResult);
}
}
log.info("MobilityManager: signal strengths: new = " + lastScanningResult + " old = " + stats.signalStrength + " + " + SIGNAL_STRENGTH_THRESHOLD + " :" + "handing off client " + cntx.clientHwAddress
+ " to agent " + stats.agentAddr);
handoffClientToAp(cntx.clientHwAddress, stats.agentAddr);
return;
}

}

/**
* This method will update statistics
*
* @param stats
* @param signalValue
* @param now
* @param agentAddr
* @param scanningResult
*/
private void updateStatsWithReassignment (MobilityStats stats, long signalValue, long now, InetAddress agentAddr, long scanningResult) {
stats.signalStrength = signalValue;
stats.lastHeard = now;
stats.assignmentTimestamp = now;
stats.agentAddr = agentAddr;
stats.scanningResult = scanningResult;
}

/**
* Sleep
*
* @param time
*/
private void giveTime (int time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

/**
* It will be a method for channel assignment
*
* FIXME: Do it in a suitable way
*/
private void channelAssignment () {
for (InetAddress agentAddr: getAgents()) {
log.info("MobilityManager: Agent IP: " + agentAddr.getHostAddress());
if (agentAddr.getHostAddress().equals("192.168.1.9")){
log.info ("MobilityManager: Agent channel: " + getChannelFromAgent(agentAddr));
setChannelToAgent(agentAddr, 1);
log.info ("MobilityManager: Agent channel: " + getChannelFromAgent(agentAddr));
}
if (agentAddr.getHostAddress().equals("192.168.1.10")){
log.info ("MobilityManager: Agent channel: " + getChannelFromAgent(agentAddr));
setChannelToAgent(agentAddr, 11);
log.info ("MobilityManager: Agent channel: " + getChannelFromAgent(agentAddr));
}

}
}

private class MobilityStats {
public long signalStrength;
public long lastHeard; // timestamp where it was heard the last time
public long assignmentTimestamp; // timestamp it was assigned
public InetAddress agentAddr;
public long scanningResult;

public MobilityStats (long signalStrength, long lastHeard, long assignmentTimestamp, InetAddress agentAddr, long scanningResult) {
this.signalStrength = signalStrength;
this.lastHeard = lastHeard;
this.assignmentTimestamp = assignmentTimestamp;
this.agentAddr = agentAddr;
this.scanningResult = scanningResult;
}
}

}
12 changes: 12 additions & 0 deletions src/main/java/net/floodlightcontroller/odin/master/IOdinAgent.java
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,16 @@ public interface IOdinAgent {
*/
public int convertChannelToFrequency(int chan);


/**
* Scanning for a client in a specific agent (AP)
*
* @param Client MAC
* @param Channel
* @param Scanning time
* @return Signal power
*
*/
public int scanClient (MACAddress clientHwAddr, int channel, int time);

}
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,19 @@ interface IOdinMasterToApplicationInterface {
* @author Luis Sequeira <[email protected]>
*/
//void sendChannelSwitchToClient (String pool, InetAddress agentAddr, MACAddress clientHwAddr, List<String> lvapSsids, int channel);

/**
* Scanning for a client in a specific agent (AP)
*
* @param Pool
* @param Agent InetAddress
* @param Client MAC
* @param Channel
* @param Scanning time
* @return Signal power
* @author Luis Sequeira <[email protected]>
*/
int scanClientFromAgent (String pool, InetAddress agentAddr, MACAddress clientHwAddr, int channel, int time);


}
29 changes: 26 additions & 3 deletions src/main/java/net/floodlightcontroller/odin/master/OdinAgent.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class OdinAgent implements IOdinAgent {
private InetAddress ipAddress;
private long lastHeard;
private int channel;
private int lastScan;

private ConcurrentSkipListSet<OdinClient> clientList = new ConcurrentSkipListSet<OdinClient>();

Expand All @@ -59,6 +60,7 @@ class OdinAgent implements IOdinAgent {
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";
private static final String READ_HANDLER_SCAN_CLIENT = "scan_client";
private static final String WRITE_HANDLER_ADD_VAP = "add_vap";
private static final String WRITE_HANDLER_SET_VAP = "set_vap";
private static final String WRITE_HANDLER_REMOVE_VAP = "remove_vap";
Expand All @@ -67,6 +69,7 @@ class OdinAgent implements IOdinAgent {
private static final String WRITE_HANDLER_SPECTRAL_SCAN = "spectral_scan";
private static final String WRITE_HANDLER_CHANNEL = "channel";
private static final String WRITE_HANDLER_CHANNEL_SWITCH_ANNOUNCEMENT = "channel_switch_announcement";
private static final String WRITE_HANDLER_SCAN_CLIENT = "scan_client";
private static final String ODIN_AGENT_ELEMENT = "odinagent";

private final int TX_STAT_NUM_PROPERTIES = 7;
Expand Down Expand Up @@ -530,8 +533,6 @@ public void setChannel(int channel) {
//Wi5- TODO: We should announce to the APs the change of the channel. This need futher discusssion
if(channel != this.channel)
this.channel = channel;
// Next line can be commented when using iw/iwconfig to change the channel in the AP. Do not comment when using hostapd_cli
channel = this.convertChannelToFrequency(channel);
String chan = Integer.toString(channel);
invokeWriteHandler(WRITE_HANDLER_CHANNEL, chan);
}
Expand Down Expand Up @@ -560,7 +561,7 @@ public void sendChannelSwitch(MACAddress clientHwAddr, MACAddress bssid, List<St
}
invokeWriteHandler(WRITE_HANDLER_CHANNEL_SWITCH_ANNOUNCEMENT, sb.toString());
}

public int convertFrequencyToChannel(int freq) {
if (freq >= 2412 && freq <= 2484) {
int chan = (freq - 2412) / 5 + 1;
Expand All @@ -584,4 +585,26 @@ public int convertChannelToFrequency(int chan) {
return -1;
}
}


@Override
public int scanClient(MACAddress clientHwAddr, int channel, int time) {
StringBuilder sb = new StringBuilder();
sb.append(clientHwAddr);
sb.append(" ");
sb.append(channel);
log.info("Sending WRITE_HANDLER_SCAN_CLIENT " + sb.toString());
invokeWriteHandler(WRITE_HANDLER_SCAN_CLIENT, sb.toString());
try {
Thread.sleep(time);
} catch (InterruptedException e){
e.printStackTrace();
}
log.info("Sending READ_HANDLER_SCAN_CLIENT");
String handler = invokeReadHandler(READ_HANDLER_SCAN_CLIENT);
lastScan = Integer.parseInt(handler.trim());
log.info("READ_HANDLER_SCAN_CLIENT " + lastScan);
return lastScan;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -199,5 +199,18 @@ protected final int getChannelFromAgent (InetAddress agentAddr){
/*protected final void sendChannelSwitchToClient (InetAddress agentAddr, MACAddress clientHwAddr, String ssid, int channel){
odinApplicationInterfaceToMaster.sendChannelSwitchToClient(pool, agentAddr, clientHwAddr, ssid, channel);
}*/

/**
* Scanning for a client in a specific agent (AP)
*
* @param Agent InetAddress
* @param Client MAC
* @param Channel
* @param Scanning time
* @return Signal power
*/
protected final int scanClientFromAgent (InetAddress agentAddr, MACAddress clientHwAddr, int channel, int time){
return odinApplicationInterfaceToMaster.scanClientFromAgent(pool, agentAddr, clientHwAddr, channel, time);
}

}
Loading

0 comments on commit cb4a5ee

Please sign in to comment.