#2519 - refactored all air-space usage to that a new instance of AirSpace is created for each instance of Network. This 1:1 relationship between network and airspace will allow parallelization. Added additional WirelessRouter test that tests wireless connectivity from config file too.
This commit is contained in:
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from enum import Enum
|
||||
from typing import Any, Dict, Final, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from prettytable import PrettyTable
|
||||
|
||||
@@ -14,7 +14,7 @@ from primaite.simulator.system.core.packet_capture import PacketCapture
|
||||
|
||||
_LOGGER = getLogger(__name__)
|
||||
|
||||
__all__ = ["AIR_SPACE", "AirSpaceFrequency", "WirelessNetworkInterface", "IPWirelessNetworkInterface"]
|
||||
__all__ = ["AirSpaceFrequency", "WirelessNetworkInterface", "IPWirelessNetworkInterface"]
|
||||
|
||||
|
||||
class AirSpace:
|
||||
@@ -100,18 +100,6 @@ class AirSpace:
|
||||
wireless_interface.receive_frame(frame)
|
||||
|
||||
|
||||
AIR_SPACE: Final[AirSpace] = AirSpace()
|
||||
"""
|
||||
A singleton instance of the AirSpace class, representing the global wireless airspace.
|
||||
|
||||
This instance acts as the central management point for all wireless communications within the simulated network
|
||||
environment. By default, there is only one airspace in the simulation, making this variable a singleton that
|
||||
manages the registration, removal, and transmission of wireless frames across all wireless network interfaces configured
|
||||
in the simulation. It ensures that wireless frames are appropriately transmitted to and received by wireless
|
||||
interfaces based on their operational status and frequency band.
|
||||
"""
|
||||
|
||||
|
||||
class AirSpaceFrequency(Enum):
|
||||
"""Enumeration representing the operating frequencies for wireless communications."""
|
||||
|
||||
@@ -149,6 +137,7 @@ class WirelessNetworkInterface(NetworkInterface, ABC):
|
||||
and may define additional properties and methods specific to wireless technology.
|
||||
"""
|
||||
|
||||
airspace: AirSpace
|
||||
frequency: AirSpaceFrequency = AirSpaceFrequency.WIFI_2_4
|
||||
|
||||
def enable(self):
|
||||
@@ -171,7 +160,7 @@ class WirelessNetworkInterface(NetworkInterface, ABC):
|
||||
self.pcap = PacketCapture(
|
||||
hostname=self._connected_node.hostname, port_num=self.port_num, port_name=self.port_name
|
||||
)
|
||||
AIR_SPACE.add_wireless_interface(self)
|
||||
self.airspace.add_wireless_interface(self)
|
||||
|
||||
def disable(self):
|
||||
"""Disable the network interface."""
|
||||
@@ -182,7 +171,7 @@ class WirelessNetworkInterface(NetworkInterface, ABC):
|
||||
self._connected_node.sys_log.info(f"Network Interface {self} disabled")
|
||||
else:
|
||||
_LOGGER.debug(f"Interface {self} disabled")
|
||||
AIR_SPACE.remove_wireless_interface(self)
|
||||
self.airspace.remove_wireless_interface(self)
|
||||
|
||||
def send_frame(self, frame: Frame) -> bool:
|
||||
"""
|
||||
@@ -198,7 +187,7 @@ class WirelessNetworkInterface(NetworkInterface, ABC):
|
||||
if self.enabled:
|
||||
frame.set_sent_timestamp()
|
||||
self.pcap.capture_outbound(frame)
|
||||
AIR_SPACE.transmit(frame, self)
|
||||
self.airspace.transmit(frame, self)
|
||||
return True
|
||||
# Cannot send Frame as the network interface is not enabled
|
||||
return False
|
||||
|
||||
@@ -5,9 +5,11 @@ import matplotlib.pyplot as plt
|
||||
import networkx as nx
|
||||
from networkx import MultiGraph
|
||||
from prettytable import MARKDOWN, PrettyTable
|
||||
from pydantic import Field
|
||||
|
||||
from primaite import getLogger
|
||||
from primaite.simulator.core import RequestManager, RequestType, SimComponent
|
||||
from primaite.simulator.network.airspace import AirSpace
|
||||
from primaite.simulator.network.hardware.base import Link, Node, WiredNetworkInterface
|
||||
from primaite.simulator.network.hardware.nodes.host.server import Printer
|
||||
from primaite.simulator.system.applications.application import Application
|
||||
@@ -28,7 +30,9 @@ class Network(SimComponent):
|
||||
"""
|
||||
|
||||
nodes: Dict[str, Node] = {}
|
||||
|
||||
links: Dict[str, Link] = {}
|
||||
airspace: AirSpace = Field(default_factory=lambda: AirSpace())
|
||||
_node_id_map: Dict[int, Node] = {}
|
||||
_link_id_map: Dict[int, Node] = {}
|
||||
|
||||
|
||||
@@ -1546,7 +1546,7 @@ class Router(NetworkNode):
|
||||
print(table)
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, cfg: dict) -> "Router":
|
||||
def from_config(cls, cfg: dict, **kwargs) -> "Router":
|
||||
"""Create a router based on a config dict.
|
||||
|
||||
Schema:
|
||||
|
||||
@@ -3,7 +3,7 @@ from typing import Any, Dict, Union
|
||||
|
||||
from pydantic import validate_call
|
||||
|
||||
from primaite.simulator.network.airspace import AirSpaceFrequency, IPWirelessNetworkInterface
|
||||
from primaite.simulator.network.airspace import AirSpace, AirSpaceFrequency, IPWirelessNetworkInterface
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.network.router import ACLAction, Router, RouterInterface
|
||||
from primaite.simulator.network.transmission.data_link_layer import Frame
|
||||
@@ -121,11 +121,14 @@ class WirelessRouter(Router):
|
||||
|
||||
network_interfaces: Dict[str, Union[RouterInterface, WirelessAccessPoint]] = {}
|
||||
network_interface: Dict[int, Union[RouterInterface, WirelessAccessPoint]] = {}
|
||||
airspace: AirSpace
|
||||
|
||||
def __init__(self, hostname: str, **kwargs):
|
||||
super().__init__(hostname=hostname, num_ports=0, **kwargs)
|
||||
def __init__(self, hostname: str, airspace: AirSpace, **kwargs):
|
||||
super().__init__(hostname=hostname, num_ports=0, airspace=airspace, **kwargs)
|
||||
|
||||
self.connect_nic(WirelessAccessPoint(ip_address="127.0.0.1", subnet_mask="255.0.0.0", gateway="0.0.0.0"))
|
||||
self.connect_nic(
|
||||
WirelessAccessPoint(ip_address="127.0.0.1", subnet_mask="255.0.0.0", gateway="0.0.0.0", airspace=airspace)
|
||||
)
|
||||
|
||||
self.connect_nic(RouterInterface(ip_address="127.0.0.1", subnet_mask="255.0.0.0", gateway="0.0.0.0"))
|
||||
|
||||
@@ -215,7 +218,7 @@ class WirelessRouter(Router):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, cfg: Dict) -> "WirelessRouter":
|
||||
def from_config(cls, cfg: Dict, **kwargs) -> "WirelessRouter":
|
||||
"""Generate the wireless router from config.
|
||||
|
||||
Schema:
|
||||
@@ -245,7 +248,7 @@ class WirelessRouter(Router):
|
||||
operating_state = (
|
||||
NodeOperatingState.ON if not (p := cfg.get("operating_state")) else NodeOperatingState[p.upper()]
|
||||
)
|
||||
router = cls(hostname=cfg["hostname"], operating_state=operating_state)
|
||||
router = cls(hostname=cfg["hostname"], operating_state=operating_state, airspace=kwargs["airspace"])
|
||||
if "router_interface" in cfg:
|
||||
ip_address = cfg["router_interface"]["ip_address"]
|
||||
subnet_mask = cfg["router_interface"]["subnet_mask"]
|
||||
|
||||
Reference in New Issue
Block a user