+ self.vnfds[vnfd.get("name")] = vnfd
+ LOG.debug("Loaded VNFD: %r" % vnfd.get("name"))
+
+ def _load_saps(self):
+ # create list of all SAPs
+ SAPs = [p for p in self.nsd["connection_points"]]
+
+ for sap in SAPs:
+ # endpoint needed in this service
+ sap_id, sap_interface, sap_docker_name = parse_interface(sap['id'])
+ # make sure SAP has type set (default internal)
+ sap["type"] = sap.get("type", 'internal')
+
+ # Each Service Access Point (connection_point) in the nsd is an IP address on the host
+ if sap.get["type"] == "external":
+ # add to vnfds to calculate placement later on
+ sap_net = SAP_SUBNETS.pop(0)
+ self.saps[sap_docker_name] = {"name": sap_docker_name , "type": "external", "net": sap_net}
+ # add SAP vnf to list in the NSD so it is deployed later on
+ # each SAP get a unique VNFD and vnf_id in the NSD and custom type (only defined in the dummygatekeeper)
+ self.nsd["network_functions"].append(
+ {"vnf_id": sap_docker_name, "vnf_name": sap_docker_name, "vnf_type": "sap_ext"})
+
+ # Each Service Access Point (connection_point) in the nsd is getting its own container (default)
+ elif sap["type"] == "internal":
+ # add SAP to self.vnfds
+ sapfile = pkg_resources.resource_filename(__name__, "sap_vnfd.yml")
+ sap_vnfd = load_yaml(sapfile)
+ sap_vnfd["connection_points"][0]["id"] = sap_interface
+ sap_vnfd["name"] = sap_docker_name
+ sap_vnfd["type"] = "internal"
+ # add to vnfds to calculate placement later on and deploy
+ self.saps[sap_docker_name] = sap_vnfd
+ # add SAP vnf to list in the NSD so it is deployed later on
+ # each SAP get a unique VNFD and vnf_id in the NSD
+ self.nsd["network_functions"].append(
+ {"vnf_id": sap_docker_name, "vnf_name": sap_docker_name, "vnf_type": "sap_int"})
+
+ LOG.debug("Loaded SAP: name: {0}, type: {1}".format(sap_docker_name, sap['type']))
+
+ # create sap lists
+ self.saps_ext = [self.saps[sap]['name'] for sap in self.saps if self.saps[sap]["type"] == "external"]
+ self.saps_int = [self.saps[sap]['name'] for sap in self.saps if self.saps[sap]["type"] == "internal"]
+
+ def _start_sap(self, sap, instance_uuid):
+ LOG.info('start SAP: {0} ,type: {1}'.format(sap['name'],sap['type']))
+ if sap["type"] == "internal":
+ vnfi = None
+ if not GK_STANDALONE_MODE:
+ vnfi = self._start_vnfd(sap)
+ self.instances[instance_uuid]["vnf_instances"].append(vnfi)
+
+ elif sap["type"] == "external":
+ target_dc = sap.get("dc")
+ # add interface to dc switch
+ target_dc.attachExternalSAP(sap['name'], str(sap['net']))
+
+ def _connect_elines(self, eline_fwd_links, instance_uuid):
+ """
+ Connect all E-LINE links in the NSD
+ :param eline_fwd_links: list of E-LINE links in the NSD
+ :param: instance_uuid of the service
+ :return:
+ """
+ # 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, src_sap_id = parse_interface(link["connection_points_reference"][0])
+ dst_id, dst_if_name, dst_sap_id = parse_interface(link["connection_points_reference"][1])
+
+ setChaining = False
+
+ # check if there is a SAP in the link and chain everything together
+ if src_sap_id in self.saps and dst_sap_id in self.saps:
+ LOG.info('2 SAPs cannot be chained together : {0} - {1}'.format(src_sap_id, dst_sap_id))
+ continue
+
+ elif src_sap_id in self.saps_ext:
+ src_id = src_sap_id
+ src_if_name = src_sap_id
+ src_name = self.vnf_id2vnf_name[src_id]
+ dst_name = self.vnf_id2vnf_name[dst_id]
+ dst_vnfi = self._get_vnf_instance(instance_uuid, dst_name)
+ if dst_vnfi is not None:
+ # choose first ip address in sap subnet
+ sap_net = self.saps[src_sap_id]['net']
+ sap_ip = "{0}/{1}".format(str(sap_net[1]), sap_net.prefixlen)
+ self._vnf_reconfigure_network(dst_vnfi, dst_if_name, sap_ip)
+ setChaining = True
+
+ elif dst_sap_id in self.saps_ext:
+ dst_id = dst_sap_id
+ dst_if_name = dst_sap_id
+ src_name = self.vnf_id2vnf_name[src_id]
+ dst_name = self.vnf_id2vnf_name[dst_id]
+ src_vnfi = self._get_vnf_instance(instance_uuid, src_name)
+ if src_vnfi is not None:
+ sap_net = self.saps[dst_sap_id]['net']
+ sap_ip = "{0}/{1}".format(str(sap_net[1]), sap_net.prefixlen)
+ self._vnf_reconfigure_network(src_vnfi, src_if_name, sap_ip)
+ setChaining = True
+
+ # Link between 2 VNFs
+ else:
+ # make sure we use the correct sap vnf name
+ if src_sap_id in self.saps_int:
+ src_id = src_sap_id
+ if dst_sap_id in self.saps_int:
+ dst_id = dst_sap_id
+ src_name = self.vnf_id2vnf_name[src_id]
+ dst_name = self.vnf_id2vnf_name[dst_id]
+ # 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)
+ dst_vnfi = self._get_vnf_instance(instance_uuid, dst_name)
+ if src_vnfi is not None and dst_vnfi is not None:
+ eline_net = ELINE_SUBNETS.pop(0)
+ ip1 = "{0}/{1}".format(str(eline_net[1]), eline_net.prefixlen)
+ ip2 = "{0}/{1}".format(str(eline_net[2]), eline_net.prefixlen)
+ self._vnf_reconfigure_network(src_vnfi, src_if_name, ip1)
+ self._vnf_reconfigure_network(dst_vnfi, dst_if_name, ip2)
+ setChaining = True
+
+ # Set the chaining
+ if setChaining:
+ ret = GK.net.setChain(
+ src_id, dst_id,
+ vnf_src_interface=src_if_name, vnf_dst_interface=dst_if_name,
+ bidirectional=BIDIRECTIONAL_CHAIN, cmd="add-flow", cookie=cookie, priority=10)
+ 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))
+
+
+ def _connect_elans(self, elan_fwd_links, instance_uuid):
+ """
+ Connect all E-LAN links in the NSD
+ :param elan_fwd_links: list of E-LAN links in the NSD
+ :param: instance_uuid of the service
+ :return:
+ """
+ for link in elan_fwd_links:
+
+ elan_vnf_list = []
+
+ # check if an external SAP is in the E-LAN (then a subnet is already defined)
+ intfs_elan = [intf for intf in link["connection_points_reference"]]
+ lan_sap = self.check_ext_saps(intfs_elan)
+ if lan_sap:
+ lan_net = self.saps[lan_sap]['net']
+ lan_hosts = list(lan_net.hosts())
+ sap_ip = str(lan_hosts.pop(0))
+ else:
+ lan_net = ELAN_SUBNETS.pop(0)
+ lan_hosts = list(lan_net.hosts())
+
+ # generate lan ip address for all interfaces except external SAPs
+ for intf in link["connection_points_reference"]:
+
+ # skip external SAPs, they already have an ip
+ vnf_id, vnf_interface, vnf_sap_docker_name = parse_interface(intf)
+ if vnf_sap_docker_name in self.saps_ext:
+ elan_vnf_list.append({'name': vnf_sap_docker_name, 'interface': vnf_interface})
+ continue
+
+ ip_address = "{0}/{1}".format(str(lan_hosts.pop(0)), lan_net.prefixlen)
+ vnf_id, intf_name, vnf_sap_id = parse_interface(intf)
+
+ # make sure we use the correct sap vnf name
+ src_docker_name = vnf_id
+ if vnf_sap_id in self.saps_int:
+ src_docker_name = vnf_sap_id
+ vnf_id = vnf_sap_id
+
+ vnf_name = self.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)
+ # add this vnf and interface to the E-LAN for tagging
+ elan_vnf_list.append({'name': src_docker_name, 'interface': intf_name})
+
+ # install the VLAN tags for this E-LAN
+ GK.net.setLAN(elan_vnf_list)
+