Updated demo scripts: the demo now outputs per-protocol information. 63/3763/1
authorKatrina LaCurts <katrina.lacurts@plexxi.com>
Mon, 16 Dec 2013 20:26:13 +0000 (15:26 -0500)
committerKatrina LaCurts <katrina.lacurts@plexxi.com>
Mon, 16 Dec 2013 20:26:13 +0000 (15:26 -0500)
Small bugfix to L2Agent, since we use that in the demo.

Signed-off-by: Katrina LaCurts <katrina.lacurts@plexxi.com>
l2agent/src/main/java/org/opendaylight/affinity/l2agent/L2Agent.java
scripts/analytics.py
scripts/demo.py
scripts/stats.py

index f25dc71b2aa2bebd6edf89bccaee8d8a2bc5a6fd..c8d1e3aa43dc54926027435bea244bb28bc0d3bd 100644 (file)
@@ -211,7 +211,9 @@ public class L2Agent implements IListenDataPacket, IfL2Agent {
     @Override
     public NodeConnector lookup_output_port(Node node, byte [] dstMAC) {
         long dstMAC_val = BitBufferHelper.toNumber(dstMAC);
-        NodeConnector nc = this.mac_to_ports.get(node).get(dstMAC_val);
+        NodeConnector nc = null;
+        if (this.mac_to_ports.get(node) != null)
+            nc = this.mac_to_ports.get(node).get(dstMAC_val);
         logger.debug("lookup_output_port: Node = {}, dst mac = {}, Nodeconnector = {}", node, dstMAC, nc);
         return nc;
     }
index 3bebdaf01dcff8bba326055980d69169e80e2b72..1c6297c17caaeeb2db6f1f11dfcd932cb614213d 100644 (file)
@@ -13,7 +13,6 @@ import requests
 import sys
 import time
 
-from stats import Stats
 from subnet import SubnetControl
 from affinity_control import AffinityControl
 
@@ -58,82 +57,134 @@ def rest_method(url, rest_type, payload=None):
     elif (rest_type == "PUT"):
         headers = {'content-type': 'application/json'}
         resp = requests.put(url, auth=('admin', 'admin'), data=json.dumps(payload), headers=headers)
+        return resp.status_code
     elif (rest_type == "DELETE"):
         resp = requests.delete(url, auth=('admin', 'admin'))
 
 ### Host Statistics
 
-def stats_hosts(src, dst):
+def stats_hosts(src, dst, do_print=True):
     url = "http://localhost:8080/affinity/nb/v2/analytics/default/hoststats/%s/%s" % (src, dst)
     data = rest_method(url, "GET")
-    print("%s bytes (%s packets) over %s seconds (%s bit/s)" % (data["byteCount"], data["packetCount"], data["duration"], data["bitRate"]))
+    if (do_print):
+        print("%s bytes (%s packets) over %s seconds (%s bit/s)" % (data["byteCount"], data["packetCount"], data["duration"], data["bitRate"]))
+    return data
 
-def stats_hosts_protocol(src, dst, protocol):
+def stats_hosts_protocol(src, dst, protocol, do_print=True):
     url = "http://localhost:8080/affinity/nb/v2/analytics/default/hoststats/%s/%s/%d" % (src, dst, protocol)
     data = rest_method(url, "GET")
-    print("%s bytes (%s packets) over %s seconds (%s bit/s)" % (data["byteCount"], data["packetCount"], data["duration"], data["bitRate"]))
+    if (do_print):
+        print("%s bytes (%s packets) over %s seconds (%s bit/s)" % (data["byteCount"], data["packetCount"], data["duration"], data["bitRate"]))
+    return data
 
-def all_stats_hosts(src, dst):
+def all_stats_hosts(src, dst, do_print=True):
     url = "http://localhost:8080/affinity/nb/v2/analytics/default/hoststats/%s/%s/all" % (src, dst)
-    data = rest_method(url, "GET")["stats"]
-    for entry in data:
-        stat = entry["stat"]
-        print("protocol %s: %s bytes (%s packets) over %s seconds (%s bit/s)" % (entry["protocol"], stat["byteCount"], stat["packetCount"], stat["duration"], stat["bitRate"]))
+    data = rest_method(url, "GET")
+    try:
+        data = convert_all_stats_data(data)
+        if (do_print):
+            for protocol in data:
+                stat = data[protocol]
+                print("protocol %s: %s bytes (%s packets) over %s seconds (%s bit/s)" % (protocol, stat["byteCount"], stat["packetCount"], stat["duration"], stat["bitRate"]))
+    except:
+        data = {}
+    finally:
+        return data
 
 ### Affinity link statistics
 
-def stats_link(al):
+def stats_link(al, do_print=True):
     url = "http://localhost:8080/affinity/nb/v2/analytics/default/affinitylinkstats/%s" % al
     data = rest_method(url, "GET")
-    print("%s bytes (%s packets) over %s seconds (%s bit/s)" % (data["byteCount"], data["packetCount"], data["duration"], data["bitRate"]))
+    if (do_print):
+        print("%s bytes (%s packets) over %s seconds (%s bit/s)" % (data["byteCount"], data["packetCount"], data["duration"], data["bitRate"]))
+    return data
 
-def stats_link_protocol(al, protocol):
+def stats_link_protocol(al, protocol, do_print=True):
     url = "http://localhost:8080/affinity/nb/v2/analytics/default/affinitylinkstats/%s/%s" % (al, protocol)
     data = rest_method(url, "GET")
-    print("%s bytes (%s packets) over %s seconds (%s bit/s)" % (data["byteCount"], data["packetCount"], data["duration"], data["bitRate"]))
+    if (do_print):
+        print("%s bytes (%s packets) over %s seconds (%s bit/s)" % (data["byteCount"], data["packetCount"], data["duration"], data["bitRate"]))
+    return data
 
-def all_stats_link(al):
+def all_stats_link(al, do_print=True):
     url = "http://localhost:8080/affinity/nb/v2/analytics/default/affinitylinkstats/%s/all" % al
-    data = rest_method(url, "GET")['stats']
-    for entry in data:
-        stat = entry["stat"]
-        print("protocol %s: %s bytes (%s packets) over %s seconds (%s bit/s)" % (entry["protocol"], stat["byteCount"], stat["packetCount"], stat["duration"], stat["bitRate"]))
+    data = rest_method(url, "GET")
+    try:
+        data = convert_all_stats_data(data)
+        if (do_print):
+            for protocol in data:
+                stat = data[protocol]
+                print("protocol %d: %s bytes (%s packets) over %s seconds (%s bit/s)" % (data, stat["byteCount"], stat["packetCount"], stat["duration"], stat["bitRate"]))
+    except:
+        data = {}
+    finally:
+        return data
 
 ### Subnet statistics
 
-def stats_subnet(src_sub, dst_sub):
+def stats_subnet(src_sub, dst_sub, do_print=True):
     url = "http://localhost:8080/affinity/nb/v2/analytics/default/subnetstats/%s/%s" % (src_sub, dst_sub)
     data = rest_method(url, "GET")
-    print("%s bytes (%s packets) over %s seconds (%s bit/s)" % (data["byteCount"], data["packetCount"], data["duration"], data["bitRate"]))
+    if (do_print):
+        print("%s bytes (%s packets) over %s seconds (%s bit/s)" % (data["byteCount"], data["packetCount"], data["duration"], data["bitRate"]))
+    return data
 
-def stats_subnet_protocol(src_sub, dst_sub, protocol):
+def stats_subnet_protocol(src_sub, dst_sub, protocol, do_print=True):
     url = "http://localhost:8080/affinity/nb/v2/analytics/default/subnetstats/%s/%s/%s" % (src_sub, dst_sub, protocol)
     data = rest_method(url, "GET")
-    print("%s bytes (%s packets) over %s seconds (%s bit/s)" % (data["byteCount"], data["packetCount"], data["duration"], data["bitRate"]))
+    if (do_print):
+        print("%s bytes (%s packets) over %s seconds (%s bit/s)" % (data["byteCount"], data["packetCount"], data["duration"], data["bitRate"]))
+    return do_print
 
-def all_stats_subnet(src_sub, dst_sub):
+def all_stats_subnet(src_sub, dst_sub, do_print=True):
     url = "http://localhost:8080/affinity/nb/v2/analytics/default/subnetstats/%s/%s/all" % (src_sub, dst_sub)
-    data = rest_method(url, "GET")['stats']
-    for entry in data:
-        stat = entry["stat"]
-        print("protocol %s: %s bytes (%s packets) over %s seconds (%s bit/s)" % (entry["protocol"], stat["byteCount"], stat["packetCount"], stat["duration"], stat["bitRate"]))
-
-def incoming_hosts(subnet):
-    url = "http://localhost:8080/affinity/nb/v2/analytics/default/subnetstats/incoming/%s" % subnet
     data = rest_method(url, "GET")
+    try:
+        data = convert_all_stats_data(data)
+        if (do_print):
+            for protocol in data:
+                stat = data[protocol]
+                print("protocol %d: %s bytes (%s packets) over %s seconds (%s bit/s)" % (protocol, stat["byteCount"], stat["packetCount"], stat["duration"], stat["bitRate"]))
+    except:
+        data = {}
+    finally:
+        return data
+
+def incoming_hosts(subnet, do_print=True):
+    url = "http://localhost:8080/affinity/nb/v2/analytics/default/subnetstats/incoming/%s" % subnet
     data = rest_method(url, "GET")['stats']
     if (type(data) == type({})):
         data = [data]
-    for entry in data:
-        print("%s bytes from host %s" % (entry['byteCount'], entry['hostIP']))
+    if (do_print):
+        for entry in data:
+            print("%s bytes from host %s" % (entry['byteCount'], entry['hostIP']))
+    return data
 
-def incoming_hosts_protocol(subnet, protocol):
+def incoming_hosts_protocol(subnet, protocol, do_print=True):
     url = "http://localhost:8080/affinity/nb/v2/analytics/default/subnetstats/incoming/%s/%s" % (subnet, protocol)
     data = rest_method(url, "GET")['data']['entry']
     if (type(data) == type({})):
         data = [data]
-    for entry in data:
-        print("%s bytes from host %s" % (entry['byteCount'], entry['hostIP']))
+    if (do_print):
+        for entry in data:
+            print("%s bytes from host %s" % (entry['byteCount'], entry['hostIP']))
+    return data
+
+def convert_all_stats_data(data):
+    try:
+        new_data = {}
+        data = data["stats"]
+        if (type(data) == type({})):
+            data = [data]
+        for entry in data:
+            stat = entry["stat"]
+            protocol = int(entry["protocol"])
+            new_data[protocol] = stat
+        return new_data
+    except Exception as e:
+        pass
+    return {}
 
 # This is not part of the analytics NB API, but it is a necessary step
 # if you want to monitor protocols
@@ -141,12 +192,16 @@ def add_protocol_flows():
     protocols = [1, 6, 17] # ICMP, TCP, UDP
     flows = get_flows()
     i = 0
+    success = True
     for flow in flows:
         i += 1
         name = "flow" + str(i)
         flow.set_priority(2)
         flow.set_protocol(1)
-        add_flow(flow, name)
+        flow_success = add_flow(flow, name)
+        if (flow_success != 201):
+            success = False
+    return success
 
 #### Flow control methods
 
@@ -163,7 +218,7 @@ def get_flows():
 
 def add_flow(flow, flow_name):
     url = "http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/%s/staticFlow/%s" % (flow.node_id, flow_name)
-    rest_method(url, "PUT", flow.get_json(flow_name))
+    return rest_method(url, "PUT", flow.get_json(flow_name))
 
 #### End flow control methods
 
index 729229f3f2f578d5d8ea65a48f94bc8d1fc44efd..b9f9b3b9f355ecee089c7d2a2346d25e3a763605 100644 (file)
@@ -19,6 +19,8 @@ from affinity_control import AffinityControl
 from subnet import SubnetControl
 from stats import Stats
 
+import analytics
+
 '''
 The instructions for running this demo are located at:
 https://wiki.opendaylight.org/view/Project_Proposals:Affinity_Metadata_Service#Current_Status
@@ -59,6 +61,7 @@ class WaypointMonitor(Thread):
     def set_large_flow_threshold(self, s):
         self.stat.set_large_flow_threshold(s)
         print "Set threshold for large flows to %d bytes" % s
+        print("-------------------------")
 
     def run(self):
         global sigint
@@ -66,7 +69,12 @@ class WaypointMonitor(Thread):
         while not sigint:
             _, is_big = self.stat.refresh()
             if is_big and not did_waypoint:
-                print "Large flow detected (%d bytes)" % self.stat.get_bytes()
+                print "Large flow detected (%d bytes, %d packets, %3.3f bit/s)" % (self.stat.get_bytes(), self.stat.get_packets(), self.stat.get_bit_rate())
+                print "   ICMP: %d bytes, %d packets" % (self.stat.get_bytes(1), self.stat.get_packets(1))
+                print "   UDP: %d bytes, %d packets" % (self.stat.get_bytes(17), self.stat.get_packets(17))
+                print "   TCP: %d bytes, %d packets" % (self.stat.get_bytes(6), self.stat.get_packets(6))
+                print "   other: %d bytes, %d packets" % (self.stat.get_bytes(-1), self.stat.get_packets(-1))
+                print("-------------------------")
                 ac = AffinityControl()
                 # First AG: Sources sending data into this subnet
                 src_ag_name = "sources"
@@ -98,6 +106,14 @@ def main():
     subnet_control = SubnetControl()
     subnet_control.add_subnet("defaultSubnet", "10.0.0.254/8")
 
+    raw_input("[Press enter when mininet is ready] ")
+    print("-------------------------")
+
+    # Add per-protocol flows so we can monitor stats that way
+    x = analytics.add_protocol_flows()
+    if (not x):
+        print "Unable to add per-protocol flows"
+
     m = WaypointMonitor(Stats.TYPE_SUBNET, subnet="10.0.0.0/31")
     m.set_waypoint("10.0.0.2")
     m.set_large_flow_threshold(2000) # 2000 bytes
index 87a78f125be1d283dc38a59a4d2d0bb1bac2227a..cb1c17dae0e3e0c88d17363932793f8455a65820 100644 (file)
@@ -1,7 +1,6 @@
 #!/usr/bin/python
 
-import httplib2
-import json
+import analytics
 
 '''
 Class for keeping track of host statistics
@@ -17,21 +16,17 @@ class Stats:
         if stat_type == Stats.TYPE_HOST:
             self.src = kwargs['src']
             self.dst = kwargs['dst']
-            self.url_prefix = "http://localhost:8080/affinity/nb/v2/analytics/default/hoststats/" 
         elif stat_type == Stats.TYPE_AL:
             self.al = kwargs['al']
-            self.url_prefix = "http://localhost:8080/affinity/nb/v2/analytics/default/affinitylinkstats/"
         elif stat_type == Stats.TYPE_SUBNET:
             self.subnet = kwargs['subnet']
-            self.url_prefix = "http://localhost:8080/affinity/nb/v2/analytics/default/subnetstats/"
         else:
             print "incorrect stat type", stat_type
 
         self.stats = {}
+        self.protocol_stats = {}
         self.rate_ewma = None
         self.large_flow_threshold = 5 * 10**6 # in bytes
-        self.http = httplib2.Http(".cache")
-        self.http.add_credentials('admin', 'admin')
 
     def __str__(self):
         if (self.stat_type == Stats.TYPE_HOST):
@@ -46,18 +41,19 @@ class Stats:
     # Refresh statistics
     def refresh(self):
         if (self.stat_type == Stats.TYPE_HOST):
-            resp, content = self.http.request(self.url_prefix + self.src + "/" + self.dst, "GET")
+            self.stats = analytics.stats_hosts(self.src, self.dst, False)
+            self.protocol_stats = analytics.all_stats_hosts(self.src, self.dst, False)
         elif (self.stat_type == Stats.TYPE_AL):
-            resp, content = self.http.request(self.url_prefix + self.al, "GET")
+            self.stats = analytics.stats_link(self.al, False)
+            self.protocol_stats = analytics.all_stats_link(self.al, False)
         elif (self.stat_type == Stats.TYPE_SUBNET):
-            resp, content = self.http.request(self.url_prefix + "null/null/" + self.subnet, "GET")
+            self.stats = analytics.stats_subnet("null/null", self.subnet, False)
+            self.protocol_stats = analytics.all_stats_subnet("null/null", self.subnet, False)
         try:
-            self.stats = json.loads(content)
             is_fast = self.handle_rate_ewma()
             is_big = self.check_large_flow()
             return [is_fast, is_big]
-        except Exception as e:
-            print "error: ", e
+        except:
             return [False, False]
 
     def set_large_flow_threshold(self, s):
@@ -66,10 +62,8 @@ class Stats:
     # Return all hosts that transferred a particular percentage of data into this entity.  Right now only supports subnets.
     def get_large_incoming_hosts(self):
         if (self.stat_type == Stats.TYPE_SUBNET):
-            resp, content = self.http.request(self.url_prefix + "incoming/" + self.subnet, "GET")
-            data = json.loads(content)
+            data = analytics.incoming_hosts(self.subnet, False)
             if (data == {}): return []
-            data = data['stats']
             ips = []
             total_bytes_in = self.get_bytes()
             n = len(data)
@@ -79,7 +73,6 @@ class Stats:
                 if (bytes_from_ip >= total_bytes_in / float(n)):
                     ips.append(ip)
             return ips
-
         else:
             print "Stat type not supported for incoming hosts"
         return []
@@ -108,14 +101,27 @@ class Stats:
         return False
 
     # Bytes
-    def get_bytes(self):
+    def get_bytes(self, protocol=None):
         try:
-            bytes = long(self.stats["byteCount"])
+            if (protocol == None):
+                bytes = long(self.stats["byteCount"])
+            else:
+                bytes = long(self.protocol_stats[protocol]["byteCount"])
         except Exception as e:
-            print "exception: ", e
             bytes = 0
         return bytes
 
+    # Packets
+    def get_packets(self, protocol=None):
+        try:
+            if (protocol == None):
+                packets = long(self.stats["packetCount"])
+            else:
+                packets = long(self.protocol_stats[protocol]["byteCount"])
+        except Exception as e:
+            packets = 0
+        return packets
+
     # Bit Rate
     def get_bit_rate(self):
         try: