def get_ports(self, o): i = 0 ports = [] if (o.slice.network in ["host", "bridged"]): pass # no ports in host or bridged mode else: for port in o.ports.all(): if (not port.ip): # 'unmanaged' ports may have an ip, but no mac # XXX: are there any ports that have a mac but no ip? raise DeferredException( "Port on network %s is not yet ready" % port.network.name) pd = {} pd["mac"] = port.mac or "" pd["ip"] = port.ip or "" pd["xos_network_id"] = port.network.id if port.network.name == "wan_network": if port.ip: (a, b, c, d) = port.ip.split('.') pd["mac"] = "02:42:%02x:%02x:%02x:%02x" % ( int(a), int(b), int(c), int(d)) if o.isolation == "container": # container on bare metal instance_port = self.get_instance_port(port) if not instance_port: raise DeferredException( "No instance on slice for port on network %s" % port.network.name) pd["snoop_instance_mac"] = instance_port.mac pd["snoop_instance_id"] = instance_port.instance.instance_id pd["src_device"] = "" pd["bridge"] = "br-int" else: # container in VM pd["snoop_instance_mac"] = "" pd["snoop_instance_id"] = "" pd["parent_mac"] = self.get_parent_port_mac(o, port) pd["bridge"] = "" for (k, v) in port.get_parameters().items(): pd[k] = v ports.append(pd) # for any ports that don't have a device, assign one used_ports = [x["device"] for x in ports if ("device" in x)] avail_ports = [ "eth%d" % i for i in range(0, 64) if ("eth%d" % i not in used_ports) ] for port in ports: if not port.get("device", None): port["device"] = avail_ports.pop(0) return ports
def map_tenant_to_route(self, address_si): instance = None # Address setup is kind of hacky right now, we'll # need to revisit. The idea is: # * Look up the instance corresponding to the address # * Look up the node running the instance # * Get the "dataPlaneIp" tag, push to the fabric sub = self.get_subscriber(address_si) if sub: instance = sub.instance else: instance_id = address_si.get_attribute("tenant_for_instance_id") instance = Instance.objects.filter(id=instance_id)[0] node = instance.node dataPlaneIp = node.dataPlaneIp if not dataPlaneIp: raise DeferredException( "No IP found for node %s tenant %s -- skipping" % (str(node), str(address_si))) data = { PREFIX: "%s/32" % address_si.public_ip, NEXT_HOP: dataPlaneIp.split('/')[0] } return data
def sync_record(self, o): self.log.info("Sync'ing Fabric Crossconnect Service Instance", service_instance=o) if (o.policed is None) or (o.policed < o.updated): raise DeferredException( "Waiting for model_policy to run on fcsi %s" % o.id) onos = self.get_fabric_onos_info(o) si = ServiceInstance.objects.get(id=o.id) if (o.s_tag is None): raise Exception( "Cannot sync FabricCrossconnectServiceInstance if s_tag is None on fcsi %s" % o.id) if (o.source_port is None): raise Exception( "Cannot sync FabricCrossconnectServiceInstance if source_port is None on fcsi %s" % o.id) if (not o.switch_datapath_id): raise Exception( "Cannot sync FabricCrossconnectServiceInstance if switch_datapath_id is unset on fcsi %s" % o.id) bng_mapping = self.find_bng(s_tag=o.s_tag) if not bng_mapping: raise Exception("Unable to determine BNG port for s_tag %s" % o.s_tag) east_port = bng_mapping.switch_port data = { "deviceId": o.switch_datapath_id, "vlanId": o.s_tag, "ports": [int(o.source_port), int(east_port)] } url = onos['url'] + '/onos/segmentrouting/xconnect' self.log.info("Sending request to ONOS", url=url, body=data) r = requests.post(url, json=data, auth=HTTPBasicAuth(onos['user'], onos['pass'])) if r.status_code != 200: raise Exception( "Failed to create fabric crossconnect in ONOS: %s" % r.text) # TODO(smbaker): If the o.backend_handle changed, then someone must have changed the # FabricCrossconnectServiceInstance. If so, then we potentially need to clean up the old # entry in ONOS. Furthermore, we might want to also save the two port numbers that we used, # to detect someone changing those. o.backend_handle = self.make_handle(o.s_tag, o.switch_datapath_id) o.save(update_fields=["backend_handle"]) self.log.info("ONOS response", res=r.text)
def defer_sync(self, o, reason): # zdw, 2017-02-18 - is raising the exception here necessary? - seems like # it's just logging the same thing twice self.log.info("defer object", object=str(o), reason=reason, **o.tologdict()) raise DeferredException("defer object %s due to %s" % (str(o), reason))
def get_parent_port_mac(self, instance, port): if not instance.parent: raise Exception("instance has no parent") for parent_port in instance.parent.ports.all(): if parent_port.network == port.network: if not parent_port.mac: raise DeferredException( "parent port on network %s does not have mac yet" % parent_port.network.name) return parent_port.mac raise Exception( "failed to find corresponding parent port for network %s" % port.network.name)
def get_onos_netcfg(self, vtn): privateGatewayMac = vtn.privateGatewayMac localManagementIp = vtn.localManagementIp ovsdbPort = vtn.ovsdbPort sshPort = vtn.sshPort sshUser = vtn.sshUser sshKeyFile = vtn.sshKeyFile mgmtSubnetBits = vtn.mgmtSubnetBits xosEndpoint = vtn.xosEndpoint xosUser = vtn.xosUser xosPassword = vtn.xosPassword controllerPort = vtn.controllerPort if ":" in controllerPort: (c_hostname, c_port) = controllerPort.split(":",1) controllerPort = socket.gethostbyname(c_hostname) + ":" + c_port else: controllerPort = ":" + controllerPort data = { "apps" : { "org.opencord.vtn" : { "cordvtn" : { "privateGatewayMac" : privateGatewayMac, "localManagementIp": localManagementIp, "ovsdbPort": ovsdbPort, "ssh": { "sshPort": sshPort, "sshUser": sshUser, "sshKeyFile": sshKeyFile }, "xos": { "endpoint": xosEndpoint, "user": xosUser, "password": xosPassword }, "publicGateways": [], "nodes" : [], "controllers": [controllerPort] } } } } # Generate apps->org.opencord.vtn->cordvtn->openstack controllers = Controller.objects.all() if controllers: controller = controllers[0] keystone_server = controller.auth_url user_name = controller.admin_user tenant_name = controller.admin_tenant password = controller.admin_password openstack = { "endpoint": keystone_server, "tenant": tenant_name, "user": user_name, "password": password } data["apps"]["org.opencord.vtn"]["cordvtn"]["openstack"] = openstack # Generate apps->org.opencord.vtn->cordvtn->nodes nodes = Node.objects.all() for node in nodes: try: nodeip = socket.gethostbyname(node.name) except socket.gaierror: log.warn("unable to resolve hostname %s: node will not be added to config" % node.name) continue try: bridgeId = node.bridgeId dataPlaneIntf = node.dataPlaneIntf dataPlaneIp = node.dataPlaneIp except: log.error("not adding node %s to the VTN configuration" % node.name) continue node_dict = { "hostname": node.name, "hostManagementIp": "%s/%s" % (nodeip, mgmtSubnetBits), "bridgeId": bridgeId, "dataPlaneIntf": dataPlaneIntf, "dataPlaneIp": dataPlaneIp } # this one is optional try: node_dict["hostManagementIface"] = node.hostManagementIface except AttributeError: pass data["apps"]["org.opencord.vtn"]["cordvtn"]["nodes"].append(node_dict) if not (data["apps"]["org.opencord.vtn"]["cordvtn"]["nodes"]): raise DeferredException("Waiting for there to be valid nodes") # Generate apps->org.onosproject.cordvtn->cordvtn->publicGateways # Pull the gateway information from Address Pool objects for ap in AddressPool.objects.all(): if (not ap.gateway_ip) or (not ap.gateway_mac): log.info("Gateway_ip or gateway_mac is blank for addresspool %s. Skipping." % ap) continue gateway_dict = { "gatewayIp": ap.gateway_ip, "gatewayMac": ap.gateway_mac } data["apps"]["org.opencord.vtn"]["cordvtn"]["publicGateways"].append(gateway_dict) if not AddressPool.objects.all().exists(): log.info("No Address Pools present, not adding publicGateways to config") return json.dumps(data, indent=4, sort_keys=True)
def defer_sync(self, o, reason): log.info("defer object", object=str(o), reason=reason, **o.tologdict()) raise DeferredException("defer object %s due to %s" % (str(o), reason))