def set_object_position(self, obj, element): """ Set the x,y,x position of obj from the point associated with the given element. """ point = self.find_point(element) if not point: return False point_type = point.getAttribute('type') if not point_type: msg = 'no type attribute found for point: \'%s\'' % \ point.toxml('utf-8') logger.warn(msg) assert False # XXX for testing elif point_type == 'pixel': self.set_object_position_pixel(obj, point) elif point_type == 'gps': self.set_object_position_gps(obj, point) elif point_type == 'cart': self.set_object_position_cartesian(obj, point) else: logger.warn("skipping unknown point type: '%s'" % point_type) assert False # XXX for testing logger.info('set position of %s from point element: \'%s\'', obj.name, point.toxml('utf-8')) return True
def redircmd(self, infd, outfd, errfd, args, wait=True): """ Execute a command on a node with standard input, output, and error redirected according to the given file descriptors. :param infd: stdin file descriptor :param outfd: stdout file descriptor :param errfd: stderr file descriptor :param list[str]|str args: command arguments :param bool wait: wait flag :return: command status :rtype: int """ self._verify_connection() # run command, return process when not waiting args = utils.split_args(args) p = self.cmdchnl.redircmd(infd, outfd, errfd, args) if not wait: return p # wait for and return exit status status = p.wait() if status: logger.warn("cmd exited with status %s: %s", status, args) return status
def configure_values(self, config_data): """ Receive configuration message for setting the reference point and scale. :param core.conf.ConfigData config_data: configuration data for carrying out a configuration :return: nothing """ values = config_data.data_values if values is None: logger.warn("location data missing") return None values = values.split('|') # Cartesian coordinate reference point refx, refy = map(lambda x: float(x), values[0:2]) refz = 0.0 self.refxyz = (refx, refy, refz) # Geographic reference point lat, lon, alt = map(lambda x: float(x), values[2:5]) self.setrefgeo(lat, lon, alt) self.refscale = float(values[5]) logger.info( "location configured: (%.2f,%.2f,%.2f) = (%.5f,%.5f,%.5f) scale=%.2f" % (self.refxyz[0], self.refxyz[1], self.refxyz[2], self.refgeo[0], self.refgeo[1], self.refgeo[2], self.refscale)) logger.info("location configured: UTM(%.5f,%.5f,%.5f)" % (self.refutm[1], self.refutm[2], self.refutm[3]))
def parse_default_services(self): # defaults from the CORE GUI self.default_services = { 'router': ['zebra', 'OSPFv2', 'OSPFv3', 'IPForward'], 'host': ['DefaultRoute', 'SSH'], 'PC': ['DefaultRoute', ], 'mdr': ['zebra', 'OSPFv3MDR', 'IPForward'], } default_services = xmlutils.get_first_child_by_tag_name(self.scenario, 'CORE:defaultservices') if not default_services: return for device in xmlutils.iter_children_with_name(default_services, 'device'): device_type = device.getAttribute('type') if not device_type: logger.warn('parse_default_services: no type attribute found for device') continue services = [] for service in xmlutils.iter_children_with_name(device, 'service'): name = service.getAttribute('name') if name: services.append(str(name)) self.default_services[device_type] = services # store default services for the session for t, s in self.default_services.iteritems(): self.session.services.default_services[t] = s logger.info('default services for node type \'%s\' set to: %s' % (t, s))
def addNetworks(self): """ Add networks in the session to the scenPlan. """ for net in self.coreSession.objects.itervalues(): if not isinstance(net, coreobj.PyCoreNet): continue if nodeutils.is_node(net, NodeTypes.CONTROL_NET): continue # Do not add switches and hubs that belong to another network if nodeutils.is_node(net, (NodeTypes.SWITCH, NodeTypes.HUB)): if in_other_network(net): continue try: NetworkElement(self, self, net) except: logger.exception("error adding node") if hasattr(net, "name") and net.name: logger.warn('Unsupported net name: %s, class: %s, type: %s', net.name, net.__class__.__name__, net.type) else: logger.warn('Unsupported net class: %s', net.__class__.__name__)
def addNetworks(self): """ Add networks in the session to the scenPlan. """ for net in self.coreSession.objects.itervalues(): if not isinstance(net, coreobj.PyCoreNet): continue if nodeutils.is_node(net, NodeTypes.CONTROL_NET): continue # Do not add switches and hubs that belong to another network if nodeutils.is_node(net, (NodeTypes.SWITCH, NodeTypes.HUB)): if in_other_network(net): continue try: NetworkElement(self, self, net) except: logger.exception("error adding node") if hasattr(net, "name") and net.name: logger.warn( 'Unsupported net name: %s, class: %s, type: %s', net.name, net.__class__.__name__, net.type) else: logger.warn('Unsupported net class: %s', net.__class__.__name__)
def addservicestonode(self, node, nodetype, services_str): """ Populate the node.service list using (1) the list of services requested from the services TLV, (2) using any custom service configuration, or (3) using the default services for this node type. :param core.coreobj.PyCoreNode node: node to add services to :param str nodetype: node type to add services to :param str services_str: string formatted service list :return: nothing """ if services_str is not None: logger.info("setting custom services for node(%s)", node.name) services = services_str.split("|") for name in services: s = ServiceManager.get(name) if s is None: logger.warn("configured service %s for node %s is unknown", name, node.name) continue logger.info("adding service to node(%s): %s", node.name, s._name) s = self.getcustomservice(node.objid, s) node.addservice(s) else: logger.info("setting default services for node(%s) type (%s)", node.name, nodetype) services = self.getdefaultservices(nodetype) for s in services: logger.info("adding service to node(%s): %s", node.name, s._name) s = self.getcustomservice(node.objid, s) node.addservice(s)
def set_object_position_cartesian(self, obj, point): # TODO: review this xm = float(point.getAttribute('x')) ym = float(point.getAttribute('y')) zm = point.getAttribute('z') if zm: zm = float(zm) else: zm = 0.0 # TODO: zMode is unused # z_mode = point.getAttribute('zMode')) if not self.location_refxyz_set: self.session.location.refxyz = xm, ym, zm self.location_refxyz_set = True # need to convert meters to pixels x = self.session.location.m2px(xm) + self.session.location.refxyz[0] y = self.session.location.m2px(ym) + self.session.location.refxyz[1] z = self.session.location.m2px(zm) + self.session.location.refxyz[2] if x < 0.0: logger.warn('limiting negative x position of \'%s\' to zero: %s' % (obj.name, x)) x = 0.0 if y < 0.0: logger.warn('limiting negative y position of \'%s\' to zero: %s' % (obj.name, y)) y = 0.0 obj.setposition(x, y, z)
def getservicefile(self, services, node, filename): """ Send a File Message when the GUI has requested a service file. The file data is either auto-generated or comes from an existing config. :param list services: service list :param core.netns.vnode.LxcNode node: node to get service file from :param str filename: file name to retrieve :return: file message for node """ svc = services[0] # get the filename and determine the config file index if svc._custom: cfgfiles = svc._configs else: cfgfiles = svc.getconfigfilenames(node.objid, services) if filename not in cfgfiles: logger.warn("Request for unknown file '%s' for service '%s'" % (filename, services[0])) return None # get the file data data = self.getservicefiledata(svc, filename) if data is None: data = "%s" % svc.generateconfig(node, filename, services) else: data = "%s" % data filetypestr = "service:%s" % svc._name return FileData(message_type=MessageFlags.ADD.value, node=node.objid, name=filename, type=filetypestr, data=data)
def parse_interface(self, node, device_id, interface): """ Each interface can have multiple 'address' elements. """ if_name = interface.getAttribute('name') network = self.find_interface_network_object(interface) if not network: msg = 'skipping node \'%s\' interface \'%s\': ' \ 'unknown network' % (node.name, if_name) logger.warn(msg) assert False # XXX for testing mac, ipv4, ipv6, hostname = self.parse_addresses(interface) if mac: hwaddr = MacAddress.from_string(mac[0]) else: hwaddr = None ifindex = node.newnetif(network, addrlist=ipv4 + ipv6, hwaddr=hwaddr, ifindex=None, ifname=if_name) # TODO: 'hostname' addresses are unused msg = 'node \'%s\' interface \'%s\' connected ' \ 'to network \'%s\'' % (node.name, if_name, network.name) logger.info(msg) # set link parameters for wired links if nodeutils.is_node(network, (NodeTypes.HUB, NodeTypes.PEER_TO_PEER, NodeTypes.SWITCH)): netif = node.netif(ifindex) self.set_wired_link_parameters(network, netif, device_id)
def startup(self, node_ids=None): """ Session is transitioning from instantiation to runtime state. Instantiate any mobility models that have been configured for a WLAN. :param list node_ids: node ids to startup :return: nothing """ if node_ids is None: node_ids = self.nodes() for node_id in node_ids: logger.info("checking mobility startup for node: %s", node_id) logger.info("node mobility configurations: %s", self.get_all_configs(node_id)) try: node = self.session.get_object(node_id) except KeyError: logger.warn("skipping mobility configuration for unknown node: %s", node_id) continue for model_name in self.models.iterkeys(): config = self.get_configs(node_id, model_name) if not config: continue model_class = self.models[model_name] self.set_model(node, model_class, config) if self.session.master: self.installphysnodes(node) if node.mobility: self.session.event_loop.add_event(0.0, node.mobility.startup)
def set_wireless_link_parameters(self, channel, link_params, mobility_model_name, mobility_params): network = self.find_channel_network(channel) network_id = network.getAttribute('id') if network_id in self.objidmap: nodenum = self.objidmap[network_id] else: logger.warn('unknown network: %s', network.toxml('utf-8')) assert False # XXX for testing model_name = xmlutils.get_first_child_text_trim_with_attribute(channel, 'type', 'domain', 'CORE') if not model_name: model_name = 'basic_range' if model_name == 'basic_range': mgr = self.session.mobility elif model_name.startswith('emane'): mgr = self.session.emane else: # TODO: any other config managers? raise NotImplementedError logger.info("setting wireless link params: node(%s) model(%s) mobility_model(%s)", nodenum, model_name, mobility_model_name) mgr.set_model_config(node_id=nodenum, model_name=model_name, config=link_params) if mobility_model_name and mobility_params: self.session.mobility.set_model_config(node_id=nodenum, model_name=mobility_model_name, config=mobility_params)
def add_event(self, event_time, node=None, name=None, data=None): """ Add an event to the event queue, with a start time relative to the start of the runtime state. :param event_time: event time :param core.netns.nodes.CoreNode node: node to add event for :param str name: name of event :param data: data for event :return: nothing """ event_time = float(event_time) current_time = self.runtime() if current_time > 0.0: if time <= current_time: logger.warn("could not schedule past event for time %s (run time is now %s)", time, current_time) return event_time = event_time - current_time self.event_loop.add_event(event_time, self.run_event, node=node, name=name, data=data) if not name: name = "" logger.info("scheduled event %s at time %s data=%s", name, event_time + current_time, data)
def process_cur_term_csv(self, row): # Term Sheet: Demand Column demand = 3 # Default try: for ir in self.df_ct_courses.itertuples(): if ir[1] == row['Course Code'] and not pd.isna(ir[6]): print(ir[1], ir[6]) demand = ir[6] break except: logger.warn(f'Empty Archive Course CSV') ranking = demand + (row['# Students'] / 100) # Term Sheet: Professor Row Reference # row_references = [] if isinstance(row['Professor'], str): prof_names_in = row['Professor'].split(', ') for ir in self.df_ct_prof.itertuples(): [ row_references.append(ir[0]) for name in prof_names_in if ir[1] == name ] assert len(prof_names_in) == len(row_references), \ f'ERROR: prof names {prof_names_in} != {row_references} row references' if row_references == []: row_references = None row['Demand'], row['Ranking'], row[ 'Professor Row #'] = demand, ranking, row_references return row
def boot(self): logger.warn("XEN PVM boot() called") self.lock.acquire() if not self.up: raise Exception("Can't boot VM without initialized disk") if self.booted: self.lock.release() return self.session.services.bootnodeservices(self) tarname = self.getconfigitem("persist_tar") if tarname: self.untarpersistent(tarname=tarname, iso=False) try: subprocess.check_call([constants.UMOUNT_BIN, self.mountdir]) self.unmount_all(self.mountdir) subprocess.check_call([UDEVADM_PATH, "settle"]) subprocess.check_call([KPARTX_PATH, "-d", self.lvpath]) # time.sleep(5) # time.sleep(1) # unpause VM logger.warn("XEN PVM boot() unpause domU %s", self.vmname) utils.mutecheck_call([XM_PATH, "unpause", self.vmname]) self.booted = True finally: self.lock.release()
def set_service_file(self, node_id, service_name, file_name, data): """ Receive a File Message from the GUI and store the customized file in the service config. The filename must match one from the list of config files in the service. :param int node_id: node id to set service file :param str service_name: service name to set file for :param str file_name: file name to set :param data: data for file to set :return: nothing """ # attempt to set custom service, if needed self.set_service(node_id, service_name) # retrieve custom service service = self.get_service(node_id, service_name) if service is None: logger.warn("received file name for unknown service: %s", service_name) return # validate file being set is valid config_files = service.configs if file_name not in config_files: logger.warn("received unknown file(%s) for service(%s)", file_name, service_name) return # set custom service file data service.config_data[file_name] = data
def process_search(self, search_name): # Try From CU Dir email = self.locate(type='xpath', locator="//ul[@class='cu-directory-results']/li" "/div[@class='people-meta']" "/div[@class='people-data']" "/a[@class='email-long']", iText=True, report=False) if not email: results = self.locate( type='xpath', locator="//div[@class='gsc-results gsc-webResult']/div", multiple=True) # Workaround for spelling suggestion first_info = self.locate(driver=results[0], type='xpath', locator=".//div/div[@class='gs-title']/a") if not first_info and len(results) > 1: first_info = self.locate( driver=results[1], type='xpath', locator=".//div/div[@class='gs-title']/a") if first_info: self.driver.get(first_info.get_attribute('href')) email = self.locate( type='xpath', locator= "//div[@class='person-email person-contact-info-item']", text=True) if not email: email = None logger.warn(f'Error in {search_name}') return email
def main(): """ Main routine when running from command-line. """ usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage=usagestr) parser.set_defaults(numnodes=10, duration=600, verbose=False) parser.add_option("-d", "--duration", dest="duration", type=int, help="number of seconds to run the simulation") parser.add_option("-n", "--numnodes", dest="numnodes", type=int, help="number of nodes") parser.add_option("-v", "--verbose", dest="verbose", action="store_true", help="be more verbose") def usage(msg=None, err=0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) opt, args = parser.parse_args() if opt.numnodes < 2: usage("invalid numnodes: %s" % opt.numnodes) for a in args: logger.warn("ignoring command line argument: '%s'", a) return wifisession(opt)
def newveth(self, ifindex=None, ifname=None, net=None, hwaddr=None): logger.warn("XEN PVM newveth(ifindex=%s, ifname=%s) called", ifindex, ifname) self.lock.acquire() try: if ifindex is None: ifindex = self.newifindex() if ifname is None: ifname = "eth%d" % ifindex sessionid = self.session.short_session_id() name = "n%s.%s.%s" % (self.objid, ifindex, sessionid) localname = "n%s.%s.%s" % (self.objid, ifname, sessionid) ifclass = XenVEth veth = ifclass(node=self, name=name, localname=localname, mtu=1500, net=net, hwaddr=hwaddr) veth.name = ifname try: self.addnetif(veth, ifindex) except: veth.shutdown() del veth raise return ifindex finally: self.lock.release()
def add_services(self, node, node_type, services=None): """ Add services to a node. :param core.coreobj.PyCoreNode node: node to add services to :param str node_type: node type to add services to :param list[str] services: names of services to add to node :return: nothing """ if not services: logger.info("using default services for node(%s) type(%s)", node.name, node_type) services = self.default_services.get(node_type, []) logger.info("setting services for node(%s): %s", node.name, services) for service_name in services: service = self.get_service(node.objid, service_name, default_service=True) if not service: logger.warn("unknown service(%s) for node(%s)", service_name, node.name) continue logger.info("adding service to node(%s): %s", node.name, service_name) node.addservice(service)
def handle_distributed_control_net(self, message, values, index): """ Modify Config Message if multiple control network prefixes are defined. Map server names to prefixes and repack the message before it is forwarded to slave servers. :param message: message to handle :param list values: values to handle :param int index: index ti get key value from :return: nothing """ key_value = values[index] key, value = key_value.split("=", 1) control_nets = value.split() if len(control_nets) < 2: logger.warn("multiple controlnet prefixes do not exist") return servers = self.session.broker.getservernames() if len(servers) < 2: logger.warn("not distributed") return servers.remove("localhost") # master always gets first prefix servers.insert(0, "localhost") # create list of "server1:ctrlnet1 server2:ctrlnet2 ..." control_nets = map(lambda x: "%s:%s" % (x[0], x[1]), zip(servers, control_nets)) values[index] = "controlnet=%s" % (" ".join(control_nets)) values_str = "|".join(values) message.tlv_data[ConfigTlvs.VALUES.value] = values_str message.repack()
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None, jitter=None, netif2=None): """ Generate CommEffect events when a Link Message is received having link parameters. """ service = self.session.emane.service if service is None: logger.warn("%s: EMANE event service unavailable", self.name) return if netif is None or netif2 is None: logger.warn("%s: missing NEM information", self.name) return # TODO: batch these into multiple events per transmission # TODO: may want to split out seconds portion of delay and jitter event = CommEffectEvent() emane_node = self.session.get_object(self.object_id) nemid = emane_node.getnemid(netif) nemid2 = emane_node.getnemid(netif2) mbw = bw logger.info("sending comm effect event") event.append( nemid, latency=convert_none(delay), jitter=convert_none(jitter), loss=convert_none(loss), duplicate=convert_none(duplicate), unicast=long(convert_none(bw)), broadcast=long(convert_none(mbw)) ) service.publish(nemid2, event)
def set_object_position_gps(self, obj, point): lat = float(point.getAttribute('lat')) lon = float(point.getAttribute('lon')) zalt = point.getAttribute('z') if zalt: zalt = float(zalt) else: zalt = 0.0 # TODO: zMode is unused # z_mode = point.getAttribute('zMode')) if not self.location_refgeo_set: # for x,y,z conversion, we need a reasonable refpt; this # picks the first coordinates as the origin self.session.location.setrefgeo(lat, lon, zalt) self.location_refgeo_set = True x, y, z = self.session.location.getxyz(lat, lon, zalt) if x < 0.0: logger.warn('limiting negative x position of \'%s\' to zero: %s' % (obj.name, x)) x = 0.0 if y < 0.0: logger.warn('limiting negative y position of \'%s\' to zero: %s' % (obj.name, y)) y = 0.0 obj.setposition(x, y, z)
def add_event(self, event_time, node=None, name=None, data=None): """ Add an event to the event queue, with a start time relative to the start of the runtime state. :param event_time: event time :param core.netns.nodes.CoreNode node: node to add event for :param str name: name of event :param data: data for event :return: nothing """ event_time = float(event_time) current_time = self.runtime() if current_time > 0.0: if time <= current_time: logger.warn( "could not schedule past event for time %s (run time is now %s)", time, current_time) return event_time = event_time - current_time self.event_loop.add_event(event_time, self.run_event, node=node, name=name, data=data) if not name: name = "" logger.info("scheduled event %s at time %s data=%s", name, event_time + current_time, data)
def set_wireless_link_parameters(self, channel, link_params, mobility_model_name, mobility_params): network = self.find_channel_network(channel) network_id = network.getAttribute('id') if network_id in self.objidmap: nodenum = self.objidmap[network_id] else: logger.warn('unknown network: %s', network.toxml('utf-8')) assert False # XXX for testing model_name = xmlutils.get_first_child_text_trim_with_attribute( channel, 'type', 'domain', 'CORE') if not model_name: model_name = 'basic_range' if model_name == 'basic_range': mgr = self.session.mobility elif model_name.startswith('emane'): mgr = self.session.emane elif model_name.startswith('xen'): mgr = self.session.xen else: # TODO: any other config managers? raise NotImplementedError logger.info( "setting wireless link params: node(%s) model(%s) mobility_model(%s)", nodenum, model_name, mobility_model_name) mgr.setconfig_keyvalues(nodenum, model_name, link_params.items()) if mobility_model_name and mobility_params: mgr.setconfig_keyvalues(nodenum, mobility_model_name, mobility_params.items())
def parse_interface(self, node, device_id, interface): """ Each interface can have multiple 'address' elements. """ if_name = interface.getAttribute('name') network = self.find_interface_network_object(interface) if not network: msg = 'skipping node \'%s\' interface \'%s\': ' \ 'unknown network' % (node.name, if_name) logger.warn(msg) assert False # XXX for testing mac, ipv4, ipv6, hostname = self.parse_addresses(interface) if mac: hwaddr = MacAddress.from_string(mac[0]) else: hwaddr = None ifindex = node.newnetif(network, addrlist=ipv4 + ipv6, hwaddr=hwaddr, ifindex=None, ifname=if_name) # TODO: 'hostname' addresses are unused msg = 'node \'%s\' interface \'%s\' connected ' \ 'to network \'%s\'' % (node.name, if_name, network.name) logger.info(msg) # set link parameters for wired links if nodeutils.is_node( network, (NodeTypes.HUB, NodeTypes.PEER_TO_PEER, NodeTypes.SWITCH)): netif = node.netif(ifindex) self.set_wired_link_parameters(network, netif, device_id)
def cmd(self, args, wait=True): """ Execute a command on a node and return the status (return code). :param list args: command arguments :param bool wait: wait for command to end or not :return: command status :rtype: int """ if USE_VCMD_MODULE: if not self.cmdchnl.connected(): raise ValueError("self.cmdchnl not connected") tmp = self.cmdchnl.qcmd(args) if not wait: return tmp tmp = tmp.wait() else: if wait: mode = os.P_WAIT else: mode = os.P_NOWAIT tmp = os.spawnlp(mode, VCMD, VCMD, "-c", self.ctrlchnlname, "-q", "--", *args) if not wait: return tmp if tmp: logger.warn("cmd exited with status %s: %s" % (tmp, str(args))) return tmp
def addfile(self, srcname, filename, mode=0644): self.lock.acquire() if not self.up: self.lock.release() raise Exception("Can't access VM file as VM disk isn't ready") if self.booted: self.lock.release() raise Exception("Can't access VM file as VM is already running") if filename in self.files_to_ignore: # self.warn("XEN PVM addfile(filename=%s) ignored" % [filename]) return if filename in self.files_redirection: redirection_filename = self.files_redirection[filename] logger.warn("XEN PVM addfile(filename=%s) redirected to %s", filename, redirection_filename) filename = redirection_filename try: fin = open(srcname, "r") contents = fin.read() fin.close() fout = self.openpausednodefile(filename, "w") fout.write(contents) os.chmod(fout.name, mode) fout.close() logger.info("created nodefile: %s; mode: 0%o", fout.name, mode) finally: self.lock.release() logger.warn("XEN PVM addfile(filename=%s) called", filename)
def addtunnel(self, remoteip, n1num, n2num, localnum): """ Adds a new GreTapBridge between nodes on two different machines. :param str remoteip: remote address for tunnel :param int n1num: node one id :param int n2num: node two id :param int localnum: local id :return: nothing """ key = self.tunnelkey(n1num, n2num) if localnum == n2num: remotenum = n1num else: remotenum = n2num if key in self.tunnels.keys(): logger.warn("tunnel with key %s (%s-%s) already exists!", key, n1num, n2num) else: objid = key & ((1 << 16) - 1) logger.info("adding tunnel for %s-%s to %s with key %s", n1num, n2num, remoteip, key) if localnum in self.physical_nodes: # no bridge is needed on physical nodes; use the GreTap directly gt = GreTap(node=None, name=None, session=self.session, remoteip=remoteip, key=key) else: gt = self.session.add_object(cls=GreTapBridge, objid=objid, policy="ACCEPT", remoteip=remoteip, key=key) gt.localnum = localnum gt.remotenum = remotenum self.tunnels[key] = gt
def savestate(self): """ Save the addresses and other interface state before using the interface for emulation purposes. TODO: save/restore the PROMISC flag :return: nothing """ self.old_up = False self.old_addrs = [] cmd = [constants.IP_BIN, "addr", "show", "dev", self.localname] try: tmp = subprocess.Popen(cmd, stdout=subprocess.PIPE) except OSError: logger.exception("Failed to run %s command: %s", constants.IP_BIN, cmd) if tmp.wait(): logger.warn("Command failed: %s", cmd) return lines = tmp.stdout.read() tmp.stdout.close() for l in lines.split("\n"): items = l.split() if len(items) < 2: continue if items[1] == "%s:" % self.localname: flags = items[2][1:-1].split(",") if "UP" in flags: self.old_up = True elif items[0] == "inet": self.old_addrs.append((items[1], items[3])) elif items[0] == "inet6": if items[1][:4] == "fe80": continue self.old_addrs.append((items[1], None))
def setupserver(self, servername): """ Send the appropriate API messages for configuring the specified emulation server. :param str servername: name of server to configure :return: nothing """ server = self.getserverbyname(servername) if server is None: logger.warn("ignoring unknown server: %s", servername) return if server.sock is None or server.host is None or server.port is None: logger.info("ignoring disconnected server: %s", servername) return # communicate this session"s current state to the server tlvdata = coreapi.CoreEventTlv.pack(EventTlvs.TYPE.value, self.session.state) msg = coreapi.CoreEventMessage.pack(0, tlvdata) server.sock.send(msg) # send a Configuration message for the broker object and inform the # server of its local name tlvdata = "" tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.OBJECT.value, "broker") tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.TYPE.value, ConfigFlags.UPDATE.value) tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.DATA_TYPES.value, (ConfigDataTypes.STRING.value,)) tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.VALUES.value, "%s:%s:%s" % (server.name, server.host, server.port)) tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.SESSION.value, "%s" % self.session.session_id) msg = coreapi.CoreConfMessage.pack(0, tlvdata) server.sock.send(msg)
def parseinterface(self, n, ifc): """ Parse a interface block such as: <interface name="eth0" net="37278"> <address type="mac">00:00:00:aa:00:01</address> <address>10.0.0.2/24</address> <address>2001::2/64</address> </interface> """ name = str(ifc.getAttribute("name")) netid = str(ifc.getAttribute("net")) hwaddr = None addrlist = [] try: net = n.session.get_object_by_name(netid) except KeyError: logger.warn("skipping node %s interface %s: unknown net %s", n.name, name, netid) return for addr in ifc.getElementsByTagName("address"): addrstr = xmlutils.get_text_child(addr) if addrstr is None: continue if addr.getAttribute("type") == "mac": hwaddr = addrstr else: addrlist.append(addrstr) i = n.newnetif(net, addrlist=addrlist, hwaddr=hwaddr, ifindex=None, ifname=name) for model in ifc.getElementsByTagName("model"): self.parsemodel(model, n, n.objid) key = (n.name, name) if key in self.linkparams: netif = n.netif(i) for k, v in self.linkparams[key]: netif.setparam(k, v)
def addsymlink(self, path, file): """ Create a symbolic link from /path/name/file -> /tmp/pycore.nnnnn/@.conf/path.name/file """ dirname = path if dirname and dirname[0] == "/": dirname = dirname[1:] dirname = dirname.replace("/", ".") if file: pathname = os.path.join(path, file) sym = os.path.join(self.session.session_dir, "@.conf", dirname, file) else: pathname = path sym = os.path.join(self.session.session_dir, "@.conf", dirname) if os.path.islink(pathname): if os.readlink(pathname) == sym: # this link already exists - silently return return os.unlink(pathname) else: if os.path.exists(pathname): logger.warn( "did not create symlink for %s since path exists on host", pathname) return logger.info("creating symlink %s -> %s", pathname, sym) os.symlink(sym, pathname)
def main(): """ Main routine when running from command-line. """ usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage=usagestr) parser.set_defaults(numnodes=4, duration=600, verbose=False, visualize=False) parser.add_option("-d", "--duration", dest="duration", type=int, help="number of seconds to run the simulation") parser.add_option("-n", "--numnodes", dest="numnodes", type=int, help="number of nodes") parser.add_option("-z", "--visualize", dest="visualize", action="store_true", help="enable visualizer") parser.add_option("-v", "--verbose", dest="verbose", action="store_true", help="be more verbose") def usage(msg=None, err=0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) opt, args = parser.parse_args() if opt.numnodes < 2: usage("invalid numnodes: %s" % opt.numnodes) for a in args: logger.warn("ignoring command line argument: '%s'", a) return ltesession(opt)
def add(cls, service): """ Add a service to manager. :param CoreService service: service to add :return: nothing """ name = service.name logger.info("loading service: class(%s) name(%s)", service.__name__, name) # avoid duplicate services if name in cls.services: raise ValueError("duplicate service being added: %s" % name) # validate dependent executables are present for executable in service.executables: if not which(executable): logger.warn("service(%s) missing executable: %s", service.name, executable) raise ValueError("service(%s) missing executable: %s" % (service.name, executable)) # make service available cls.services[name] = service
def parse_default_services(self): # defaults from the CORE GUI self.default_services = { 'router': ['zebra', 'OSPFv2', 'OSPFv3', 'IPForward'], 'host': ['DefaultRoute', 'SSH'], 'PC': [ 'DefaultRoute', ], 'mdr': ['zebra', 'OSPFv3MDR', 'IPForward'], } default_services = xmlutils.get_first_child_by_tag_name( self.scenario, 'CORE:defaultservices') if not default_services: return for device in xmlutils.iter_children_with_name(default_services, 'device'): device_type = device.getAttribute('type') if not device_type: logger.warn( 'parse_default_services: no type attribute found for device' ) continue services = [] for service in xmlutils.iter_children_with_name(device, 'service'): name = service.getAttribute('name') if name: services.append(str(name)) self.default_services[device_type] = services # store default services for the session for t, s in self.default_services.iteritems(): self.session.services.defaultservices[t] = s logger.info('default services for node type \'%s\' set to: %s' % (t, s))
def cmdresult(self, args): cmd_string = string.join(args, " ") if cmd_string in self.cmds_to_ignore: # self.warn("XEN PVM cmd(args=[%s]) called and ignored" % cmdAsString) return 0, "" logger.warn( "XEN PVM cmdresult(args=[%s]) called, but not yet implemented", cmd_string) return 0, ""
def cmd(self, args, wait=True): if wait: mode = os.P_WAIT else: mode = os.P_NOWAIT tmp = subprocess.call([constants.VIMAGE_BIN, self.name] + args, cwd=self.nodedir) if not wait: tmp = None if tmp: logger.warn("cmd exited with status %s: %s", tmp, str(args)) return tmp
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None, jitter=None, netif2=None): """ Invoked when a Link Message is received. Default is unimplemented. :param core.netns.vif.Veth netif: interface one :param bw: bandwidth to set to :param delay: packet delay to set to :param loss: packet loss to set to :param duplicate: duplicate percentage to set to :param jitter: jitter to set to :param core.netns.vif.Veth netif2: interface two :return: nothing """ logger.warn("emane model(%s) does not support link configuration", self.name)
def parsenetem(self, model, obj, kvs): """ Determine interface and invoke setparam() using the parsed (key, value) pairs. """ ifname = model.getAttribute("netif") peer = model.getAttribute("peer") key = (peer, ifname) # nodes and interfaces do not exist yet, at this point of the parsing, # save (key, value) pairs for later try: kvs = map(self.numericvalue, kvs) except ValueError: logger.warn("error parsing link parameters for '%s' on '%s'", ifname, peer) self.linkparams[key] = kvs
def set_object_position_pixel(self, obj, point): x = float(point.getAttribute('x')) y = float(point.getAttribute('y')) z = point.getAttribute('z') if z: z = float(z) else: z = 0.0 # TODO: zMode is unused # z_mode = point.getAttribute('zMode')) if x < 0.0: logger.warn('limiting negative x position of \'%s\' to zero: %s' % (obj.name, x)) x = 0.0 if y < 0.0: logger.warn('limiting negative y position of \'%s\' to zero: %s' % (obj.name, y)) y = 0.0 obj.setposition(x, y, z)
def addDevices(self): """ Add device elements to the scenario plan. """ for node in self.coreSession.objects.itervalues(): if not isinstance(node, nodes.PyCoreNode): continue try: DeviceElement(self, self, node) except: logger.exception("error adding device") if hasattr(node, "name") and node.name: logger.warn('Unsupported device name: %s, class: %s, type: %s', node.name, node.__class__.__name__, node.type) else: logger.warn('Unsupported device: %s', node.__class__.__name__)
def handlelocationevent(self, rxnemid, eid, data): """ Handle an EMANE location event. """ events = LocationEvent() events.restore(data) for event in events: txnemid, attrs = event if "latitude" not in attrs or "longitude" not in attrs or "altitude" not in attrs: logger.warn("dropped invalid location event") continue # yaw,pitch,roll,azimuth,elevation,velocity are unhandled lat = attrs["latitude"] lon = attrs["longitude"] alt = attrs["altitude"] logger.debug("emane location event: %s,%s,%s", lat, lon, alt) self.handlelocationeventtoxyz(txnemid, lat, lon, alt)
def netifstats(self, ifname=None): """ Retrieve network interface state. :param str ifname: name of interface to get state for :return: interface state information :rtype: dict """ stats = {} args = ["cat", "/proc/net/dev"] p, stdin, stdout, stderr = self.popen(args) stdin.close() # ignore first line stdout.readline() # second line has count names tmp = stdout.readline().strip().split("|") rxkeys = tmp[1].split() txkeys = tmp[2].split() for line in stdout: line = line.strip().split() devname, tmp = line[0].split(":") if tmp: line.insert(1, tmp) stats[devname] = {"rx": {}, "tx": {}} field = 1 for count in rxkeys: stats[devname]["rx"][count] = int(line[field]) field += 1 for count in txkeys: stats[devname]["tx"][count] = int(line[field]) field += 1 err = stderr.read() stdout.close() stderr.close() status = p.wait() if status: logger.warn("nonzero exist status (%s) for cmd: %s", status, args) if err: logger.warn("error output: %s", err) if ifname is not None: return stats[ifname] else: return stats
def parse_layer2_device(self, device): objid, device_name = self.get_common_attributes(device) logger.info('parsing layer-2 device: name=%s id=%s' % (device_name, objid)) try: return self.session.get_object(objid) except KeyError: logger.exception("error geting object: %s", objid) device_type = self.device_type(device) if device_type == 'hub': device_class = nodeutils.get_node_class(NodeTypes.HUB) elif device_type == 'switch': device_class = nodeutils.get_node_class(NodeTypes.SWITCH) else: logger.warn('unknown layer-2 device type: \'%s\'' % device_type) assert False # XXX for testing n = self.create_core_object(device_class, objid, device_name, device, None) return n
def get_default_services(self, node_type): """ Get the list of default services that should be enabled for a node for the given node type. :param node_type: node type to get default services for :return: default services :rtype: list[CoreService] """ logger.debug("getting default services for type: %s", node_type) results = [] defaults = self.default_services.get(node_type, []) for name in defaults: logger.debug("checking for service with service manager: %s", name) service = ServiceManager.get(name) if not service: logger.warn("default service %s is unknown", name) else: results.append(service) return results
def parsenets(self): linkednets = [] for net in self.np.getElementsByTagName("NetworkDefinition"): node_id, name, node_type = self.getcommonattributes(net) nodecls = xmlutils.xml_type_to_node_class(node_type) if not nodecls: logger.warn("skipping unknown network node '%s' type '%s'", name, node_type) continue n = self.session.add_object(cls=nodecls, objid=node_id, name=name, start=self.start) if name in self.coords: x, y, z = self.coords[name] n.setposition(x, y, z) xmlutils.get_params_set_attrs(net, ("icon", "canvas", "opaque"), n) if hasattr(n, "canvas") and n.canvas is not None: n.canvas = int(n.canvas) # links between two nets (e.g. switch-switch) for ifc in net.getElementsByTagName("interface"): netid = str(ifc.getAttribute("net")) ifcname = str(ifc.getAttribute("name")) linkednets.append((n, netid, ifcname)) self.parsemodels(net, n) # link networks together now that they all have been parsed for n, netid, ifcname in linkednets: try: n2 = n.session.get_object_by_name(netid) except KeyError: logger.warn("skipping net %s interface: unknown net %s", n.name, netid) continue upstream = False netif = n.getlinknetif(n2) if netif is None: netif = n2.linknet(n) else: netif.swapparams('_params_up') upstream = True key = (n2.name, ifcname) if key in self.linkparams: for k, v in self.linkparams[key]: netif.setparam(k, v) if upstream: netif.swapparams('_params_up')
def add_services(cls, path): """ Method for retrieving all CoreServices from a given path. :param str path: path to retrieve services from :return: list of core services that failed to load :rtype: list[str] """ service_errors = [] services = utils.load_classes(path, CoreService) for service in services: if not service.name: continue service.on_load() try: cls.add(service) except ValueError as e: service_errors.append(service.name) logger.warn("not loading service: %s", e) return service_errors
def parse_addresses(self, interface): mac = [] ipv4 = [] ipv6 = [] hostname = [] for address in xmlutils.iter_children_with_name(interface, 'address'): addr_type = address.getAttribute('type') if not addr_type: msg = 'no type attribute found for address ' \ 'in interface: \'%s\'' % interface.toxml('utf-8') logger.warn(msg) assert False # XXX for testing addr_text = xmlutils.get_child_text_trim(address) if not addr_text: msg = 'no text found for address ' \ 'in interface: \'%s\'' % interface.toxml('utf-8') logger.warn(msg) assert False # XXX for testing if addr_type == 'mac': mac.append(addr_text) elif addr_type == 'IPv4': ipv4.append(addr_text) elif addr_type == 'IPv6': ipv6.append(addr_text) elif addr_type == 'hostname': hostname.append(addr_text) else: msg = 'skipping unknown address type \'%s\' in ' \ 'interface: \'%s\'' % (addr_type, interface.toxml('utf-8')) logger.warn(msg) assert False # XXX for testing return mac, ipv4, ipv6, hostname
def load_classes(path, clazz): """ Dynamically load classes for use within CORE. :param path: path to load classes from :param clazz: class type expected to be inherited from for loading :return: list of classes loaded """ # validate path exists logger.debug("attempting to load modules from path: %s", path) if not os.path.isdir(path): logger.warn("invalid custom module directory specified" ": %s" % path) # check if path is in sys.path parent_path = os.path.dirname(path) if parent_path not in sys.path: logger.debug("adding parent path to allow imports: %s", parent_path) sys.path.append(parent_path) # retrieve potential service modules, and filter out invalid modules base_module = os.path.basename(path) module_names = os.listdir(path) module_names = filter(lambda x: _valid_module(path, x), module_names) module_names = map(lambda x: x[:-3], module_names) # import and add all service modules in the path classes = [] for module_name in module_names: import_statement = "%s.%s" % (base_module, module_name) logger.debug("importing custom module: %s", import_statement) try: module = importlib.import_module(import_statement) members = inspect.getmembers(module, lambda x: _is_class(module, x, clazz)) for member in members: valid_class = member[1] classes.append(valid_class) except: logger.exception("unexpected error during import, skipping: %s", import_statement) return classes