merge with latest upstream status
authorstevenvanrossem <steven.vanrossem@intec.ugent.be>
Fri, 27 Jan 2017 22:37:29 +0000 (23:37 +0100)
committerstevenvanrossem <steven.vanrossem@intec.ugent.be>
Fri, 27 Jan 2017 22:37:29 +0000 (23:37 +0100)
1  2 
Vagrantfile
ansible/install.yml
misc/sonata-demo-service.son
setup.py
src/emuvim/api/sonata/dummygatekeeper.py
src/emuvim/dcemulator/net.py
src/emuvim/dcemulator/node.py
src/emuvim/test/unittests/test_sonata_dummy_gatekeeper.py

diff --cc Vagrantfile
index b87a9f5,7c9c68f..7c9c68f
mode 100755,100644..100755
@@@ -57,8 -57,8 +57,8 @@@
     - name: install requests
       pip: name=requests state=latest
  
--   - name: install docker-py
--     pip: name=docker-py version=1.7.1
++   - name: install docker
++     pip: name=docker version=2.0.2
  
     - name: install prometheus_client
       pip: name=prometheus_client state=latest
index c4e58e2,c4e58e2..c4e58e2
mode 100644,100644..100755
Binary files differ
diff --cc setup.py
+++ b/setup.py
@@@ -52,7 -52,7 +52,7 @@@ setup(name='emuvim'
            'pytest',
            'Flask',
            'flask_restful',
--          'docker-py==1.7.1',
++          'docker==2.0.2',
            'requests',
            'prometheus_client',
            'urllib3'
@@@ -176,98 -175,83 +176,99 @@@ class Service(object)
                  vnfi = self._start_vnfd(vnfd)
              self.instances[instance_uuid]["vnf_instances"].append(vnfi)
  
-         vlinks = self.nsd["virtual_links"]
-         fwd_links = self.nsd["forwarding_graphs"][0]["constituent_virtual_links"]
-         eline_fwd_links = [l for l in vlinks if (l["id"] in fwd_links) and (l["connectivity_type"] == "E-Line")]
-         elan_fwd_links = [l for l in vlinks if (l["id"] in fwd_links) and (l["connectivity_type"] == "E-LAN")]
-         GK.net.deployed_elines.extend(eline_fwd_links)
-         GK.net.deployed_elans.extend(elan_fwd_links)
-         # 4a. deploy E-Line links
-         # cookie is used as identifier for the flowrules installed by the dummygatekeeper
-         # eg. different services get a unique cookie for their flowrules
-         cookie = 1
-         for link in eline_fwd_links:
-             src_id, src_if_name = link["connection_points_reference"][0].split(":")
-             dst_id, dst_if_name = link["connection_points_reference"][1].split(":")
-             # check if there is a SAP in the link
-             if src_id in self.sap_identifiers:
-                 src_docker_name = "{0}_{1}".format(src_id, src_if_name)
-                 src_id = src_docker_name
-             else:
-                 src_docker_name = src_id
-             if dst_id in self.sap_identifiers:
-                 dst_docker_name = "{0}_{1}".format(dst_id, dst_if_name)
-                 dst_id = dst_docker_name
-             else:
-                 dst_docker_name = dst_id
-             src_name = vnf_id2vnf_name[src_id]
-             dst_name = vnf_id2vnf_name[dst_id]
-             LOG.debug(
-                 "Setting up E-Line link. %s(%s:%s) -> %s(%s:%s)" % (
-                     src_name, src_id, src_if_name, dst_name, dst_id, dst_if_name))
-             if (src_name in self.vnfds) and (dst_name in self.vnfds):
-                 network = self.vnfds[src_name].get("dc").net  # there should be a cleaner way to find the DCNetwork
-                 LOG.debug(src_docker_name)
-                 ret = network.setChain(
-                     src_docker_name, dst_docker_name,
-                     vnf_src_interface=src_if_name, vnf_dst_interface=dst_if_name,
-                     bidirectional=BIDIRECTIONAL_CHAIN, cmd="add-flow", cookie=cookie, priority=10)
-                 # re-configure the VNFs IP assignment and ensure that a new subnet is used for each E-Link
-                 src_vnfi = self._get_vnf_instance(instance_uuid, src_name)
-                 if src_vnfi is not None:
-                     self._vnf_reconfigure_network(src_vnfi, src_if_name, self.eline_subnets_src.pop(0))
-                 dst_vnfi = self._get_vnf_instance(instance_uuid, dst_name)
-                 if dst_vnfi is not None:
-                     self._vnf_reconfigure_network(dst_vnfi, dst_if_name, self.eline_subnets_dst.pop(0))
-         # 4b. deploy E-LAN links
-         base = 10
-         for link in elan_fwd_links:
-             elan_vnf_list=[]
-             # generate lan ip address
-             ip = 1
-             for intf in link["connection_points_reference"]:
-                 ip_address = generate_lan_string("10.0", base, subnet_size=24, ip=ip)
-                 vnf_id, intf_name = intf.split(":")
-                 if vnf_id in self.sap_identifiers:
-                     src_docker_name = "{0}_{1}".format(vnf_id, intf_name)
-                     vnf_id = src_docker_name
+         if "virtual_links" in self.nsd:
+             vlinks = self.nsd["virtual_links"]
+             fwd_links = self.nsd["forwarding_graphs"][0]["constituent_virtual_links"]
+             eline_fwd_links = [l for l in vlinks if (l["id"] in fwd_links) and (l["connectivity_type"] == "E-Line")]
+             elan_fwd_links = [l for l in vlinks if (l["id"] in fwd_links) and (l["connectivity_type"] == "E-LAN")]
++            GK.net.deployed_elines.extend(eline_fwd_links)
++            GK.net.deployed_elans.extend(elan_fwd_links)
++
+             # 4a. deploy E-Line links
+             # cookie is used as identifier for the flowrules installed by the dummygatekeeper
+             # eg. different services get a unique cookie for their flowrules
+             cookie = 1
+             for link in eline_fwd_links:
+                 src_id, src_if_name = link["connection_points_reference"][0].split(":")
+                 dst_id, dst_if_name = link["connection_points_reference"][1].split(":")
+                 # check if there is a SAP in the link
+                 if src_id in self.sap_identifiers:
+                     src_docker_name = "{0}_{1}".format(src_id, src_if_name)
+                     src_id = src_docker_name
                  else:
-                     src_docker_name = vnf_id
-                 vnf_name = vnf_id2vnf_name[vnf_id]
-                 LOG.debug(
-                     "Setting up E-LAN link. %s(%s:%s) -> %s" % (
-                         vnf_name, vnf_id, intf_name, ip_address))
-                 if vnf_name in self.vnfds:
-                     # re-configure the VNFs IP assignment and ensure that a new subnet is used for each E-LAN
-                     # E-LAN relies on the learning switch capability of Ryu which has to be turned on in the topology
-                     # (DCNetwork(controller=RemoteController, enable_learning=True)), so no explicit chaining is necessary.
-                     vnfi = self._get_vnf_instance(instance_uuid, vnf_name)
-                     if vnfi is not None:
-                         self._vnf_reconfigure_network(vnfi, intf_name, ip_address)
-                         # increase for the next ip address on this E-LAN
-                         ip += 1
+                     src_docker_name = src_id
  
-                         # add this vnf and interface to the E-LAN for tagging
-                         network = self.vnfds[vnf_name].get("dc").net  # there should be a cleaner way to find the DCNetwork
-                         elan_vnf_list.append({'name':src_docker_name,'interface':intf_name})
+                 if dst_id in self.sap_identifiers:
+                     dst_docker_name = "{0}_{1}".format(dst_id, dst_if_name)
+                     dst_id = dst_docker_name
+                 else:
+                     dst_docker_name = dst_id
  
+                 src_name = vnf_id2vnf_name[src_id]
+                 dst_name = vnf_id2vnf_name[dst_id]
  
-             # install the VLAN tags for this E-LAN
-             network.setLAN(elan_vnf_list)
-             # increase the base ip address for the next E-LAN
-             base += 1
+                 LOG.debug(
+                     "Setting up E-Line link. %s(%s:%s) -> %s(%s:%s)" % (
+                         src_name, src_id, src_if_name, dst_name, dst_id, dst_if_name))
+                 if (src_name in self.vnfds) and (dst_name in self.vnfds):
+                     network = self.vnfds[src_name].get("dc").net  # there should be a cleaner way to find the DCNetwork
+                     LOG.debug(src_docker_name)
+                     ret = network.setChain(
+                         src_docker_name, dst_docker_name,
+                         vnf_src_interface=src_if_name, vnf_dst_interface=dst_if_name,
+                         bidirectional=BIDIRECTIONAL_CHAIN, cmd="add-flow", cookie=cookie, priority=10)
+                     # re-configure the VNFs IP assignment and ensure that a new subnet is used for each E-Link
+                     src_vnfi = self._get_vnf_instance(instance_uuid, src_name)
+                     if src_vnfi is not None:
+                         self._vnf_reconfigure_network(src_vnfi, src_if_name, self.eline_subnets_src.pop(0))
+                     dst_vnfi = self._get_vnf_instance(instance_uuid, dst_name)
+                     if dst_vnfi is not None:
+                         self._vnf_reconfigure_network(dst_vnfi, dst_if_name, self.eline_subnets_dst.pop(0))
+             # 4b. deploy E-LAN links
+             base = 10
+             for link in elan_fwd_links:
++
++                elan_vnf_list=[]
++
+                 # generate lan ip address
+                 ip = 1
+                 for intf in link["connection_points_reference"]:
+                     ip_address = generate_lan_string("10.0", base, subnet_size=24, ip=ip)
+                     vnf_id, intf_name = intf.split(":")
+                     if vnf_id in self.sap_identifiers:
+                         src_docker_name = "{0}_{1}".format(vnf_id, intf_name)
+                         vnf_id = src_docker_name
++                    else:
++                        src_docker_name = vnf_id
+                     vnf_name = vnf_id2vnf_name[vnf_id]
+                     LOG.debug(
+                         "Setting up E-LAN link. %s(%s:%s) -> %s" % (
+                             vnf_name, vnf_id, intf_name, ip_address))
+                     if vnf_name in self.vnfds:
+                         # re-configure the VNFs IP assignment and ensure that a new subnet is used for each E-LAN
+                         # E-LAN relies on the learning switch capability of Ryu which has to be turned on in the topology
+                         # (DCNetwork(controller=RemoteController, enable_learning=True)), so no explicit chaining is necessary.
+                         vnfi = self._get_vnf_instance(instance_uuid, vnf_name)
+                         if vnfi is not None:
+                             self._vnf_reconfigure_network(vnfi, intf_name, ip_address)
+                             # increase for the next ip address on this E-LAN
+                             ip += 1
++
++                            # add this vnf and interface to the E-LAN for tagging
++                            network = self.vnfds[vnf_name].get("dc").net  # there should be a cleaner way to find the DCNetwork
++                            elan_vnf_list.append({'name':src_docker_name,'interface':intf_name})
++
++
++                # install the VLAN tags for this E-LAN
++                network.setLAN(elan_vnf_list)
+                 # increase the base ip address for the next E-LAN
+                 base += 1
  
          # 5. run the emulator specific entrypoint scripts in the VNFIs of this service instance
          self._trigger_emulator_start_scripts_in_vnfis(self.instances[instance_uuid]["vnf_instances"])
@@@ -500,41 -274,24 +500,47 @@@ class DCNetwork(Containernet)
          :param cookie: cookie for the installed flowrules (can be used later as identifier for a set of installed chains)
          :param match: custom match entry to be added to the flowrules (default: only in_port and vlan tag)
          :param priority: custom flowrule priority
++<<<<<<< HEAD
 +        :param monitor: boolean to indicate whether this chain is a monitoring chain
 +        :param tag: vlan tag to be used for this chain (pre-defined or new one if none is specified)
++=======
+         :param path: custom path between the two VNFs (list of switches)
++>>>>>>> upstream/master
          :return: output log string
          """
 +
 +        # special procedure for monitoring flows
 +        if kwargs.get('monitor'):
 +
 +            # check if chain already exists
 +            found_chains = [chain_dict for chain_dict in self.installed_chains if
 +             (chain_dict['vnf_src_name'] == vnf_src_name and chain_dict['vnf_src_interface'] == vnf_src_interface
 +             and chain_dict['vnf_dst_name'] == vnf_dst_name and chain_dict['vnf_dst_interface'] == vnf_dst_interface)]
 +
 +            if len(found_chains) > 0:
 +                # this chain exists, so need an extra monitoring flow
 +                # assume only 1 chain per vnf/interface pair
 +                LOG.debug('*** installing monitoring chain on top of pre-defined chain from {0}:{1} -> {2}:{3}'.
 +                            format(vnf_src_name, vnf_src_interface, vnf_dst_name, vnf_dst_interface))
 +                tag = found_chains[0]['tag']
 +                ret = self._addMonitorFlow(vnf_src_name, vnf_dst_name, vnf_src_interface, vnf_dst_interface,
 +                                     tag=tag, table_id=0, **kwargs)
 +                return ret
 +            else:
 +                # no chain existing (or E-LAN) -> install normal chain
 +                LOG.warning('*** installing monitoring chain without pre-defined NSD chain from {0}:{1} -> {2}:{3}'.
 +                            format(vnf_src_name, vnf_src_interface, vnf_dst_name, vnf_dst_interface))
 +                pass
 +
 +
          cmd = kwargs.get('cmd')
 -        if cmd == 'add-flow':
 +        if cmd == 'add-flow' or cmd == 'del-flows':
              ret = self._chainAddFlow(vnf_src_name, vnf_dst_name, vnf_src_interface, vnf_dst_interface, **kwargs)
              if kwargs.get('bidirectional'):
+                 if kwargs.get('path') is not None:
+                     kwargs['path'] = list(reversed(kwargs.get('path')))
                  ret = ret +'\n' + self._chainAddFlow(vnf_dst_name, vnf_src_name, vnf_dst_interface, vnf_src_interface, **kwargs)
  
 -        elif cmd == 'del-flows':
 -            ret = self._chainAddFlow(vnf_src_name, vnf_dst_name, vnf_src_interface, vnf_dst_interface, **kwargs)
 -            if kwargs.get('bidirectional'):
 -                if kwargs.get('path') is not None:
 -                    kwargs['path'] = list(reversed(kwargs.get('path')))
 -                ret = ret + '\n' + self._chainAddFlow(vnf_dst_name, vnf_src_name, vnf_dst_interface, vnf_src_interface, **kwargs)
 -
          else:
              ret = "Command unknown"
  
                      # found the right link and connected switch
                      dst_sw = connected_sw
                      dst_sw_outport_nr = link_dict[link]['src_port_nr']
 +                    dst_sw_outport_name = link_dict[link]['src_port_name']
                      break
  
-         # get shortest path
-         try:
-             # returns the first found shortest path
-             # if all shortest paths are wanted, use: all_shortest_paths
-             path = nx.shortest_path(self.DCNetwork_graph, src_sw, dst_sw, weight=kwargs.get('weight'))
-         except:
-             LOG.exception("No path could be found between {0} and {1} using src_sw={2} and dst_sw={3}".format(
-                 vnf_src_name, vnf_dst_name, src_sw, dst_sw))
-             LOG.debug("Graph nodes: %r" % self.DCNetwork_graph.nodes())
-             LOG.debug("Graph edges: %r" % self.DCNetwork_graph.edges())
-             for e, v in self.DCNetwork_graph.edges():
-                 LOG.debug("%r" % self.DCNetwork_graph[e][v])
-             return "No path could be found between {0} and {1}".format(vnf_src_name, vnf_dst_name)
+         path = kwargs.get('path')
+         if path is None:
+             # get shortest path
+             try:
+                 # returns the first found shortest path
+                 # if all shortest paths are wanted, use: all_shortest_paths
+                 path = nx.shortest_path(self.DCNetwork_graph, src_sw, dst_sw, weight=kwargs.get('weight'))
+             except:
+                 LOG.exception("No path could be found between {0} and {1} using src_sw={2} and dst_sw={3}".format(
+                     vnf_src_name, vnf_dst_name, src_sw, dst_sw))
+                 LOG.debug("Graph nodes: %r" % self.DCNetwork_graph.nodes())
+                 LOG.debug("Graph edges: %r" % self.DCNetwork_graph.edges())
+                 for e, v in self.DCNetwork_graph.edges():
+                     LOG.debug("%r" % self.DCNetwork_graph[e][v])
+                 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(vnf_src_name, vnf_dst_name, path))
  
              if isinstance( current_node, OVSSwitch ):
                  kwargs['vlan'] = vlan
                  kwargs['path'] = path
 +                kwargs['current_hop'] = current_hop
 +                kwargs['switch_inport_name'] = src_sw_inport_name
 +                kwargs['switch_outport_name'] = dst_sw_outport_name
+                 kwargs['pathindex'] = i
  
                  if self.controller == RemoteController:
                      ## set flow entry via ryu rest api
          match_input = kwargs.get('match')
          cmd = kwargs.get('cmd')
          path = kwargs.get('path')
-         current_hop = kwargs.get('current_hop')
+         index = kwargs.get('pathindex')
          vlan = kwargs.get('vlan')
          priority = kwargs.get('priority')
 +        # flag to not set the ovs port vlan tag
 +        skip_vlan_tag = kwargs.get('skip_vlan_tag')
 +        # table id to put this flowentry
 +        table_id = kwargs.get('table_id')
 +        if not table_id:
 +            table_id = 0
  
          s = ','
          if match_input:
          if cmd == 'add-flow':
              prefix = 'stats/flowentry/add'
              if vlan != None:
-                 if path.index(current_hop) == 0:  # first node
+                 if index == 0:  # first node
 -                    action = {}
 -                    action['type'] = 'PUSH_VLAN'  # Push a new VLAN tag if a input frame is non-VLAN-tagged
 -                    action['ethertype'] = 33024   # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
 -                    flow['actions'].append(action)
 -                    action = {}
 -                    action['type'] = 'SET_FIELD'
 -                    action['field'] = 'vlan_vid'
 -                    # ryu expects the field to be masked
 -                    action['value'] = vlan | 0x1000
 -                    flow['actions'].append(action)
 -                elif index == len(path) -1:  # last node
 -                    match += ',dl_vlan=%s' % vlan
 -                    action = {}
 -                    action['type'] = 'POP_VLAN'
 -                    flow['actions'].append(action)
 +                    # set vlan tag in ovs instance (to isolate E-LANs)
 +                    if not skip_vlan_tag:
 +                        in_port_name = kwargs.get('switch_inport_name')
 +                        self._set_vlan_tag(node, in_port_name, vlan)
 +                    # set vlan push action if more than 1 switch in the path
 +                    if len(path) > 1:
 +                        action = {}
 +                        action['type'] = 'PUSH_VLAN'  # Push a new VLAN tag if a input frame is non-VLAN-tagged
 +                        action['ethertype'] = 33024   # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
 +                        flow['actions'].append(action)
 +                        action = {}
 +                        action['type'] = 'SET_FIELD'
 +                        action['field'] = 'vlan_vid'
-                         action['value'] = vlan
++                        # ryu expects the field to be masked
++                        action['value'] = vlan | 0x1000
 +                        flow['actions'].append(action)
 +
-                 if path.index(current_hop) == len(path) - 1:  # last node
++                elif index == len(path) - 1:  # last node
 +                    # set vlan tag in ovs instance (to isolate E-LANs)
 +                    if not skip_vlan_tag:
 +                        out_port_name = kwargs.get('switch_outport_name')
 +                        self._set_vlan_tag(node, out_port_name, vlan)
 +                    # set vlan pop action if more than 1 switch in the path
 +                    if len(path) > 1:
 +                        match += ',dl_vlan=%s' % vlan
 +                        action = {}
 +                        action['type'] = 'POP_VLAN'
 +                        flow['actions'].append(action)
 +
-                 if 0 < path.index(current_hop) < (len(path) - 1):  # middle nodes
+                 else:  # middle nodes
                      match += ',dl_vlan=%s' % vlan
 +
              # output action must come last
              action = {}
              action['type'] = 'OUTPUT'
@@@ -190,13 -173,9 +190,14 @@@ class Datacenter(object)
              dcmd=command,
              datacenter=self,
              flavor_name=flavor_name,
 +            cpu_period = cpu_period,
 +            cpu_quota = cpu_quota,
 +            environment = {'VNF_NAME':name}
+             **params
          )
  
 +
 +
          # apply resource limits to container if a resource model is defined
          if self._resource_model is not None:
              try: