Fix: Added gevent monkey patch to fix issue that blocks
[osm/vim-emu.git] / src / emuvim / dcemulator / net.py
index 005e272..58c2bff 100755 (executable)
 # acknowledge the contributions of their colleagues of the SONATA
 # partner consortium (www.sonata-nfv.eu).
 import logging
 # acknowledge the contributions of their colleagues of the SONATA
 # partner consortium (www.sonata-nfv.eu).
 import logging
-
-import site
 import time
 import time
-from subprocess import Popen
 import re
 import requests
 import os
 import json
 import re
 import requests
 import os
 import json
-
+import networkx as nx
+from subprocess import Popen
+from gevent import monkey
 from mininet.net import Containernet
 from mininet.node import OVSSwitch, OVSKernelSwitch, Docker, RemoteController
 from mininet.cli import CLI
 from mininet.link import TCLink
 from mininet.clean import cleanup
 from mininet.net import Containernet
 from mininet.node import OVSSwitch, OVSKernelSwitch, Docker, RemoteController
 from mininet.cli import CLI
 from mininet.link import TCLink
 from mininet.clean import cleanup
-import networkx as nx
 from emuvim.dcemulator.monitoring import DCNetworkMonitor
 from emuvim.dcemulator.node import Datacenter, EmulatorCompute
 from emuvim.dcemulator.resourcemodel import ResourceModelRegistrar
 
 from emuvim.dcemulator.monitoring import DCNetworkMonitor
 from emuvim.dcemulator.node import Datacenter, EmulatorCompute
 from emuvim.dcemulator.resourcemodel import ResourceModelRegistrar
 
+# ensure correct functionality of all gevent based REST servers
+monkey.patch_all(sys=True)
+
+# setup logging
 LOG = logging.getLogger("dcemulator.net")
 LOG.setLevel(logging.DEBUG)
 
 LOG = logging.getLogger("dcemulator.net")
 LOG.setLevel(logging.DEBUG)
 
@@ -462,7 +464,7 @@ class DCNetwork(Containernet):
             return "No path could be found between {0} and {1}".format(
                 vnf_src_name, vnf_dst_name)
 
             return "No path could be found between {0} and {1}".format(
                 vnf_src_name, vnf_dst_name)
 
-        LOG.info("Path between {0} and {1}: {2}".format(
+        LOG.debug("Creating path between {0} and {1}: {2}".format(
             vnf_src_name, vnf_dst_name, path))
 
         current_hop = src_sw
             vnf_src_name, vnf_dst_name, path))
 
         current_hop = src_sw
@@ -484,7 +486,7 @@ class DCNetwork(Containernet):
 
             if next_hop == vnf_dst_name:
                 switch_outport_nr = dst_sw_outport_nr
 
             if next_hop == vnf_dst_name:
                 switch_outport_nr = dst_sw_outport_nr
-                LOG.info("end node reached: {0}".format(vnf_dst_name))
+                LOG.debug("end node reached: {0}".format(vnf_dst_name))
             elif not isinstance(next_node, OVSSwitch):
                 LOG.info("Next node: {0} is not a switch".format(next_hop))
                 return "Next node: {0} is not a switch".format(next_hop)
             elif not isinstance(next_node, OVSSwitch):
                 LOG.info("Next node: {0} is not a switch".format(next_hop))
                 return "Next node: {0} is not a switch".format(next_hop)
@@ -666,7 +668,7 @@ class DCNetwork(Containernet):
                 return "No path could be found between {0} and {1}".format(
                     vnf_src_name, vnf_dst_name)
 
                 return "No path could be found between {0} and {1}".format(
                     vnf_src_name, vnf_dst_name)
 
-        LOG.info("Path between {0} and {1}: {2}".format(
+        LOG.debug("Creating path between {0} and {1}: {2}".format(
             vnf_src_name, vnf_dst_name, path))
 
         current_hop = src_sw
             vnf_src_name, vnf_dst_name, path))
 
         current_hop = src_sw
@@ -706,7 +708,7 @@ class DCNetwork(Containernet):
 
             if next_hop == vnf_dst_name:
                 switch_outport_nr = dst_sw_outport_nr
 
             if next_hop == vnf_dst_name:
                 switch_outport_nr = dst_sw_outport_nr
-                LOG.info("end node reached: {0}".format(vnf_dst_name))
+                LOG.debug("end node reached: {0}".format(vnf_dst_name))
             elif not isinstance(next_node, OVSSwitch):
                 LOG.info("Next node: {0} is not a switch".format(next_hop))
                 return "Next node: {0} is not a switch".format(next_hop)
             elif not isinstance(next_node, OVSSwitch):
                 LOG.info("Next node: {0} is not a switch".format(next_hop))
                 return "Next node: {0} is not a switch".format(next_hop)
@@ -746,6 +748,8 @@ class DCNetwork(Containernet):
             'match_input': kwargs.get('match')
         }
         flow_options_str = json.dumps(flow_options, indent=1)
             'match_input': kwargs.get('match')
         }
         flow_options_str = json.dumps(flow_options, indent=1)
+        LOG.info("Installed flow rule: ({}:{}) -> ({}:{}) with options: {}"
+                 .format(vnf_src_name, vnf_src_interface, vnf_dst_name, vnf_dst_interface, flow_options))
         return "success: {2} between {0} and {1} with options: {3}".format(
             vnf_src_name, vnf_dst_name, cmd, flow_options_str)
 
         return "success: {2} between {0} and {1} with options: {3}".format(
             vnf_src_name, vnf_dst_name, cmd, flow_options_str)
 
@@ -758,6 +762,7 @@ class DCNetwork(Containernet):
         cmd = kwargs.get('cmd')
         path = kwargs.get('path')
         index = kwargs.get('pathindex')
         cmd = kwargs.get('cmd')
         path = kwargs.get('path')
         index = kwargs.get('pathindex')
+        mod_dl_dst = kwargs.get('mod_dl_dst')
 
         vlan = kwargs.get('vlan')
         priority = kwargs.get('priority', DEFAULT_PRIORITY)
 
         vlan = kwargs.get('vlan')
         priority = kwargs.get('priority', DEFAULT_PRIORITY)
@@ -825,6 +830,12 @@ class DCNetwork(Containernet):
 
                 else:  # middle nodes
                     match += ',dl_vlan=%s' % vlan
 
                 else:  # middle nodes
                     match += ',dl_vlan=%s' % vlan
+            if mod_dl_dst:
+                action = {}
+                action['type'] = 'SET_FIELD'
+                action['field'] = 'eth_dst'
+                action['value'] = mod_dl_dst
+                flow['actions'].append(action)
 
             # output action must come last
             action = {}
 
             # output action must come last
             action = {}
@@ -896,14 +907,14 @@ class DCNetwork(Containernet):
     # start Ryu Openflow controller as Remote Controller for the DCNetwork
     def startRyu(self, learning_switch=True):
         # start Ryu controller with rest-API
     # start Ryu Openflow controller as Remote Controller for the DCNetwork
     def startRyu(self, learning_switch=True):
         # start Ryu controller with rest-API
-        python_install_path = site.getsitepackages()[0]
+
         # ryu default learning switch
         # ryu default learning switch
-        # ryu_path = python_install_path + '/ryu/app/simple_switch_13.py'
+        # ryu_learning_app = python_install_path + '/ryu/app/simple_switch_13.py'
         # custom learning switch that installs a default NORMAL action in the
         # ovs switches
         dir_path = os.path.dirname(os.path.realpath(__file__))
         # custom learning switch that installs a default NORMAL action in the
         # ovs switches
         dir_path = os.path.dirname(os.path.realpath(__file__))
-        ryu_path = dir_path + '/son_emu_simple_switch_13.py'
-        ryu_path2 = python_install_path + '/ryu/app/ofctl_rest.py'
+        ryu_learning_app = dir_path + '/son_emu_simple_switch_13.py'
+        ryu_rest_app = 'ryu.app.ofctl_rest'
         # change the default Openflow controller port to 6653 (official IANA-assigned port number), as used by Mininet
         # Ryu still uses 6633 as default
         ryu_option = '--ofp-tcp-listen-port'
         # change the default Openflow controller port to 6653 (official IANA-assigned port number), as used by Mininet
         # Ryu still uses 6633 as default
         ryu_option = '--ofp-tcp-listen-port'
@@ -911,15 +922,13 @@ class DCNetwork(Containernet):
         ryu_cmd = 'ryu-manager'
         FNULL = open("/tmp/ryu.log", 'w')
         if learning_switch:
         ryu_cmd = 'ryu-manager'
         FNULL = open("/tmp/ryu.log", 'w')
         if learning_switch:
-            self.ryu_process = Popen(
-                [ryu_cmd, ryu_path, ryu_path2, ryu_option, ryu_of_port], stdout=FNULL, stderr=FNULL)
-            LOG.debug('starting ryu-controller with {0}'.format(ryu_path))
-            LOG.debug('starting ryu-controller with {0}'.format(ryu_path2))
+            # learning and rest api
+            args = [ryu_cmd, ryu_learning_app, ryu_rest_app, ryu_option, ryu_of_port]
         else:
             # no learning switch, but with rest api
         else:
             # no learning switch, but with rest api
-            self.ryu_process = Popen(
-                [ryu_cmd, ryu_path2, ryu_option, ryu_of_port], stdout=FNULL, stderr=FNULL)
-            LOG.debug('starting ryu-controller with {0}'.format(ryu_path2))
+            args = [ryu_cmd, ryu_rest_app, ryu_option, ryu_of_port]
+        self.ryu_process = Popen(args, stdout=FNULL, stderr=FNULL)
+        LOG.debug('starting ryu-controller with %s' % args)
         time.sleep(1)
 
     def killRyu(self):
         time.sleep(1)
 
     def killRyu(self):
@@ -940,6 +949,8 @@ class DCNetwork(Containernet):
             url = self.ryu_REST_api + '/' + str(prefix) + '/' + str(dpid)
         else:
             url = self.ryu_REST_api + '/' + str(prefix)
             url = self.ryu_REST_api + '/' + str(prefix) + '/' + str(dpid)
         else:
             url = self.ryu_REST_api + '/' + str(prefix)
+
+        LOG.debug('sending RYU command: %s, payload: %s', url, data)
         if data:
             req = self.RyuSession.post(url, json=data)
         else:
         if data:
             req = self.RyuSession.post(url, json=data)
         else:
@@ -947,7 +958,7 @@ class DCNetwork(Containernet):
 
         # do extra logging if status code is not 200 (OK)
         if req.status_code is not requests.codes.ok:
 
         # do extra logging if status code is not 200 (OK)
         if req.status_code is not requests.codes.ok:
-            logging.info(
+            LOG.info(
                 'type {0}  encoding: {1} text: {2} headers: {3} history: {4}'.format(req.headers['content-type'],
                                                                                      req.encoding, req.text,
                                                                                      req.headers, req.history))
                 'type {0}  encoding: {1} text: {2} headers: {3} history: {4}'.format(req.headers['content-type'],
                                                                                      req.encoding, req.text,
                                                                                      req.headers, req.history))