def link_message(n1, n2, intf_one=None, address_one=None, intf_two=None, address_two=None, key=None): """ Convenience method for creating link TLV messages. :param int n1: node one id :param int n2: node two id :param int intf_one: node one interface id :param core.misc.ipaddress.IpAddress address_one: node one ip4 address :param int intf_two: node two interface id :param core.misc.ipaddress.IpAddress address_two: node two ip4 address :param int key: tunnel key for link if needed :return: tlv mesage :rtype: core.api.coreapi.CoreLinkMessage """ mac_one, mac_two = None, None if address_one: mac_one = MacAddress.random() if address_two: mac_two = MacAddress.random() values = [ (LinkTlvs.N1_NUMBER, n1), (LinkTlvs.N2_NUMBER, n2), (LinkTlvs.DELAY, 0), (LinkTlvs.BANDWIDTH, 0), (LinkTlvs.PER, "0"), (LinkTlvs.DUP, "0"), (LinkTlvs.JITTER, 0), (LinkTlvs.TYPE, LinkTypes.WIRED.value), (LinkTlvs.INTERFACE1_NUMBER, intf_one), (LinkTlvs.INTERFACE1_IP4, address_one), (LinkTlvs.INTERFACE1_IP4_MASK, 24), (LinkTlvs.INTERFACE1_MAC, mac_one), (LinkTlvs.INTERFACE2_NUMBER, intf_two), (LinkTlvs.INTERFACE2_IP4, address_two), (LinkTlvs.INTERFACE2_IP4_MASK, 24), (LinkTlvs.INTERFACE2_MAC, mac_two), ] if key: values.append((LinkTlvs.KEY, key)) return CoreLinkMessage.create(MessageFlags.ADD.value, values)
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 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 newveth(self, ifindex=None, ifname=None, net=None): """ Create a new interface. :param int ifindex: index for the new interface :param str ifname: name for the new interface :param net: network to associate interface with :return: nothing """ with self.lock: if ifindex is None: ifindex = self.newifindex() if ifname is None: ifname = "eth%d" % ifindex sessionid = self.session.short_session_id() try: suffix = "%x.%s.%s" % (self.objid, ifindex, sessionid) except TypeError: suffix = "%s.%s.%s" % (self.objid, ifindex, sessionid) localname = "veth" + suffix if len(localname) >= 16: raise ValueError("interface local name (%s) too long" % localname) name = localname + "p" if len(name) >= 16: raise ValueError("interface name (%s) too long" % name) veth = VEth(node=self, name=name, localname=localname, net=net, start=self.up) if self.up: utils.check_cmd([constants.IP_BIN, "link", "set", veth.name, "netns", str(self.pid)]) self.check_cmd([constants.IP_BIN, "link", "set", veth.name, "name", ifname]) veth.name = ifname if self.up: # TODO: potentially find better way to query interface ID # retrieve interface information output = self.check_cmd(["ip", "link", "show", veth.name]) logger.debug("interface command output: %s", output) output = output.split("\n") veth.flow_id = int(output[0].strip().split(":")[0]) + 1 logger.debug("interface flow index: %s - %s", veth.name, veth.flow_id) veth.hwaddr = MacAddress.from_string(output[1].strip().split()[1]) logger.debug("interface mac: %s - %s", veth.name, veth.hwaddr) try: self.addnetif(veth, ifindex) except ValueError as e: veth.shutdown() del veth raise e return ifindex
def new_obj(value): """ Retrieve mac address from a string representation. :param str value: value to get Ipv4 address from :return: Ipv4 address :rtype: core.misc.ipaddress.MacAddress """ # only use 48 bits return MacAddress(address=value[2:])
def link_message(n1, n2, intf_one=None, address_one=None, intf_two=None, address_two=None, key=None): """ Convenience method for creating link TLV messages. :param int n1: node one id :param int n2: node two id :param int intf_one: node one interface id :param core.misc.ipaddress.IpAddress address_one: node one ip4 address :param int intf_two: node two interface id :param core.misc.ipaddress.IpAddress address_two: node two ip4 address :param int key: tunnel key for link if needed :return: tlv mesage :rtype: core.api.coreapi.CoreLinkMessage """ mac_one, mac_two = None, None if address_one: mac_one = MacAddress.random() if address_two: mac_two = MacAddress.random() values = [ (LinkTlvs.N1_NUMBER, n1), (LinkTlvs.N2_NUMBER, n2), (LinkTlvs.DELAY, 0), (LinkTlvs.BANDWIDTH, 0), (LinkTlvs.PER, "0"), (LinkTlvs.DUP, "0"), (LinkTlvs.JITTER, 0), (LinkTlvs.TYPE, LinkTypes.WIRED.value), (LinkTlvs.INTERFACE1_NUMBER, intf_one), (LinkTlvs.INTERFACE1_IP4, address_one), (LinkTlvs.INTERFACE1_IP4_MASK, 24), (LinkTlvs.INTERFACE1_MAC, mac_one), (LinkTlvs.INTERFACE2_NUMBER, intf_two), (LinkTlvs.INTERFACE2_IP4, address_two), (LinkTlvs.INTERFACE2_IP4_MASK, 24), (LinkTlvs.INTERFACE2_MAC, mac_two), ] if key: values.append((LinkTlvs.KEY, key)) return CoreLinkMessage.create(MessageFlags.ADD.value, values)
def create_interface_data(interface_element): interface_id = int(interface_element.get("id")) name = interface_element.get("name") mac = interface_element.get("mac") if mac: mac = MacAddress.from_string(mac) ip4 = interface_element.get("ip4") ip4_mask = get_int(interface_element, "ip4_mask") ip6 = interface_element.get("ip6") ip6_mask = get_int(interface_element, "ip6_mask") return InterfaceData(interface_id, name, mac, ip4, ip4_mask, ip6, ip6_mask)
def create_interface_data(interface_element): interface_id = int(interface_element.get("id")) name = interface_element.get("name") mac = interface_element.get("mac") if mac: mac = MacAddress.from_string(mac) ip4 = interface_element.get("ip4") ip4_mask = get_int(interface_element, "ip4_mask") ip6 = interface_element.get("ip6") ip6_mask = get_int(interface_element, "ip6_mask") return InterfaceData(interface_id, name, mac, ip4, ip4_mask, ip6, ip6_mask)
def add_remove_control_interface(self, node, net_index=0, remove=False, conf_required=True): """ Add a control interface to a node when a 'controlnet' prefix is listed in the config file or session options. Uses addremovectrlnet() to build or remove the control bridge. If conf_reqd is False, the control network may be built even when the user has not configured one (e.g. for EMANE.) :param core.netns.nodes.CoreNode node: node to add or remove control interface :param int net_index: network index :param bool remove: flag to check if it should be removed :param bool conf_required: flag to check if conf is required :return: nothing """ control_net = self.add_remove_control_net(net_index, remove, conf_required) if not control_net: return if not node: return # ctrl# already exists if node.netif(control_net.CTRLIF_IDX_BASE + net_index): return control_ip = node.objid try: addrlist = [ "%s/%s" % (control_net.prefix.addr(control_ip), control_net.prefix.prefixlen) ] except ValueError: msg = "Control interface not added to node %s. " % node.objid msg += "Invalid control network prefix (%s). " % control_net.prefix msg += "A longer prefix length may be required for this many nodes." logger.exception(msg) return interface1 = node.newnetif(net=control_net, ifindex=control_net.CTRLIF_IDX_BASE + net_index, ifname="ctrl%d" % net_index, hwaddr=MacAddress.random(), addrlist=addrlist) node.netif(interface1).control = True
def buildplatformxml(self, ctrlnet): """ Build a platform.xml file now that all nodes are configured. """ values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1] nemid = int(self.emane_config.valueof("nem_id_start", values)) platformxmls = {} # assume self._objslock is already held here for key in sorted(self._emane_nodes.keys()): emane_node = self._emane_nodes[key] nems = emane_node.buildplatformxmlentry(self.xmldoc("platform")) for netif in sorted(nems, key=lambda x: x.node.objid): nementry = nems[netif] nementry.setAttribute("id", "%d" % nemid) key = netif.node.objid if netif.transport_type == "raw": key = "host" otadev = ctrlnet.brname eventdev = ctrlnet.brname else: otadev = None eventdev = None if key not in platformxmls: platformxmls[key] = self.newplatformxmldoc( values, otadev, eventdev) doc = platformxmls[key] plat = doc.getElementsByTagName("platform").pop() plat.appendChild(nementry) emane_node.setnemid(netif, nemid) macstr = self._hwaddr_prefix + ":00:00:" macstr += "%02X:%02X" % ((nemid >> 8) & 0xFF, nemid & 0xFF) netif.sethwaddr(MacAddress.from_string(macstr)) nemid += 1 for key in sorted(platformxmls.keys()): if key == "host": self.xmlwrite(platformxmls["host"], "platform.xml") continue self.xmlwrite(platformxmls[key], "platform%d.xml" % key)
def create_interface(self, node, name=None, mac=None): """ Creates interface data for linking nodes, using the nodes unique id for generation, along with a random mac address, unless provided. :param core.coreobj.PyCoreNode node: node to create interface for :param str name: name to set for interface, default is eth{id} :param str mac: mac address to use for this interface, default is random generation :return: new interface data for the provided node :rtype: InterfaceData """ # interface id inteface_id = node.newifindex() # generate ip4 data ip4 = None ip4_mask = None if self.ip4: ip4 = str(self.ip4.addr(node.objid)) ip4_mask = self.ip4.prefixlen # generate ip6 data ip6 = None ip6_mask = None if self.ip6: ip6 = str(self.ip6.addr(node.objid)) ip6_mask = self.ip6.prefixlen # random mac if not mac: mac = MacAddress.random() return InterfaceData( _id=inteface_id, name=name, ip4=ip4, ip4_mask=ip4_mask, ip6=ip6, ip6_mask=ip6_mask, mac=mac )
def add_remove_control_interface(self, node, net_index=0, remove=False, conf_required=True): """ Add a control interface to a node when a 'controlnet' prefix is listed in the config file or session options. Uses addremovectrlnet() to build or remove the control bridge. If conf_reqd is False, the control network may be built even when the user has not configured one (e.g. for EMANE.) :param core.netns.nodes.CoreNode node: node to add or remove control interface :param int net_index: network index :param bool remove: flag to check if it should be removed :param bool conf_required: flag to check if conf is required :return: nothing """ control_net = self.add_remove_control_net(net_index, remove, conf_required) if not control_net: return if not node: return # ctrl# already exists if node.netif(control_net.CTRLIF_IDX_BASE + net_index): return control_ip = node.objid try: addrlist = ["%s/%s" % (control_net.prefix.addr(control_ip), control_net.prefix.prefixlen)] except ValueError: msg = "Control interface not added to node %s. " % node.objid msg += "Invalid control network prefix (%s). " % control_net.prefix msg += "A longer prefix length may be required for this many nodes." logger.exception(msg) return interface1 = node.newnetif(net=control_net, ifindex=control_net.CTRLIF_IDX_BASE + net_index, ifname="ctrl%d" % net_index, hwaddr=MacAddress.random(), addrlist=addrlist) node.netif(interface1).control = True
def build_node_platform_xml(emane_manager, control_net, node, nem_id, platform_xmls): """ Create platform xml for a specific node. :param core.emane.emanemanager.EmaneManager emane_manager: emane manager with emane configurations :param core.netns.nodes.CtrlNet control_net: control net node for this emane network :param core.emane.nodes.EmaneNode node: node to write platform xml for :param int nem_id: nem id to use for interfaces for this node :param dict platform_xmls: stores platform xml elements to append nem entries to :return: the next nem id that can be used for creating platform xml files :rtype: int """ logging.debug("building emane platform xml for node(%s): %s", node, node.name) nem_entries = {} if node.model is None: logging.warn("warning: EmaneNode %s has no associated model", node.name) return nem_entries for netif in node.netifs(): # build nem xml nem_definition = nem_file_name(node.model, netif) nem_element = etree.Element("nem", id=str(nem_id), name=netif.localname, definition=nem_definition) # check if this is an external transport, get default config if an interface specific one does not exist config = emane_manager.getifcconfig(node.model.object_id, netif, node.model.name) if is_external(config): nem_element.set("transport", "external") platform_endpoint = "platformendpoint" add_param(nem_element, platform_endpoint, config[platform_endpoint]) transport_endpoint = "transportendpoint" add_param(nem_element, transport_endpoint, config[transport_endpoint]) else: # build transport xml transport_type = netif.transport_type if not transport_type: logging.info("warning: %s interface type unsupported!", netif.name) transport_type = "raw" transport_file = transport_file_name(node.objid, transport_type) transport_element = etree.SubElement(nem_element, "transport", definition=transport_file) # add transport parameter add_param(transport_element, "device", netif.name) # add nem entry nem_entries[netif] = nem_element # merging code key = netif.node.objid if netif.transport_type == "raw": key = "host" otadev = control_net.brname eventdev = control_net.brname else: otadev = None eventdev = None platform_element = platform_xmls.get(key) if platform_element is None: platform_element = etree.Element("platform") if otadev: emane_manager.set_config("otamanagerdevice", otadev) if eventdev: emane_manager.set_config("eventservicedevice", eventdev) # append all platform options (except starting id) to doc for configuration in emane_manager.emane_config.emulator_config: name = configuration.id if name == "platform_id_start": continue value = emane_manager.get_config(name) add_param(platform_element, name, value) # add platform xml platform_xmls[key] = platform_element platform_element.append(nem_element) node.setnemid(netif, nem_id) macstr = _hwaddr_prefix + ":00:00:" macstr += "%02X:%02X" % ((nem_id >> 8) & 0xFF, nem_id & 0xFF) netif.sethwaddr(MacAddress.from_string(macstr)) # increment nem id nem_id += 1 for key in sorted(platform_xmls.keys()): if key == "host": file_name = "platform.xml" else: file_name = "platform%d.xml" % key platform_element = platform_xmls[key] doc_name = "platform" file_path = os.path.join(emane_manager.session.session_dir, file_name) create_file(platform_element, doc_name, file_path) return nem_id
def build_node_platform_xml(emane_manager, control_net, node, nem_id, platform_xmls): """ Create platform xml for a specific node. :param core.emane.emanemanager.EmaneManager emane_manager: emane manager with emane configurations :param core.netns.nodes.CtrlNet control_net: control net node for this emane network :param core.emane.nodes.EmaneNode node: node to write platform xml for :param int nem_id: nem id to use for interfaces for this node :param dict platform_xmls: stores platform xml elements to append nem entries to :return: the next nem id that can be used for creating platform xml files :rtype: int """ logger.debug("building emane platform xml for node(%s): %s", node, node.name) nem_entries = {} if node.model is None: logger.warn("warning: EmaneNode %s has no associated model", node.name) return nem_entries for netif in node.netifs(): # build nem xml nem_definition = nem_file_name(node.model, netif) nem_element = etree.Element("nem", id=str(nem_id), name=netif.localname, definition=nem_definition) # check if this is an external transport, get default config if an interface specific one does not exist config = emane_manager.getifcconfig(node.model.object_id, netif, node.model.name) if is_external(config): nem_element.set("transport", "external") platform_endpoint = "platformendpoint" add_param(nem_element, platform_endpoint, config[platform_endpoint]) transport_endpoint = "transportendpoint" add_param(nem_element, transport_endpoint, config[transport_endpoint]) else: # build transport xml transport_type = netif.transport_type if not transport_type: logger.info("warning: %s interface type unsupported!", netif.name) transport_type = "raw" transport_file = transport_file_name(node.objid, transport_type) transport_element = etree.SubElement(nem_element, "transport", definition=transport_file) # add transport parameter add_param(transport_element, "device", netif.name) # add nem entry nem_entries[netif] = nem_element # merging code key = netif.node.objid if netif.transport_type == "raw": key = "host" otadev = control_net.brname eventdev = control_net.brname else: otadev = None eventdev = None platform_element = platform_xmls.get(key) if platform_element is None: platform_element = etree.Element("platform") if otadev: emane_manager.set_config("otamanagerdevice", otadev) if eventdev: emane_manager.set_config("eventservicedevice", eventdev) # append all platform options (except starting id) to doc for configuration in emane_manager.emane_config.emulator_config: name = configuration.id if name == "platform_id_start": continue value = emane_manager.get_config(name) add_param(platform_element, name, value) # add platform xml platform_xmls[key] = platform_element platform_element.append(nem_element) node.setnemid(netif, nem_id) macstr = _hwaddr_prefix + ":00:00:" macstr += "%02X:%02X" % ((nem_id >> 8) & 0xFF, nem_id & 0xFF) netif.sethwaddr(MacAddress.from_string(macstr)) # increment nem id nem_id += 1 for key in sorted(platform_xmls.keys()): if key == "host": file_name = "platform.xml" else: file_name = "platform%d.xml" % key platform_element = platform_xmls[key] doc_name = "platform" file_path = os.path.join(emane_manager.session.session_dir, file_name) create_file(platform_element, doc_name, file_path) return nem_id