#2139 - Fixed unicast and broadcast functionality properly
This commit is contained in:
@@ -274,11 +274,20 @@ class NIC(SimComponent):
|
||||
|
||||
def receive_frame(self, frame: Frame) -> bool:
|
||||
"""
|
||||
Receive a network frame from the connected link if the NIC is enabled.
|
||||
Receive a network frame from the connected link, processing it if the NIC is enabled.
|
||||
|
||||
The Frame is passed to the Node.
|
||||
This method decrements the Time To Live (TTL) of the frame, captures it using PCAP (Packet Capture), and checks
|
||||
if the frame is either a broadcast or destined for this NIC. If the frame is acceptable, it is passed to the
|
||||
connected node. The method also handles the discarding of frames with TTL expired and logs this event.
|
||||
|
||||
:param frame: The network frame being received.
|
||||
The frame's reception is based on various conditions:
|
||||
- If the NIC is disabled, the frame is not processed.
|
||||
- If the TTL of the frame reaches zero after decrement, it is discarded and logged.
|
||||
- If the frame is a broadcast or its destination MAC/IP address matches this NIC's, it is accepted.
|
||||
- All other frames are dropped and logged or printed to the console.
|
||||
|
||||
:param frame: The network frame being received. This should be an instance of the Frame class.
|
||||
:return: Returns True if the frame is processed and passed to the node, False otherwise.
|
||||
"""
|
||||
if self.enabled:
|
||||
frame.decrement_ttl()
|
||||
@@ -288,7 +297,17 @@ class NIC(SimComponent):
|
||||
frame.set_received_timestamp()
|
||||
self.pcap.capture(frame)
|
||||
# If this destination or is broadcast
|
||||
if frame.ethernet.dst_mac_addr == self.mac_address or frame.ethernet.dst_mac_addr == "ff:ff:ff:ff:ff:ff":
|
||||
accept_frame = False
|
||||
|
||||
# Check if it's a broadcast:
|
||||
if frame.ethernet.dst_mac_addr == "ff:ff:ff:ff:ff:ff":
|
||||
if frame.ip.dst_ip_address in {self.ip_address, self.ip_network.broadcast_address}:
|
||||
accept_frame = True
|
||||
else:
|
||||
if frame.ethernet.dst_mac_addr == self.mac_address:
|
||||
accept_frame = True
|
||||
|
||||
if accept_frame:
|
||||
self._connected_node.receive_frame(frame=frame, from_nic=self)
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -690,6 +690,47 @@ class RouterICMP(ICMP):
|
||||
self.router.process_frame(frame, from_nic)
|
||||
|
||||
|
||||
class RouterNIC(NIC):
|
||||
"""
|
||||
A Router-specific Network Interface Card (NIC) that extends the standard NIC functionality.
|
||||
|
||||
This class overrides the standard Node NIC's Layer 3 (L3) broadcast/unicast checks. It is designed
|
||||
to handle network frames in a manner specific to routers, allowing them to efficiently process
|
||||
and route network traffic.
|
||||
"""
|
||||
|
||||
def receive_frame(self, frame: Frame) -> bool:
|
||||
"""
|
||||
Receive and process a network frame from the connected link, provided the NIC is enabled.
|
||||
|
||||
This method is tailored for router behavior. It decrements the frame's Time To Live (TTL), checks for TTL
|
||||
expiration, and captures the frame using PCAP (Packet Capture). The frame is accepted if it is destined for
|
||||
this NIC's MAC address or is a broadcast frame.
|
||||
|
||||
Key Differences from Standard NIC:
|
||||
- Does not perform Layer 3 (IP-based) broadcast checks.
|
||||
- Only checks for Layer 2 (Ethernet) destination MAC address and broadcast frames.
|
||||
|
||||
:param frame: The network frame being received. This should be an instance of the Frame class.
|
||||
:return: Returns True if the frame is processed and passed to the connected node, False otherwise.
|
||||
"""
|
||||
if self.enabled:
|
||||
frame.decrement_ttl()
|
||||
if frame.ip and frame.ip.ttl < 1:
|
||||
self._connected_node.sys_log.info("Frame discarded as TTL limit reached")
|
||||
return False
|
||||
frame.set_received_timestamp()
|
||||
self.pcap.capture(frame)
|
||||
# If this destination or is broadcast
|
||||
if frame.ethernet.dst_mac_addr == self.mac_address or frame.ethernet.dst_mac_addr == "ff:ff:ff:ff:ff:ff":
|
||||
self._connected_node.receive_frame(frame=frame, from_nic=self)
|
||||
return True
|
||||
return False
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.mac_address}/{self.ip_address}"
|
||||
|
||||
|
||||
class Router(Node):
|
||||
"""
|
||||
A class to represent a network router node.
|
||||
@@ -700,7 +741,7 @@ class Router(Node):
|
||||
"""
|
||||
|
||||
num_ports: int
|
||||
ethernet_ports: Dict[int, NIC] = {}
|
||||
ethernet_ports: Dict[int, RouterNIC] = {}
|
||||
acl: AccessControlList
|
||||
route_table: RouteTable
|
||||
arp: RouterARPCache
|
||||
@@ -719,7 +760,7 @@ class Router(Node):
|
||||
kwargs["icmp"] = RouterICMP(sys_log=kwargs.get("sys_log"), arp_cache=kwargs.get("arp"), router=self)
|
||||
super().__init__(hostname=hostname, num_ports=num_ports, **kwargs)
|
||||
for i in range(1, self.num_ports + 1):
|
||||
nic = NIC(ip_address="127.0.0.1", subnet_mask="255.0.0.0", gateway="0.0.0.0")
|
||||
nic = RouterNIC(ip_address="127.0.0.1", subnet_mask="255.0.0.0", gateway="0.0.0.0")
|
||||
self.connect_nic(nic)
|
||||
self.ethernet_ports[i] = nic
|
||||
|
||||
|
||||
Reference in New Issue
Block a user