Merge remote-tracking branch 'upstream/master'
diff --git a/src/emuvim/api/zerorpc/network.py b/src/emuvim/api/zerorpc/network.py
index 37b34f9..d55e775 100755
--- a/src/emuvim/api/zerorpc/network.py
+++ b/src/emuvim/api/zerorpc/network.py
@@ -134,6 +134,16 @@
             logging.exception("RPC error.")
             return ex.message
 
+    # remove the flow metrics measurement
+    def stop_flow(self, vnf_name, vnf_interface, metric, cookie):
+        logging.debug("RPC CALL: stop flow")
+        try:
+            c = self.net.monitor_agent.stop_flow(vnf_name, vnf_interface, metric, cookie)
+            return c
+        except Exception as ex:
+            logging.exception("RPC error.")
+            return ex.message
+
     # do prometheus query
     def prometheus(self, dc_label, vnf_name, vnf_interface, query):
         logging.debug("RPC CALL: query prometheus")
diff --git a/src/emuvim/cli/monitor.py b/src/emuvim/cli/monitor.py
index 123abe5..34853a6 100755
--- a/src/emuvim/cli/monitor.py
+++ b/src/emuvim/cli/monitor.py
@@ -56,6 +56,16 @@
             args.get("cookie"))

         pp.pprint(r)

 

+    def stop_flow(self, args):

+        vnf_name = self._parse_vnf_name(args.get("vnf_name"))

+        vnf_interface = self._parse_vnf_interface(args.get("vnf_name"))

+        r = self.c.stop_flow(

+            vnf_name,

+            vnf_interface,

+            args.get("metric"),

+            args.get("cookie"))

+        pp.pprint(r)

+

     def prometheus(self, args):

         vnf_name = self._parse_vnf_name(args.get("vnf_name"))

         vnf_interface = self._parse_vnf_interface(args.get("vnf_name"))

@@ -82,7 +92,8 @@
 parser = argparse.ArgumentParser(description='son-emu monitor')

 parser.add_argument(

     "command",

-    help="Action to be executed")

+    choices=['setup_metric', 'stop_metric', 'setup_flow', 'stop_flow','prometheus'],

+    help="setup/stop a metric/flow to be monitored or Prometheus query")

 parser.add_argument(

     "--vnf_name", "-vnf", dest="vnf_name",

     help="vnf name:interface to be monitored")

diff --git a/src/emuvim/cli/network.py b/src/emuvim/cli/network.py
index 53007cd..516a752 100755
--- a/src/emuvim/cli/network.py
+++ b/src/emuvim/cli/network.py
@@ -84,7 +84,8 @@
 parser = argparse.ArgumentParser(description='son-emu network')

 parser.add_argument(

     "command",

-    help="Action to be executed: add|remove")

+    choices=['add', 'remove'],

+    help="Action to be executed.")

 parser.add_argument(

     "--datacenter", "-d", dest="datacenter",

     help="Data center to in which the network action should be initiated")

@@ -103,10 +104,10 @@
 parser.add_argument(

     "--bidirectional", "-b", dest="bidirectional",

     action='store_true',

-    help="add/remove the flow entries in 2 directions")

+    help="add/remove the flow entries from src to dst and back")

 parser.add_argument(

     "--cookie", "-c", dest="cookie",

-    help="cookie for this flow")

+    help="cookie for this flow, as easy to use identifier (eg. per tenant/service)")

 

 def main(argv):

     args = vars(parser.parse_args(argv))

diff --git a/src/emuvim/dcemulator/monitoring.py b/src/emuvim/dcemulator/monitoring.py
index 762c947..e663cae 100755
--- a/src/emuvim/dcemulator/monitoring.py
+++ b/src/emuvim/dcemulator/monitoring.py
@@ -139,6 +139,28 @@
             logging.exception("setup_metric error.")

             return ex.message

 

+    def stop_flow(self, vnf_name, vnf_interface=None, metric=None, cookie=0):

+        for flow_dict in self.flow_metrics:

+            if flow_dict['vnf_name'] == vnf_name and flow_dict['vnf_interface'] == vnf_interface \

+                    and flow_dict['metric_key'] == metric and flow_dict['cookie'] == cookie:

+

+                self.monitor_flow_lock.acquire()

+

+                self.flow_metrics.remove(flow_dict)

+

+                for collector in self.registry._collectors:

+                    if (vnf_name, vnf_interface, cookie) in collector._metrics:

+                        #logging.info('2 name:{0} labels:{1} metrics:{2}'.format(collector._name, collector._labelnames,

+                        #                                                        collector._metrics))

