diff --git a/src/primaite/game/game.py b/src/primaite/game/game.py index 691ac2a1..c8fbac4e 100644 --- a/src/primaite/game/game.py +++ b/src/primaite/game/game.py @@ -329,7 +329,7 @@ class PrimaiteGame: elif n_type.lower() in Node._registry: new_node = HostNode._registry[n_type]( hostname=node_cfg["hostname"], - ip_address=node_cfg["ip_address"], + ip_address=node_cfg.get("ip_address"), subnet_mask=IPv4Address(node_cfg.get("subnet_mask", "255.255.255.0")), default_gateway=node_cfg.get("default_gateway"), dns_server=node_cfg.get("dns_server", None), diff --git a/src/primaite/simulator/network/airspace.py b/src/primaite/simulator/network/airspace.py index 2705c108..2b8503d6 100644 --- a/src/primaite/simulator/network/airspace.py +++ b/src/primaite/simulator/network/airspace.py @@ -137,14 +137,16 @@ class AirSpace(BaseModel): table.set_style(MARKDOWN) table.align = "l" table.title = "Airspace Frequency Channel Loads" - for frequency, load in self.bandwidth_load.items(): - maximum_capacity = self.get_frequency_max_capacity_mbps(frequency) - load_percent = load / maximum_capacity if maximum_capacity > 0 else 0.0 + for freq_name, freq_obj in self.frequencies.items(): + maximum_capacity = self.get_frequency_max_capacity_mbps(freq_name) + load_percent = ( + self.bandwidth_load.get(freq_obj.frequency_hz, 0.0) / maximum_capacity if maximum_capacity > 0 else 0.0 + ) if load_percent > 1.0: load_percent = 1.0 table.add_row( [ - format_hertz(self.frequencies[frequency].frequency_hz), + format_hertz(self.frequencies[freq_name].frequency_hz), f"{load_percent:.0%}", f"{maximum_capacity:.3f}", ] @@ -180,7 +182,7 @@ class AirSpace(BaseModel): interface.mac_address, interface.ip_address if hasattr(interface, "ip_address") else None, interface.subnet_mask if hasattr(interface, "subnet_mask") else None, - format_hertz(self.frequencies[interface.frequency].frequency_hz), + format_hertz(self.frequencies[interface.frequency.name].frequency_hz), f"{interface.speed:.3f}", status, ] @@ -253,11 +255,11 @@ class AirSpace(BaseModel): relevant frequency and its current bandwidth load. :return: True if the frame can be transmitted within the bandwidth limit, False if it would exceed the limit. """ - if sender_network_interface.frequency not in self.bandwidth_load: - self.bandwidth_load[sender_network_interface.frequency] = 0.0 + if sender_network_interface.frequency.frequency_hz not in self.bandwidth_load: + self.bandwidth_load[sender_network_interface.frequency.frequency_hz] = 0.0 return self.bandwidth_load[ - sender_network_interface.frequency - ] + frame.size_Mbits <= self.get_frequency_max_capacity_mbps(sender_network_interface.frequency) + sender_network_interface.frequency.frequency_hz + ] + frame.size_Mbits <= self.get_frequency_max_capacity_mbps(sender_network_interface.frequency.name) def transmit(self, frame: Frame, sender_network_interface: WirelessNetworkInterface): """ @@ -269,8 +271,10 @@ class AirSpace(BaseModel): :param sender_network_interface: The wireless network interface sending the frame. This interface will be excluded from the list of receivers to prevent it from receiving its own transmission. """ - self.bandwidth_load[sender_network_interface.frequency] += frame.size_Mbits - for wireless_interface in self.wireless_interfaces_by_frequency.get(sender_network_interface.frequency, []): + self.bandwidth_load[sender_network_interface.frequency.frequency_hz] += frame.size_Mbits + for wireless_interface in self.wireless_interfaces_by_frequency.get( + sender_network_interface.frequency.frequency_hz, [] + ): if wireless_interface != sender_network_interface and wireless_interface.enabled: wireless_interface.receive_frame(frame) @@ -428,7 +432,7 @@ class IPWirelessNetworkInterface(WirelessNetworkInterface, Layer3Interface, ABC) # Update the state with information from Layer3Interface state.update(Layer3Interface.describe_state(self)) - state["frequency"] = self.frequency + state["frequency"] = self.frequency.name return state diff --git a/src/primaite/simulator/network/creation.py b/src/primaite/simulator/network/creation.py index 8cc9a493..5d36f58b 100644 --- a/src/primaite/simulator/network/creation.py +++ b/src/primaite/simulator/network/creation.py @@ -1,7 +1,7 @@ # © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK from abc import ABC, abstractmethod from ipaddress import IPv4Address -from typing import Any, ClassVar, Dict, Literal, Self, Type +from typing import Any, ClassVar, Dict, Literal, Type from pydantic import BaseModel, model_validator @@ -117,7 +117,7 @@ class OfficeLANAdder(NetworkNodeAdder, identifier="office_lan"): """Data bandwidth to the LAN measured in Mbps.""" @model_validator(mode="after") - def check_ip_range(self) -> Self: + def check_ip_range(self) -> "OfficeLANAdder.ConfigSchema": """Make sure the ip addresses of hosts don't exceed the maximum possible ip address.""" if self.pcs_ip_block_start + self.num_pcs >= 254: raise ValueError( diff --git a/tests/integration_tests/extensions/test_extendable_config.py b/tests/integration_tests/extensions/test_extendable_config.py index 8467151b..5addcbd7 100644 --- a/tests/integration_tests/extensions/test_extendable_config.py +++ b/tests/integration_tests/extensions/test_extendable_config.py @@ -25,8 +25,8 @@ def test_extended_example_config(): assert len(network.router_nodes) == 1 # 1 router in network assert len(network.switch_nodes) == 1 # 1 switches in network assert len(network.server_nodes) == 5 # 5 servers in network - assert len(network.extended_hostnodes) == 1 # One extended node based on HostNode - assert len(network.extended_networknodes) == 1 # One extended node based on NetworkNode - assert "ExtendedApplication" in network.extended_hostnodes[0].software_manager.software - assert "ExtendedService" in network.extended_hostnodes[0].software_manager.software + extended_host = network.get_node_by_hostname("client_1") + + assert "ExtendedApplication" in extended_host.software_manager.software + assert "ExtendedService" in extended_host.software_manager.software