by northbound API calls (see analytics.py).
Signed-off-by: Katrina LaCurts <katrina.lacurts@plexxi.com>
<configuration>
<instructions>
<Import-Package>
+ org.opendaylight.controller.affinity,
org.opendaylight.controller.analytics,
org.opendaylight.controller.clustering.services,
org.opendaylight.controller.hosttracker,
org.opendaylight.controller.sal.reader,
org.opendaylight.controller.sal.utils,
org.opendaylight.controller.statisticsmanager,
- org.opendaylight.controller.switchmanager,
org.apache.felix.dm,
org.slf4j
</Import-Package>
</plugins>
</build>
<dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>affinity</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>analytics</artifactId>
<artifactId>statisticsmanager</artifactId>
<version>0.4.0-SNAPSHOT</version>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>switchmanager</artifactId>
- <version>0.5.0-SNAPSHOT</version>
- </dependency>
</dependencies>
</project>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.opendaylight.controller.affinity.IAffinityManager;
import org.opendaylight.controller.analytics.IAnalyticsManager;
import org.opendaylight.controller.clustering.services.IClusterContainerServices;
import org.opendaylight.controller.hosttracker.IfIptoHost;
import org.opendaylight.controller.sal.reader.IReadService;
import org.opendaylight.controller.sal.reader.IReadServiceListener;
import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
-import org.opendaylight.controller.switchmanager.ISwitchManager;
public class Activator extends ComponentActivatorAbstractBase {
protected static final Logger logger = LoggerFactory
.setCallbacks("setHostTracker", "unsetHostTracker").setRequired(true));
c.add(createServiceDependency().setService(IStatisticsManager.class)
.setCallbacks("setStatisticsManager", "unsetStatisticsManager").setRequired(false));
- c.add(createContainerServiceDependency(containerName).setService(ISwitchManager.class)
- .setCallbacks("setSwitchManager", "unsetSwitchManager").setRequired(true));
+ c.add(createContainerServiceDependency(containerName).setService(IAffinityManager.class)
+ .setCallbacks("setAffinityManager", "unsetAffinityManager").setRequired(true));
c.add(createContainerServiceDependency(containerName).setService(IReadService.class)
.setCallbacks("setReaderService", "unsetReaderService").setRequired(true));
package org.opendaylight.controller.analytics.internal;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.opendaylight.controller.affinity.AffinityGroup;
+import org.opendaylight.controller.affinity.IAffinityManager;
import org.opendaylight.controller.analytics.IAnalyticsManager;
import org.opendaylight.controller.hosttracker.IfIptoHost;
import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
import org.opendaylight.controller.sal.reader.NodeDescription;
import org.opendaylight.controller.sal.reader.NodeTableStatistics;
+import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
-import org.opendaylight.controller.switchmanager.ISwitchManager;
-import org.opendaylight.controller.switchmanager.SubnetConfig;
public class AnalyticsManager implements IReadServiceListener, IAnalyticsManager {
private static final Logger log = LoggerFactory.getLogger(AnalyticsManager.class);
+ private IAffinityManager affinityManager;
private IStatisticsManager statisticsManager;
- private ISwitchManager switchManager;
private IfIptoHost hostTracker;
private Map<MatchField, Host> destinationHostCache;
log.debug("STOP called!");
}
+ void setAffinityManager(IAffinityManager a) {
+ this.affinityManager = a;
+
+ // TODO: This is just for testing
+ AffinityGroup ag1 = new AffinityGroup("testAG1");
+ ag1.add("10.0.0.1");
+ ag1.add("10.0.0.2");
+ AffinityGroup ag2 = new AffinityGroup("testAG2");
+ ag2.add("10.0.0.3");
+ ag2.add("10.0.0.4");
+ this.affinityManager.addAffinityGroup(ag1);
+ this.affinityManager.addAffinityGroup(ag2);
+ }
+
+ void unsetAffinityManager(IAffinityManager a) {
+ if (this.affinityManager.equals(a)) {
+ this.affinityManager = null;
+ }
+ }
+
void setStatisticsManager(IStatisticsManager s) {
this.statisticsManager = s;
}
}
}
- void setSwitchManager(ISwitchManager s) {
- this.switchManager = s;
-
- // Add a default subnet to allow the hostTracker to populate
- // the host lists.
- SubnetConfig defaultSubnet = new SubnetConfig("default", "10.0.0.254/8", new HashSet<String>());
- this.switchManager.addSubnet(defaultSubnet);
- }
-
- void unsetSwitchManager(ISwitchManager s) {
- if (this.switchManager.equals(s)) {
- this.switchManager = null;
- }
- }
-
/* Returns the destination host associated with this flow, if one
* exists. Returns null otherwise.
*/
return bitRate;
}
+ // TODO: This functionality should be more general, and a part of
+ // the affinity group class.
+ private boolean hostIsInAffinity(Host h, AffinityGroup a) {
+ Set<String> ips = a.getIPs();
+ InetAddress hostAddress = h.getNetworkAddress();
+ for (String ip : ips) {
+ try {
+ InetAddress thisAddress = InetAddress.getByName(ip);
+ if (hostAddress.equals(thisAddress)) {
+ return true;
+ }
+ } catch (UnknownHostException e) {
+ }
+ }
+ return false;
+ }
+
+ public long getByteCountBetweenAffinities(AffinityGroup a1, AffinityGroup a2) {
+ // TODO: Cache for host-to-AG mapping
+ Set<HostNodeConnector> allHosts = this.hostTracker.getAllHosts();
+ long b = 0;
+ for (Host h1 : allHosts) {
+ for (Host h2 : allHosts) {
+ if (hostIsInAffinity(h1, a1) && hostIsInAffinity(h2, a2)) {
+ b += getByteCountBetweenHosts(h1, h2);
+ }
+ }
+ }
+ return b;
+ }
+
@Override
public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
+ // TODO: Start testing
+ /*AffinityGroup ag1 = this.affinityManager.getAffinityGroup("testAG1");
+ AffinityGroup ag2 = this.affinityManager.getAffinityGroup("testAG2");
+ long b = getByteCountBetweenAffinities(ag1, ag2);
+ System.out.println("!!! " + b + " bytes");*/
+ // TODO: End testing
+
Set<HostNodeConnector> allHosts = this.hostTracker.getAllHosts();
for (FlowOnNode f : flowStatsList) {
Host srcHost = getSourceHostFromFlow(f.getFlow(), allHosts);
}
public double getBitRate() {
- System.out.println("!!! byte count: " + this.byteCount);
- System.out.println("!!! duration: " + this.duration);
return (this.byteCount * 8)/(this.duration);
}
}
\ No newline at end of file
# Should see output like: "xxx bytes between 10.0.0.1 and 10.0.0.2",
# where xxx is a positive integer.
+'''
+Class to keep track of host statistics (byte count, bit rate)
+'''
class HostStats:
def __init__(self, src, dst):
def refresh(self):
resp, content = self.http.request("http://localhost:8080/controller/nb/v2/analytics/default/hoststats/" + self.src + "/" + self.dst, "GET")
if (resp.status == 404):
- print "404 Error; exiting"
- sys.exit()
+ return
if (resp.status == 503):
- print "503 Error; exiting"
- sys.exit()
+ return
self.host_stats = json.loads(content)
def get_bytes(self):
try:
bytes = long(self.host_stats["byteCount"])
except Exception as e:
- print "exception: ", e
- bytes = None
+ bytes = 0
return bytes
def get_bit_rate(self):
try:
bitrate = float(self.host_stats["bitRate"])
except Exception as e:
- print "exception: ", e
- bitrate = None
+ bitrate = 0.0
return bitrate
+'''
+Class for controlling subnets. Right now, just adds subnets and
+checks whether they exist, because that's all we need.
+'''
+class SubnetControl:
+
+ def __init__(self):
+ self.http = httplib2.Http(".cache")
+ self.http.add_credentials("admin", "admin")
+
+ # Checks whether subnet exists. Checks against the actual subnet
+ # string (e.g., "10.0.0.255/1"), not the subnet name. Will not
+ # catch things like overlapping subnets.
+ def exists(self, subnet):
+ resp, content = self.http.request("http://localhost:8080/controller/nb/v2/subnet/default/subnet/all", "GET")
+ data = json.loads(content)
+ for key in data:
+ if (data[key]["subnet"] == subnet):
+ return True
+ return False
+
+ # Add a subnet if it doesn't already exist.
+ def add_subnet(self, subnet_name, subnet):
+ if (self.exists(subnet)):
+ print "subnet", subnet, "already exists"
+ return
+ subnet_config = dict(name=subnet_name, subnet=subnet)
+ json_data = json.dumps(subnet_config)
+ resp, content = self.http.request("http://localhost:8080/controller/nb/v2/subnet/default/subnet/" + subnet_name, "POST", json_data, {'Content-Type': 'application/json'})
+ if (resp.status == 201):
+ print "subnet", subnet, "added"
+ else:
+ print "subnet", subnet, "could not be added"
+
+
def main():
+
+ # Default subnet is required for the host tracker to work. Run
+ # this script once *before* you start mininet.
+ subnet_control = SubnetControl()
+ subnet_control.add_subnet("defaultSubnet", "10.0.0.254/8")
+
src = "10.0.0.1"
dst = "10.0.0.2"
+ host_stat = HostStats(src, dst)
+
+ # These counts should be nonzero
+ print("%d bytes between %s and %s" % (host_stat.get_bytes(), src, dst))
+ print("%f mbit/s between %s and %s" % (host_stat.get_bit_rate(), src, dst))
- h = HostStats(src, dst)
- print("%d bytes between %s and %s" % (h.get_bytes(), src, dst))
- print("%f mbit/s between %s and %s" % (h.get_bit_rate(), src, dst))
if __name__ == "__main__":
main()