Beispiel #1
0
    def __init__(
        self,
        session: "Session",
        name: str,
        localname: str,
        mtu: int = DEFAULT_MTU,
        server: "DistributedServer" = None,
        node: "CoreNode" = None,
    ) -> None:
        """
        Creates a CoreInterface instance.

        :param session: core session instance
        :param name: interface name
        :param localname: interface local name
        :param mtu: mtu value
        :param server: remote server node will run on, default is None for localhost
        :param node: node for interface
        """
        if len(name) >= 16:
            raise CoreError(f"interface name ({name}) too long, max 16")
        if len(localname) >= 16:
            raise CoreError(
                f"interface local name ({localname}) too long, max 16")
        self.session: "Session" = session
        self.node: Optional["CoreNode"] = node
        self.name: str = name
        self.localname: str = localname
        self.up: bool = False
        self.mtu: int = mtu
        self.net: Optional[CoreNetworkBase] = None
        self.othernet: Optional[CoreNetworkBase] = None
        self.ip4s: List[netaddr.IPNetwork] = []
        self.ip6s: List[netaddr.IPNetwork] = []
        self.mac: Optional[netaddr.EUI] = None
        # placeholder position hook
        self.poshook: Callable[[CoreInterface], None] = lambda x: None
        # used with EMANE
        self.transport_type: TransportType = TransportType.VIRTUAL
        # id of interface for node
        self.node_id: Optional[int] = None
        # id of interface for network
        self.net_id: Optional[int] = None
        # id used to find flow data
        self.flow_id: Optional[int] = None
        self.server: Optional["DistributedServer"] = server
        self.net_client: LinuxNetClient = get_net_client(
            self.session.use_ovs(), self.host_cmd)
        self.control: bool = False
        # configuration data
        self.has_local_netem: bool = False
        self.local_options: LinkOptions = LinkOptions()
        self.has_netem: bool = False
        self.options: LinkOptions = LinkOptions()
Beispiel #2
0
    def get_link_options(self, unidirectional: int) -> LinkOptions:
        """
        Get currently set params as link options.

        :param unidirectional: unidirectional setting
        :return: link options
        """
        delay = self.getparam("delay")
        if delay is not None:
            delay = int(delay)
        bandwidth = self.getparam("bw")
        if bandwidth is not None:
            bandwidth = int(bandwidth)
        dup = self.getparam("duplicate")
        if dup is not None:
            dup = int(dup)
        jitter = self.getparam("jitter")
        if jitter is not None:
            jitter = int(jitter)
        return LinkOptions(
            delay=delay,
            bandwidth=bandwidth,
            dup=dup,
            jitter=jitter,
            loss=self.getparam("loss"),
            unidirectional=unidirectional,
        )
Beispiel #3
0
def add_link_data(
    link_proto: core_pb2.Link
) -> Tuple[InterfaceData, InterfaceData, LinkOptions, LinkTypes]:
    """
    Convert link proto to link interfaces and options data.

    :param link_proto: link  proto
    :return: link interfaces and options
    """
    iface1_data = link_iface(link_proto.iface1)
    iface2_data = link_iface(link_proto.iface2)
    link_type = LinkTypes(link_proto.type)
    options = LinkOptions()
    options_proto = link_proto.options
    if options_proto:
        options.delay = options_proto.delay
        options.bandwidth = options_proto.bandwidth
        options.loss = options_proto.loss
        options.dup = options_proto.dup
        options.jitter = options_proto.jitter
        options.mer = options_proto.mer
        options.burst = options_proto.burst
        options.mburst = options_proto.mburst
        options.unidirectional = options_proto.unidirectional
        options.key = options_proto.key
    return iface1_data, iface2_data, options, link_type
Beispiel #4
0
    def read_links(self) -> None:
        link_elements = self.scenario.find("links")
        if link_elements is None:
            return

        node_sets = set()
        for link_element in link_elements.iterchildren():
            node1_id = get_int(link_element, "node1")
            if node1_id is None:
                node1_id = get_int(link_element, "node_one")
            node2_id = get_int(link_element, "node2")
            if node2_id is None:
                node2_id = get_int(link_element, "node_two")
            node_set = frozenset((node1_id, node2_id))

            iface1_element = link_element.find("iface1")
            if iface1_element is None:
                iface1_element = link_element.find("interface_one")
            iface1_data = None
            if iface1_element is not None:
                iface1_data = create_iface_data(iface1_element)

            iface2_element = link_element.find("iface2")
            if iface2_element is None:
                iface2_element = link_element.find("interface_two")
            iface2_data = None
            if iface2_element is not None:
                iface2_data = create_iface_data(iface2_element)

            options_element = link_element.find("options")
            options = LinkOptions()
            if options_element is not None:
                options.bandwidth = get_int(options_element, "bandwidth")
                options.burst = get_int(options_element, "burst")
                options.delay = get_int(options_element, "delay")
                options.dup = get_int(options_element, "dup")
                options.mer = get_int(options_element, "mer")
                options.mburst = get_int(options_element, "mburst")
                options.jitter = get_int(options_element, "jitter")
                options.key = get_int(options_element, "key")
                options.loss = get_float(options_element, "loss")
                if options.loss is None:
                    options.loss = get_float(options_element, "per")
                options.unidirectional = get_int(options_element,
                                                 "unidirectional")
                options.buffer = get_int(options_element, "buffer")

            if options.unidirectional == 1 and node_set in node_sets:
                logging.info("updating link node1(%s) node2(%s)", node1_id,
                             node2_id)
                self.session.update_link(node1_id, node2_id, iface1_data.id,
                                         iface2_data.id, options)
            else:
                logging.info("adding link node1(%s) node2(%s)", node1_id,
                             node2_id)
                self.session.add_link(node1_id, node2_id, iface1_data,
                                      iface2_data, options)

            node_sets.add(node_set)
Beispiel #5
0
    def test_add_node_to_node_uni(self, session: Session,
                                  ip_prefixes: IpPrefixes):
        # given
        node1 = session.add_node(CoreNode)
        node2 = session.add_node(CoreNode)
        iface1_data = ip_prefixes.create_iface(node1)
        iface2_data = ip_prefixes.create_iface(node2)
        link_options1 = LinkOptions(
            delay=50,
            bandwidth=5000000,
            loss=25,
            dup=25,
            jitter=10,
            buffer=100,
            unidirectional=True,
        )
        link_options2 = LinkOptions(
            delay=51,
            bandwidth=5000001,
            loss=26,
            dup=26,
            jitter=11,
            buffer=101,
            unidirectional=True,
        )

        # when
        iface1, iface2 = session.add_link(node1.id, node2.id, iface1_data,
                                          iface2_data, link_options1)
        session.update_link(node2.id, node1.id, iface2_data.id, iface1_data.id,
                            link_options2)

        # then
        assert node1.get_iface(iface1_data.id)
        assert node2.get_iface(iface2_data.id)
        assert iface1 is not None
        assert iface2 is not None
        assert iface1.local_options == link_options1
        assert iface1.has_local_netem
        assert iface2.local_options == link_options2
        assert iface2.has_local_netem
Beispiel #6
0
    def test_update_ptp(self, session: Session, ip_prefixes: IpPrefixes):
        # given
        delay = 50
        bandwidth = 5000000
        loss = 25
        dup = 25
        jitter = 10
        buffer = 100
        node1 = session.add_node(CoreNode)
        node2 = session.add_node(CoreNode)
        iface1_data = ip_prefixes.create_iface(node1)
        iface2_data = ip_prefixes.create_iface(node2)
        session.add_link(node1.id, node2.id, iface1_data, iface2_data)
        iface1 = node1.get_iface(iface1_data.id)
        iface2 = node2.get_iface(iface2_data.id)
        assert iface1.getparam("delay") != delay
        assert iface1.getparam("bw") != bandwidth
        assert iface1.getparam("loss") != loss
        assert iface1.getparam("duplicate") != dup
        assert iface1.getparam("jitter") != jitter
        assert iface1.getparam("buffer") != buffer
        assert iface2.getparam("delay") != delay
        assert iface2.getparam("bw") != bandwidth
        assert iface2.getparam("loss") != loss
        assert iface2.getparam("duplicate") != dup
        assert iface2.getparam("jitter") != jitter
        assert iface2.getparam("buffer") != buffer

        # when
        options = LinkOptions(
            delay=delay,
            bandwidth=bandwidth,
            loss=loss,
            dup=dup,
            jitter=jitter,
            buffer=buffer,
        )
        session.update_link(node1.id, node2.id, iface1_data.id, iface2_data.id, options)

        # then
        assert iface1.getparam("delay") == delay
        assert iface1.getparam("bw") == bandwidth
        assert iface1.getparam("loss") == loss
        assert iface1.getparam("duplicate") == dup
        assert iface1.getparam("jitter") == jitter
        assert iface1.getparam("buffer") == buffer
        assert iface2.getparam("delay") == delay
        assert iface2.getparam("bw") == bandwidth
        assert iface2.getparam("loss") == loss
        assert iface2.getparam("duplicate") == dup
        assert iface2.getparam("jitter") == jitter
        assert iface2.getparam("buffer") == buffer
Beispiel #7
0
 def setlinkparams(self) -> None:
     """
     Apply link parameters to all interfaces. This is invoked from
     WlanNode.setmodel() after the position callback has been set.
     """
     with self.iface_lock:
         for iface in self.iface_to_pos:
             options = LinkOptions(
                 bandwidth=self.bw,
                 delay=self.delay,
                 loss=self.loss,
                 jitter=self.jitter,
             )
             iface.config(options)
Beispiel #8
0
    def test_clear_net_to_net(self, session: Session, ip_prefixes: IpPrefixes):
        # given
        node1 = session.add_node(SwitchNode)
        node2 = session.add_node(SwitchNode)
        iface1, _ = session.add_link(node1.id, node2.id, options=LINK_OPTIONS)
        assert iface1.local_options == LINK_OPTIONS
        assert iface1.has_local_netem
        assert iface1.options == LINK_OPTIONS
        assert iface1.has_netem

        # when
        options = LinkOptions(delay=0,
                              bandwidth=0,
                              loss=0.0,
                              dup=0,
                              jitter=0,
                              buffer=0)
        session.update_link(node1.id, node2.id, options=options)

        # then
        assert iface1.local_options.is_clear()
        assert not iface1.has_local_netem
        assert iface1.options.is_clear()
        assert not iface1.has_netem
Beispiel #9
0
        "range": "280",
        "bandwidth": "55000000",
        "delay": "100",
        "error": 0,
        "jitter": 0
    },
)

# link nodes to wlan
iface1 = ip_prefixes.create_iface(n1)
session.add_link(n1.id, wlan.id, iface1)

iface2 = ip_prefixes.create_iface(n2)
session.add_link(n2.id, wlan.id, iface2)

options = LinkOptions(delay=100,
                      bandwidth=50_000_000,
                      dup=5,
                      loss=5.5,
                      jitter=0)

#iface1 = ip_prefixes.create_iface(n1)
#iface2 = ip_prefixes.create_iface(n2)

#print("Iface1", iface1.ip4)
#print("Iface2", iface2.ip4)

#session.add_link(n1.id, n2.id, iface1, iface2)


def writeConfig(n):  #
    n.cmd(shell=True, args="mkdir -p /etc/quagga/")
