From: stevenvanrossem Date: Fri, 27 Jan 2017 22:37:29 +0000 (+0100) Subject: merge with latest upstream status X-Git-Tag: v3.1~45^2~25 X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2Fvim-emu.git;a=commitdiff_plain;h=9cc7360bf2c0dacb869d8ed0674d9d9e269a1082 merge with latest upstream status --- 9cc7360bf2c0dacb869d8ed0674d9d9e269a1082 diff --cc Vagrantfile index b87a9f5,7c9c68f..7c9c68f mode 100755,100644..100755 --- a/Vagrantfile +++ b/Vagrantfile diff --cc ansible/install.yml index fd3aa4b,fd3aa4b..4e4ff01 --- a/ansible/install.yml +++ b/ansible/install.yml @@@ -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 diff --cc misc/sonata-demo-service.son index c4e58e2,c4e58e2..c4e58e2 mode 100644,100644..100755 Binary files differ diff --cc setup.py index 0baad49,0baad49..ce1c47f --- a/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' diff --cc src/emuvim/api/sonata/dummygatekeeper.py index f0a7ccd,4018b69..d5daf42 --- a/src/emuvim/api/sonata/dummygatekeeper.py +++ b/src/emuvim/api/sonata/dummygatekeeper.py @@@ -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"]) diff --cc src/emuvim/dcemulator/net.py index 191d6a8,faf758c..b0838e0 --- a/src/emuvim/dcemulator/net.py +++ b/src/emuvim/dcemulator/net.py @@@ -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" @@@ -586,23 -340,23 +592,24 @@@ # 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)) @@@ -658,9 -397,7 +665,10 @@@ 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 @@@ -683,15 -422,10 +691,16 @@@ 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: @@@ -714,38 -446,24 +723,39 @@@ 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' diff --cc src/emuvim/dcemulator/node.py index 8a7be0a,a0112cf..fd4b8fb --- a/src/emuvim/dcemulator/node.py +++ b/src/emuvim/dcemulator/node.py @@@ -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: