Пример #1
0
    def attachnet(self, net):
        """
        Attach a network.

        :param core.coreobj.PyCoreNet net: network to attach
        :return: nothing
        """
        CoreInterface.attachnet(self, net)
Пример #2
0
    def attachnet(self, net: CoreNetworkBase) -> None:
        """
        Attach a network.

        :param net: network to attach
        :return: nothing
        """
        CoreInterface.attachnet(self, net)
Пример #3
0
class Rj45Node(CoreNodeBase):
    """
    RJ45Node is a physical interface on the host linked to the emulated
    network.
    """

    apitype: NodeTypes = NodeTypes.RJ45
    type: str = "rj45"

    def __init__(
        self,
        session: "Session",
        _id: int = None,
        name: str = None,
        mtu: int = 1500,
        server: DistributedServer = None,
    ) -> None:
        """
        Create an RJ45Node instance.

        :param session: core session instance
        :param _id: node id
        :param name: node name
        :param mtu: rj45 mtu
        :param server: remote server node
            will run on, default is None for localhost
        """
        super().__init__(session, _id, name, server)
        self.iface = CoreInterface(session, self, name, name, mtu, server)
        self.iface.transport_type = TransportType.RAW
        self.lock: threading.RLock = threading.RLock()
        self.iface_id: Optional[int] = None
        self.old_up: bool = False
        self.old_addrs: List[Tuple[str, Optional[str]]] = []

    def startup(self) -> None:
        """
        Set the interface in the up state.

        :return: nothing
        :raises CoreCommandError: when there is a command exception
        """
        # interface will also be marked up during net.attach()
        self.savestate()
        self.net_client.device_up(self.iface.localname)
        self.up = True

    def shutdown(self) -> None:
        """
        Bring the interface down. Remove any addresses and queuing
        disciplines.

        :return: nothing
        """
        if not self.up:
            return
        localname = self.iface.localname
        self.net_client.device_down(localname)
        self.net_client.device_flush(localname)
        try:
            self.net_client.delete_tc(localname)
        except CoreCommandError:
            pass
        self.up = False
        self.restorestate()

    def path_exists(self, path: str) -> bool:
        """
        Determines if a file or directory path exists.

        :param path: path to file or directory
        :return: True if path exists, False otherwise
        """
        try:
            self.host_cmd(f"{TEST} -e {path}")
            return True
        except CoreCommandError:
            return False

    def new_iface(self, net: CoreNetworkBase,
                  iface_data: InterfaceData) -> CoreInterface:
        """
        This is called when linking with another node. Since this node
        represents an interface, we do not create another object here,
        but attach ourselves to the given network.

        :param net: new network instance
        :param iface_data: interface data for new interface
        :return: interface index
        :raises ValueError: when an interface has already been created, one max
        """
        with self.lock:
            iface_id = iface_data.id
            if iface_id is None:
                iface_id = 0
            if self.iface.net is not None:
                raise CoreError(
                    "RJ45 nodes support at most 1 network interface")
            self.ifaces[iface_id] = self.iface
            self.iface_id = iface_id
            if net is not None:
                self.iface.attachnet(net)
            for ip in iface_data.get_ips():
                self.add_ip(ip)
            return self.iface

    def delete_iface(self, iface_id: int) -> None:
        """
        Delete a network interface.

        :param iface_id: interface index to delete
        :return: nothing
        """
        self.get_iface(iface_id)
        self.ifaces.pop(iface_id)
        self.shutdown()

    def get_iface(self, iface_id: int) -> CoreInterface:
        if iface_id != self.iface_id or iface_id not in self.ifaces:
            raise CoreError(
                f"node({self.name}) interface({iface_id}) does not exist")
        return self.iface

    def get_iface_id(self, iface: CoreInterface) -> Optional[int]:
        """
        Retrieve network interface index.

        :param iface: network interface to retrieve
            index for
        :return: interface index, None otherwise
        """
        if iface is not self.iface:
            raise CoreError(
                f"node({self.name}) does not have interface({iface.name})")
        return self.iface_id

    def add_ip(self, ip: str) -> None:
        """
        Add an ip address to an interface in the format "10.0.0.1/24".

        :param ip: address to add to interface
        :return: nothing
        :raises CoreError: when ip address provided is invalid
        :raises CoreCommandError: when a non-zero exit status occurs
        """
        self.iface.add_ip(ip)
        if self.up:
            self.net_client.create_address(self.name, ip)

    def remove_ip(self, ip: str) -> None:
        """
        Remove an ip address from an interface in the format "10.0.0.1/24".

        :param ip: ip address to remove from interface
        :return: nothing
        :raises CoreError: when ip address provided is invalid
        :raises CoreCommandError: when a non-zero exit status occurs
        """
        self.iface.remove_ip(ip)
        if self.up:
            self.net_client.delete_address(self.name, ip)

    def savestate(self) -> None:
        """
        Save the addresses and other interface state before using the
        interface for emulation purposes. TODO: save/restore the PROMISC flag

        :return: nothing
        :raises CoreCommandError: when there is a command exception
        """
        self.old_up = False
        self.old_addrs: List[Tuple[str, Optional[str]]] = []
        localname = self.iface.localname
        output = self.net_client.address_show(localname)
        for line in output.split("\n"):
            items = line.split()
            if len(items) < 2:
                continue
            if items[1] == f"{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))
        logging.info("saved rj45 state: addrs(%s) up(%s)", self.old_addrs,
                     self.old_up)

    def restorestate(self) -> None:
        """
        Restore the addresses and other interface state after using it.

        :return: nothing
        :raises CoreCommandError: when there is a command exception
        """
        localname = self.iface.localname
        logging.info("restoring rj45 state: %s", localname)
        for addr in self.old_addrs:
            self.net_client.create_address(localname, addr[0], addr[1])
        if self.old_up:
            self.net_client.device_up(localname)

    def setposition(self,
                    x: float = None,
                    y: float = None,
                    z: float = None) -> None:
        """
        Uses setposition from both parent classes.

        :param x: x position
        :param y: y position
        :param z: z position
        :return: True if position changed, False otherwise
        """
        super().setposition(x, y, z)
        self.iface.setposition()

    def termcmdstring(self, sh: str) -> str:
        raise CoreError("rj45 does not support terminal commands")

    def addfile(self, srcname: str, filename: str) -> None:
        raise CoreError("rj45 does not support addfile")

    def nodefile(self,
                 filename: str,
                 contents: str,
                 mode: int = 0o644) -> None:
        raise CoreError("rj45 does not support nodefile")

    def cmd(self, args: str, wait: bool = True, shell: bool = False) -> str:
        raise CoreError("rj45 does not support cmds")
Пример #4
0
class Rj45Node(CoreNodeBase):
    """
    RJ45Node is a physical interface on the host linked to the emulated
    network.
    """

    apitype: NodeTypes = NodeTypes.RJ45
    type: str = "rj45"

    def __init__(
        self,
        session: "Session",
        _id: int = None,
        name: str = None,
        mtu: int = 1500,
        start: bool = True,
        server: DistributedServer = None,
    ) -> None:
        """
        Create an RJ45Node instance.

        :param session: core session instance
        :param _id: node id
        :param name: node name
        :param mtu: rj45 mtu
        :param start: start flag
        :param server: remote server node
            will run on, default is None for localhost
        """
        super().__init__(session, _id, name, start, server)
        self.interface = CoreInterface(session, self, name, name, mtu, server)
        self.interface.transport_type = TransportType.RAW
        self.lock: threading.RLock = threading.RLock()
        self.ifindex: Optional[int] = None
        self.old_up: bool = False
        self.old_addrs: List[Tuple[str, Optional[str]]] = []
        if start:
            self.startup()

    def startup(self) -> None:
        """
        Set the interface in the up state.

        :return: nothing
        :raises CoreCommandError: when there is a command exception
        """
        # interface will also be marked up during net.attach()
        self.savestate()
        self.net_client.device_up(self.interface.localname)
        self.up = True

    def shutdown(self) -> None:
        """
        Bring the interface down. Remove any addresses and queuing
        disciplines.

        :return: nothing
        """
        if not self.up:
            return
        localname = self.interface.localname
        self.net_client.device_down(localname)
        self.net_client.device_flush(localname)
        try:
            self.net_client.delete_tc(localname)
        except CoreCommandError:
            pass
        self.up = False
        self.restorestate()

    def newnetif(self, net: CoreNetworkBase, interface: InterfaceData) -> int:
        """
        This is called when linking with another node. Since this node
        represents an interface, we do not create another object here,
        but attach ourselves to the given network.

        :param net: new network instance
        :param interface: interface data for new interface
        :return: interface index
        :raises ValueError: when an interface has already been created, one max
        """
        with self.lock:
            ifindex = interface.id
            if ifindex is None:
                ifindex = 0
            if self.interface.net is not None:
                raise ValueError(
                    "RJ45 nodes support at most 1 network interface")
            self._netif[ifindex] = self.interface
            self.ifindex = ifindex
            if net is not None:
                self.interface.attachnet(net)
            for addr in interface.get_addresses():
                self.addaddr(addr)
            return ifindex

    def delnetif(self, ifindex: int) -> None:
        """
        Delete a network interface.

        :param ifindex: interface index to delete
        :return: nothing
        """
        if ifindex is None:
            ifindex = 0
        self._netif.pop(ifindex)
        if ifindex == self.ifindex:
            self.shutdown()
        else:
            raise ValueError(f"ifindex {ifindex} does not exist")

    def netif(self,
              ifindex: int,
              net: CoreNetworkBase = None) -> Optional[CoreInterface]:
        """
        This object is considered the network interface, so we only
        return self here. This keeps the RJ45Node compatible with
        real nodes.

        :param ifindex: interface index to retrieve
        :param net: network to retrieve
        :return: a network interface
        """
        if net is not None and net == self.interface.net:
            return self.interface
        if ifindex is None:
            ifindex = 0
        if ifindex == self.ifindex:
            return self.interface
        return None

    def getifindex(self, netif: CoreInterface) -> Optional[int]:
        """
        Retrieve network interface index.

        :param netif: network interface to retrieve
            index for
        :return: interface index, None otherwise
        """
        if netif != self.interface:
            return None
        return self.ifindex

    def addaddr(self, addr: str) -> None:
        """
        Add address to to network interface.

        :param addr: address to add
        :return: nothing
        :raises CoreCommandError: when there is a command exception
        """
        addr = utils.validate_ip(addr)
        if self.up:
            self.net_client.create_address(self.name, addr)
        self.interface.addaddr(addr)

    def deladdr(self, addr: str) -> None:
        """
        Delete address from network interface.

        :param addr: address to delete
        :return: nothing
        :raises CoreCommandError: when there is a command exception
        """
        if self.up:
            self.net_client.delete_address(self.name, addr)
        self.interface.deladdr(addr)

    def savestate(self) -> None:
        """
        Save the addresses and other interface state before using the
        interface for emulation purposes. TODO: save/restore the PROMISC flag

        :return: nothing
        :raises CoreCommandError: when there is a command exception
        """
        self.old_up = False
        self.old_addrs: List[Tuple[str, Optional[str]]] = []
        localname = self.interface.localname
        output = self.net_client.address_show(localname)
        for line in output.split("\n"):
            items = line.split()
            if len(items) < 2:
                continue
            if items[1] == f"{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))
        logging.info("saved rj45 state: addrs(%s) up(%s)", self.old_addrs,
                     self.old_up)

    def restorestate(self) -> None:
        """
        Restore the addresses and other interface state after using it.

        :return: nothing
        :raises CoreCommandError: when there is a command exception
        """
        localname = self.interface.localname
        logging.info("restoring rj45 state: %s", localname)
        for addr in self.old_addrs:
            self.net_client.create_address(localname, addr[0], addr[1])
        if self.old_up:
            self.net_client.device_up(localname)

    def setposition(self,
                    x: float = None,
                    y: float = None,
                    z: float = None) -> None:
        """
        Uses setposition from both parent classes.

        :param x: x position
        :param y: y position
        :param z: z position
        :return: True if position changed, False otherwise
        """
        super().setposition(x, y, z)
        self.interface.setposition()

    def termcmdstring(self, sh: str) -> str:
        """
        Create a terminal command string.

        :param sh: shell to execute command in
        :return: str
        """
        raise NotImplementedError