Beispiel #10
0
    def test_link_options_bidirectional(self, session: Session,
                                        tmpdir: TemporaryFile,
                                        ip_prefixes: IpPrefixes):
        """
        Test xml client methods for a ptp network.

        :param session: session for test
        :param tmpdir: tmpdir to create data in
        :param ip_prefixes: generates ip addresses for nodes
        """
        # create nodes
        node1 = session.add_node(CoreNode)
        iface1_data = ip_prefixes.create_iface(node1)
        node2 = session.add_node(CoreNode)
        iface2_data = ip_prefixes.create_iface(node2)

        # create link
        options1 = LinkOptions()
        options1.unidirectional = 1
        options1.bandwidth = 5000
        options1.delay = 10
        options1.loss = 10.5
        options1.dup = 5
        options1.jitter = 5
        options1.buffer = 50
        session.add_link(node1.id, node2.id, iface1_data, iface2_data,
                         options1)
        options2 = LinkOptions()
        options2.unidirectional = 1
        options2.bandwidth = 10000
        options2.delay = 20
        options2.loss = 10
        options2.dup = 10
        options2.jitter = 10
        options2.buffer = 100
        session.update_link(node2.id, node1.id, iface2_data.id, iface1_data.id,
                            options2)

        # instantiate session
        session.instantiate()

        # get ids for nodes
        node1_id = node1.id
        node2_id = node2.id

        # save xml
        xml_file = tmpdir.join("session.xml")
        file_path = Path(xml_file.strpath)
        session.save_xml(file_path)

        # verify xml file was created and can be parsed
        assert xml_file.isfile()
        assert ElementTree.parse(file_path)

        # stop current session, clearing data
        session.shutdown()

        # verify nodes have been removed from session
        with pytest.raises(CoreError):
            assert not session.get_node(node1_id, CoreNode)
        with pytest.raises(CoreError):
            assert not session.get_node(node2_id, CoreNode)

        # load saved xml
        session.open_xml(file_path, start=True)

        # verify nodes have been recreated
        assert session.get_node(node1_id, CoreNode)
        assert session.get_node(node2_id, CoreNode)
        links = []
        for node_id in session.nodes:
            node = session.nodes[node_id]
            links += node.links()
        assert len(links) == 2
        link1 = links[0]
        link2 = links[1]
        assert options1.bandwidth == link1.options.bandwidth
        assert options1.delay == link1.options.delay
        assert options1.loss == link1.options.loss
        assert options1.dup == link1.options.dup
        assert options1.jitter == link1.options.jitter
        assert options1.buffer == link1.options.buffer
        assert options2.bandwidth == link2.options.bandwidth
        assert options2.delay == link2.options.delay
        assert options2.loss == link2.options.loss
        assert options2.dup == link2.options.dup
        assert options2.jitter == link2.options.jitter
        assert options2.buffer == link2.options.buffer
Beispiel #11
0
def main():

    parser = argparse.ArgumentParser()
    parser.add_argument('--is_virtual',
                        dest='is_virtual',
                        help='with Kronos',
                        default="False")

    args = parser.parse_args()

    if args.is_virtual == "True":
        is_virtual = True
    else:
        is_virtual = False

    # Kronos specific parameters
    total_num_dilated_executables = 6  # (2 plcs + 2 communication modules + 2 hmis )
    run_time_secs = 5
    rel_cpu_speed = 1.0
    num_insns_per_round = 1000000

    plc_spec_directory = os.path.dirname(os.path.realpath(__file__))
    plc1_spec_file = f"{plc_spec_directory}/plc1_system_specification.prototxt"
    plc2_spec_file = f"{plc_spec_directory}/plc2_system_specification.prototxt"

    NUM_PLCS = 2
    NUM_HMIS = 2

    # ip generator for example
    prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")

    # create emulator instance for creating sessions and utility methods
    coreemu = CoreEmu()
    session = coreemu.create_session()

    # must be in configuration state for nodes to start, when using "node_add" below
    session.set_state(EventTypes.CONFIGURATION_STATE)

    # create switch network node
    switch = session.add_node(SwitchNode, _id=100)

    # create nodes
    for _ in range(NUM_PLCS + NUM_HMIS):
        node = session.add_node(CoreNode)
        interface = prefixes.create_iface(node)
        session.add_link(node.id,
                         switch.id,
                         iface1_data=interface,
                         options=LinkOptions(delay=1000))  # delay in us

    # instantiate session
    session.instantiate()

    node_ifaces = []

    # get nodes to run example
    plc1_node = session.get_node(1, CoreNode)
    node_ifaces.extend(
        [x.localname for x in plc1_node.get_ifaces(control=False)])

    plc2_node = session.get_node(2, CoreNode)
    node_ifaces.extend(
        [x.localname for x in plc2_node.get_ifaces(control=False)])

    hmi1_node = session.get_node(3, CoreNode)
    node_ifaces.extend(
        [x.localname for x in hmi1_node.get_ifaces(control=False)])

    hmi2_node = session.get_node(4, CoreNode)
    node_ifaces.extend(
        [x.localname for x in hmi2_node.get_ifaces(control=False)])

    print("node-ifaces ", node_ifaces)
    plc1_ip_address = prefixes.ip4_address(plc1_node.id)
    plc2_ip_address = prefixes.ip4_address(plc2_node.id)

    print(f"PLC-1 IP: {plc1_ip_address}, PLC-2 IP: {plc2_ip_address}")

    # Clear any existing log files
    if os.path.exists("/tmp/pc_grpc_server_log.txt"):
        os.remove("/tmp/pc_grpc_server_log.txt")
    if os.path.exists("/tmp/plc1_log.txt"):
        os.remove("/tmp/plc1_log.txt")
    if os.path.exists("/tmp/plc2_log.txt"):
        os.remove("/tmp/plc2_log.txt")
    if os.path.exists("/tmp/comm_module1_log.txt"):
        os.remove("/tmp/comm_module1_log.txt")
    if os.path.exists("/tmp/comm_module2_log.txt"):
        os.remove("/tmp/comm_module2_log.txt")
    if os.path.exists("/tmp/hmi1.txt"):
        os.remove("/tmp/hmi1.txt")
    if os.path.exists("/tmp/hmi2.txt"):
        os.remove("/tmp/hmi2.txt")

    fd1 = os.open("/tmp/pc_grpc_server_log.txt", os.O_RDWR | os.O_CREAT)

    pendulum_sim = PendulumSystemSimulator()
    if args.is_virtual == "True":
        is_virtual = True
    else:
        is_virtual = False

    # Create an emulation driver. Register pendulum system simulator with it.
    emulation = EmulationDriver(
        number_dilated_nodes=total_num_dilated_executables,
        is_virtual=is_virtual,
        n_insns_per_round=num_insns_per_round,
        rel_cpu_speed=rel_cpu_speed,
        physical_system_sim_driver=pendulum_sim)

    # Start pc_grpc_server, all PLCs and all communication modules here
    emulation.start_grpc_server(plc_spec_directory, fd1)

    if is_virtual:
        emulation.add_interfaces_to_vt_control(node_ifaces)

    # Retrieve command strings to run PLCs/HMIs/Communication Modules
    plc1_cmd = emulation.get_plc_exec_command(
        path_to_plc_specification_file=plc1_spec_file,
        log_file_path="/tmp/plc1_log.txt")
    plc2_cmd = emulation.get_plc_exec_command(
        path_to_plc_specification_file=plc2_spec_file,
        log_file_path="/tmp/plc2_log.txt")

    comm_module1_cmd = emulation.wrap_command(
        get_comm_module_start_command(plc1_spec_file, plc1_ip_address,
                                      "/tmp/comm_module1_log.txt"))
    comm_module2_cmd = emulation.wrap_command(
        get_comm_module_start_command(plc2_spec_file, plc2_ip_address,
                                      "/tmp/comm_module2_log.txt"))

    hmi1_cmd = emulation.wrap_command(
        get_example_hmi_start_command(plc1_ip_address, "/tmp/hmi1.txt"))
    hmi2_cmd = emulation.wrap_command(
        get_example_hmi_start_command(plc2_ip_address, "/tmp/hmi2.txt"))

    print("Starting PLCs ...")
    plc1_node.cmd(plc1_cmd, wait=False)
    plc2_node.cmd(plc2_cmd, wait=False)
    print("Starting PLC Modbus Comm modules ...")
    plc1_node.cmd(comm_module1_cmd, wait=False)
    plc2_node.cmd(comm_module2_cmd, wait=False)
    print("Starting HMI ...")
    hmi1_node.cmd(hmi1_cmd, wait=False)
    hmi2_node.cmd(hmi2_cmd, wait=False)

    # Wait until all processes have started and registered themselves
    emulation.wait_for_initialization()

    # Register an interrupt signal handler.
    signal.signal(signal.SIGINT, handler)

    total_time_elapsed = 0.0
    while total_time_elapsed <= run_time_secs:

        emulation.run_for(0.01)
        total_time_elapsed += 0.01
        if is_virtual:
            print("Time Elapsed: ", total_time_elapsed)
        if stop == True:
            break

    print("Stopping Emulation ...")
    sys.stdout.flush()
    emulation.stop_exp()

    os.close(fd1)

    # shutdown session
    coreemu.shutdown()

    print("Emulation finished ! ")
Beispiel #12
0
from typing import Tuple

import pytest

from core.emulator.data import IpPrefixes, LinkOptions
from core.emulator.session import Session
from core.errors import CoreError
from core.nodes.base import CoreNode
from core.nodes.network import SwitchNode

INVALID_ID: int = 100
LINK_OPTIONS: LinkOptions = LinkOptions(delay=50,
                                        bandwidth=5000000,
                                        loss=25,
                                        dup=25,
                                        jitter=10,
                                        buffer=100)


def create_ptp_network(session: Session,
                       ip_prefixes: IpPrefixes) -> Tuple[CoreNode, CoreNode]:
    # create nodes
    node1 = session.add_node(CoreNode)
    node2 = session.add_node(CoreNode)

    # link nodes to net node
    iface1_data = ip_prefixes.create_iface(node1)
    iface2_data = ip_prefixes.create_iface(node2)
    session.add_link(node1.id, node2.id, iface1_data, iface2_data)

    # instantiate session
Beispiel #13
0
    def test_link_options(self, session: Session, tmpdir: TemporaryFile,
                          ip_prefixes: IpPrefixes):
        """
        Test xml client methods for a ptp network.

        :param session: session for test
        :param tmpdir: tmpdir to create data in
        :param ip_prefixes: generates ip addresses for nodes
        """
        # create nodes
        node1 = session.add_node(CoreNode)
        iface1_data = ip_prefixes.create_iface(node1)
        switch = session.add_node(SwitchNode)

        # create link
        options = LinkOptions()
        options.loss = 10.5
        options.bandwidth = 50000
        options.jitter = 10
        options.delay = 30
        options.dup = 5
        session.add_link(node1.id, switch.id, iface1_data, options=options)

        # instantiate session
        session.instantiate()

        # get ids for nodes
        node1_id = node1.id
        node2_id = switch.id

        # save xml
        xml_file = tmpdir.join("session.xml")
        file_path = xml_file.strpath
        session.save_xml(file_path)

        # verify xml file was created and can be parsed
        assert xml_file.isfile()
        assert ElementTree.parse(file_path)

        # stop current session, clearing data
        session.shutdown()

        # verify nodes have been removed from session
        with pytest.raises(CoreError):
            assert not session.get_node(node1_id, CoreNode)
        with pytest.raises(CoreError):
            assert not session.get_node(node2_id, SwitchNode)

        # load saved xml
        session.open_xml(file_path, start=True)

        # verify nodes have been recreated
        assert session.get_node(node1_id, CoreNode)
        assert session.get_node(node2_id, SwitchNode)
        links = []
        for node_id in session.nodes:
            node = session.nodes[node_id]
            links += node.links()
        link = links[0]
        assert options.loss == link.options.loss
        assert options.bandwidth == link.options.bandwidth
        assert options.jitter == link.options.jitter
        assert options.delay == link.options.delay
        assert options.dup == link.options.dup