+                        collector.remove(vnf_name, vnf_interface, cookie)

+

+                delete_from_gateway(self.pushgateway, job='sonemu-SDNcontroller')

+

+                self.monitor_flow_lock.release()

+

+                logging.info('Stopped monitoring flow {3}: {2} on {0}:{1}'.format(vnf_name, vnf_interface, metric, cookie))

+                return 'Stopped monitoring flow {3}: {2} on {0}:{1}'.format(vnf_name, vnf_interface, metric, cookie)

+

 

     # first set some parameters, before measurement can start

     def setup_metric(self, vnf_name, vnf_interface=None, metric='tx_packets'):

@@ -297,7 +319,7 @@
                 ret = self.net.ryu_REST('stats/flow', dpid=flow_dict['switch_dpid'], data=data)

                 flow_stat_dict = ast.literal_eval(ret)

 

-                logging.info('received flow stat:{0} '.format(flow_stat_dict))

+                #logging.info('received flow stat:{0} '.format(flow_stat_dict))

                 self.set_flow_metric(flow_dict, flow_stat_dict)

 

             self.monitor_flow_lock.release()

diff --git a/src/emuvim/dcemulator/net.py b/src/emuvim/dcemulator/net.py
index 3556535..39c4a96 100755
--- a/src/emuvim/dcemulator/net.py
+++ b/src/emuvim/dcemulator/net.py
@@ -236,15 +236,17 @@
         if cmd == 'add-flow':
             ret = self._chainAddFlow(vnf_src_name, vnf_dst_name, vnf_src_interface, vnf_dst_interface, **kwargs)
             if kwargs.get('bidirectional'):
-                return ret +'\n' + self._chainAddFlow(vnf_dst_name, vnf_src_name, vnf_dst_interface, vnf_src_interface, **kwargs)
+                ret = ret +'\n' + self._chainAddFlow(vnf_dst_name, vnf_src_name, vnf_dst_interface, vnf_src_interface, **kwargs)
 
         elif cmd == 'del-flows':  # TODO: del-flow to be implemented
             ret = self._chainAddFlow(vnf_src_name, vnf_dst_name, vnf_src_interface, vnf_dst_interface, **kwargs)
             if kwargs.get('bidirectional'):
-                return ret + '\n' + self._chainAddFlow(vnf_dst_name, vnf_src_name, vnf_dst_interface, vnf_src_interface, **kwargs)
+                ret = ret + '\n' + self._chainAddFlow(vnf_dst_name, vnf_src_name, vnf_dst_interface, vnf_src_interface, **kwargs)
 
         else:
-            return "Command unknown"
+            ret = "Command unknown"
+
+        return ret
 
 
     def _chainAddFlow(self, vnf_src_name, vnf_dst_name, vnf_src_interface=None, vnf_dst_interface=None, **kwargs):
@@ -404,9 +406,8 @@
         elif cmd == 'del-flows':
             prefix = 'stats/flowentry/delete'
 
-            # if cookie is given, only delete flows by cookie
-            # do not specify other match -> also other cookies can be matched
             if cookie:
+                # TODO: add cookie_mask as argument
                 flow['cookie_mask'] = int('0xffffffffffffffff', 16)  # need full mask to match complete cookie
 
             action = {}
@@ -479,7 +480,6 @@
             self.ryu_process.kill()
 
     def ryu_REST(self, prefix, dpid=None, data=None):
-        if data: logging.info('log POST: {0}'.format(str(data)))
         try:
             if dpid:
                 url = self.ryu_REST_api + '/' + str(prefix) + '/' + str(dpid)
diff --git a/src/emuvim/examples/monitoring_demo_topology.py b/src/emuvim/examples/monitoring_demo_topology.py
index 4dfd5b7..0650be4 100755
--- a/src/emuvim/examples/monitoring_demo_topology.py
+++ b/src/emuvim/examples/monitoring_demo_topology.py
@@ -32,11 +32,16 @@
     net = DCNetwork(monitor=True, enable_learning=False)
 
     """
-    1b. add a monitoring agent to the DCNetwork
+    1b. Add endpoint APIs for the whole DCNetwork,
+        to access and control the networking from outside.
+        e.g., to setup forwarding paths between compute
+        instances aka. VNFs (represented by Docker containers), passing through
+        different switches and datacenters of the emulated topology
     """
     mon_api = ZeroRpcApiEndpointDCNetwork("0.0.0.0", 5151)
     mon_api.connectDCNetwork(net)
     mon_api.start()
+
     """
     2. Add (logical) data centers to the topology
        (each data center is one "bigswitch" in our simplified