149 lines
6.5 KiB
Python
149 lines
6.5 KiB
Python
from ipaddress import IPv4Address
|
|
from typing import Optional
|
|
|
|
from primaite.simulator.network.container import Network
|
|
from primaite.simulator.network.hardware.nodes.host.computer import Computer
|
|
from primaite.simulator.network.hardware.nodes.network.router import ACLAction, Router
|
|
from primaite.simulator.network.hardware.nodes.network.switch import Switch
|
|
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
|
from primaite.simulator.network.transmission.transport_layer import Port
|
|
|
|
|
|
def num_of_switches_required(num_nodes: int, max_switch_ports: int = 24) -> int:
|
|
"""
|
|
Calculate the minimum number of network switches required to connect a given number of nodes.
|
|
|
|
Each switch is assumed to have one port reserved for connecting to a router, reducing the effective
|
|
number of ports available for PCs. The function calculates the total number of switches needed
|
|
to accommodate all nodes under this constraint.
|
|
|
|
:param num_nodes: The total number of nodes that need to be connected in the network.
|
|
:param max_switch_ports: The maximum number of ports available on each switch. Defaults to 24.
|
|
|
|
:return: The minimum number of switches required to connect all PCs.
|
|
|
|
Example:
|
|
>>> num_of_switches_required(5)
|
|
1
|
|
>>> num_of_switches_required(24,24)
|
|
2
|
|
>>> num_of_switches_required(48,24)
|
|
3
|
|
>>> num_of_switches_required(25,10)
|
|
3
|
|
"""
|
|
# Reduce the effective number of switch ports by 1 to leave space for the router
|
|
effective_switch_ports = max_switch_ports - 1
|
|
|
|
# Calculate the number of fully utilised switches and any additional switch for remaining PCs
|
|
full_switches = num_nodes // effective_switch_ports
|
|
extra_pcs = num_nodes % effective_switch_ports
|
|
|
|
# Return the total number of switches required
|
|
return full_switches + (1 if extra_pcs > 0 else 0)
|
|
|
|
|
|
def create_office_lan(
|
|
lan_name: str,
|
|
subnet_base: int,
|
|
pcs_ip_block_start: int,
|
|
num_pcs: int,
|
|
network: Optional[Network] = None,
|
|
include_router: bool = True,
|
|
) -> Network:
|
|
"""
|
|
Creates a 2-Tier or 3-Tier office local area network (LAN).
|
|
|
|
The LAN is configured with a specified number of personal computers (PCs), optionally including a router,
|
|
and multiple edge switches to connect them. A core switch is added only if more than one edge switch is required.
|
|
The network topology involves edge switches connected either directly to the router in a 2-Tier setup or
|
|
to a core switch in a 3-Tier setup. If a router is included, it is connected to the core switch (if present)
|
|
and configured with basic access control list (ACL) rules. PCs are distributed across the edge switches.
|
|
|
|
|
|
:param str lan_name: The name to be assigned to the LAN.
|
|
:param int subnet_base: The subnet base number to be used in the IP addresses.
|
|
:param int pcs_ip_block_start: The starting block for assigning IP addresses to PCs.
|
|
:param int num_pcs: The number of PCs to be added to the LAN.
|
|
:param Optional[Network] network: The network to which the LAN components will be added. If None, a new network is
|
|
created.
|
|
:param bool include_router: Flag to determine if a router should be included in the LAN. Defaults to True.
|
|
:return: The network object with the LAN components added.
|
|
:raises ValueError: If pcs_ip_block_start is less than or equal to the number of required switches.
|
|
"""
|
|
# Initialise the network if not provided
|
|
if not network:
|
|
network = Network()
|
|
|
|
# Calculate the required number of switches
|
|
num_of_switches = num_of_switches_required(num_nodes=num_pcs)
|
|
effective_switch_ports = 23 # One port less for router connection
|
|
if pcs_ip_block_start <= num_of_switches:
|
|
raise ValueError(f"pcs_ip_block_start must be greater than the number of required switches {num_of_switches}")
|
|
|
|
# Create a core switch if more than one edge switch is needed
|
|
if num_of_switches > 1:
|
|
core_switch = Switch(hostname=f"switch_core_{lan_name}", start_up_duration=0)
|
|
core_switch.power_on()
|
|
network.add_node(core_switch)
|
|
core_switch_port = 1
|
|
|
|
# Initialise the default gateway to None
|
|
default_gateway = None
|
|
|
|
# Optionally include a router in the LAN
|
|
if include_router:
|
|
default_gateway = IPv4Address(f"192.168.{subnet_base}.1")
|
|
router = Router(hostname=f"router_{lan_name}", start_up_duration=0)
|
|
router.power_on()
|
|
router.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.ARP, dst_port=Port.ARP, position=22)
|
|
router.acl.add_rule(action=ACLAction.PERMIT, protocol=IPProtocol.ICMP, position=23)
|
|
network.add_node(router)
|
|
router.configure_port(port=1, ip_address=default_gateway, subnet_mask="255.255.255.0")
|
|
router.enable_port(1)
|
|
|
|
# Initialise the first edge switch and connect to the router or core switch
|
|
switch_port = 0
|
|
switch_n = 1
|
|
switch = Switch(hostname=f"switch_edge_{switch_n}_{lan_name}", start_up_duration=0)
|
|
switch.power_on()
|
|
network.add_node(switch)
|
|
if num_of_switches > 1:
|
|
network.connect(core_switch.network_interface[core_switch_port], switch.network_interface[24])
|
|
else:
|
|
network.connect(router.network_interface[1], switch.network_interface[24])
|
|
|
|
# Add PCs to the LAN and connect them to switches
|
|
for i in range(1, num_pcs + 1):
|
|
# Add a new edge switch if the current one is full
|
|
if switch_port == effective_switch_ports:
|
|
switch_n += 1
|
|
switch_port = 0
|
|
switch = Switch(hostname=f"switch_edge_{switch_n}_{lan_name}", start_up_duration=0)
|
|
switch.power_on()
|
|
network.add_node(switch)
|
|
# Connect the new switch to the router or core switch
|
|
if num_of_switches > 1:
|
|
core_switch_port += 1
|
|
network.connect(core_switch.network_interface[core_switch_port], switch.network_interface[24])
|
|
else:
|
|
network.connect(router.network_interface[1], switch.network_interface[24])
|
|
|
|
# Create and add a PC to the network
|
|
pc = Computer(
|
|
hostname=f"pc_{i}_{lan_name}",
|
|
ip_address=f"192.168.{subnet_base}.{i+pcs_ip_block_start-1}",
|
|
subnet_mask="255.255.255.0",
|
|
default_gateway=default_gateway,
|
|
start_up_duration=0,
|
|
)
|
|
pc.power_on()
|
|
network.add_node(pc)
|
|
|
|
# Connect the PC to the switch
|
|
switch_port += 1
|
|
network.connect(switch.network_interface[switch_port], pc.network_interface[1])
|
|
switch.network_interface[switch_port].enable()
|
|
|
|
return network
|