wip(rumpk): Phase 3.5 Live Wire - 95% Complete (TX Wire Issue)
- Implemented ping_ion.zig: Sovereign ARP/ICMP Responder - Fixed VirtIO header offset (10-byte skip) - Fixed packed struct size issues (hardcoded 14/28/20 byte headers) - Full data path working: RX -> NPL Parse -> TX Push -> Kernel Drain -> VirtIO Queue - Remaining: VirtIO TX packets not reaching wire (needs tcpdump debugging) - ARP Reply crafted correctly, ICMP Echo Reply crafted correctly - VirtIO notify called, but packets not observed by host
This commit is contained in:
parent
0aa8febe46
commit
bcba945557
|
|
@ -83,9 +83,14 @@ proc rumpk_yield_internal() {.cdecl, exportc.} =
|
||||||
return
|
return
|
||||||
elif load == 0:
|
elif load == 0:
|
||||||
# IDLE MODE (Phase 3): No pending commands.
|
# IDLE MODE (Phase 3): No pending commands.
|
||||||
# In a purely cooperative system, we don't WFI here to avoid hanging
|
# We must enable interrupts to receive packets!
|
||||||
# without a timer IRQ. The Watchdog will manage the sleep.
|
asm "csrsi sstatus, 2"
|
||||||
discard
|
# We can just yield here, interrupts will fire and preempt us (if we had preemption)
|
||||||
|
# or fire and return to here.
|
||||||
|
# But if we just loop, we burn CPU.
|
||||||
|
# Ideally: WFI.
|
||||||
|
# For now: Just enable interrupts so ISR can fire.
|
||||||
|
# asm "wfi" # Optional: Save power.
|
||||||
|
|
||||||
# Normal Round Robin logic
|
# Normal Round Robin logic
|
||||||
if current_fiber == addr fiber_ion:
|
if current_fiber == addr fiber_ion:
|
||||||
|
|
@ -100,17 +105,15 @@ proc rumpk_yield_internal() {.cdecl, exportc.} =
|
||||||
proc fiber_yield*() {.exportc, cdecl.} =
|
proc fiber_yield*() {.exportc, cdecl.} =
|
||||||
rumpk_yield_internal()
|
rumpk_yield_internal()
|
||||||
|
|
||||||
|
|
||||||
# Utility moved up
|
# Utility moved up
|
||||||
|
|
||||||
|
|
||||||
# Channel API (The Valve) - Wrappers for ION
|
# Channel API (The Valve) - Wrappers for ION
|
||||||
# Channel API is imported from ion.nim
|
# Channel API is imported from ion.nim
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# HAL/NPL Entry points
|
# HAL/NPL Entry points
|
||||||
proc rumpk_halt() {.importc, cdecl, noreturn.}
|
proc rumpk_halt() {.importc, cdecl, noreturn.}
|
||||||
proc hal_io_init() {.importc, cdecl.}
|
proc hal_io_init() {.importc, cdecl.}
|
||||||
|
|
@ -120,6 +123,7 @@ proc launch_subject() {.importc, cdecl.}
|
||||||
# Hardware Ingress (Zig -> Nim)
|
# Hardware Ingress (Zig -> Nim)
|
||||||
proc ion_ingress*(id: uint16, len: uint16) {.exportc, cdecl.} =
|
proc ion_ingress*(id: uint16, len: uint16) {.exportc, cdecl.} =
|
||||||
## Intercept raw hardware packet and push to Sovereign RX Channel
|
## Intercept raw hardware packet and push to Sovereign RX Channel
|
||||||
|
# kprint("[Kernel] Ingress ID: "); kprint_int(int(id)); kprint(" Len: "); kprint_int(int(len)); kprintln("")
|
||||||
let data = ion_get_virt(id)
|
let data = ion_get_virt(id)
|
||||||
var pkt = IonPacket(data: cast[ptr UncheckedArray[byte]](data), len: len, id: id)
|
var pkt = IonPacket(data: cast[ptr UncheckedArray[byte]](data), len: len, id: id)
|
||||||
chan_rx.send(pkt)
|
chan_rx.send(pkt)
|
||||||
|
|
@ -144,6 +148,11 @@ proc subject_fiber_entry() {.cdecl.} =
|
||||||
# Include Watchdog Logic (Access to Kernel Globals)
|
# Include Watchdog Logic (Access to Kernel Globals)
|
||||||
include watchdog
|
include watchdog
|
||||||
|
|
||||||
|
# HAL Driver API
|
||||||
|
proc virtio_net_poll() {.importc, cdecl.}
|
||||||
|
proc virtio_net_send(data: pointer, len: csize_t) {.importc, cdecl.}
|
||||||
|
proc ion_free_raw(id: uint16) {.importc, cdecl.}
|
||||||
|
|
||||||
proc ion_fiber_entry() {.cdecl.} =
|
proc ion_fiber_entry() {.cdecl.} =
|
||||||
kprint("[ION] Fiber 1 Reporting for Duty.")
|
kprint("[ION] Fiber 1 Reporting for Duty.")
|
||||||
if ion_paused: kprintln(" (PAUSED)") else: kprintln("")
|
if ion_paused: kprintln(" (PAUSED)") else: kprintln("")
|
||||||
|
|
@ -152,6 +161,9 @@ proc ion_fiber_entry() {.cdecl.} =
|
||||||
var cmd: CmdPacket
|
var cmd: CmdPacket
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
|
# 0. Poll Hardware (The Heartbeat)
|
||||||
|
virtio_net_poll()
|
||||||
|
|
||||||
# 1. Process Commands (Drain the ring!)
|
# 1. Process Commands (Drain the ring!)
|
||||||
while chan_cmd.recv(cmd):
|
while chan_cmd.recv(cmd):
|
||||||
if cmd.kind == uint32(CMD_ION_STOP):
|
if cmd.kind == uint32(CMD_ION_STOP):
|
||||||
|
|
@ -165,9 +177,14 @@ proc ion_fiber_entry() {.cdecl.} =
|
||||||
# 2. Process Data (if not paused, Drain the ring!)
|
# 2. Process Data (if not paused, Drain the ring!)
|
||||||
if not ion_paused:
|
if not ion_paused:
|
||||||
while chan_tx.recv(pkt):
|
while chan_tx.recv(pkt):
|
||||||
# High speed telemetry logic
|
# Transmit to Hardware
|
||||||
var alert = IonPacket(id: 777, len: 42)
|
kprint("[ION] TX from chan_tx, len=")
|
||||||
chan_event.send(alert)
|
# kprint_int(int(pkt.len))
|
||||||
|
kprintln("")
|
||||||
|
virtio_net_send(pkt.data, csize_t(pkt.len))
|
||||||
|
# Zero-Copy Ingest means we own the buffer now.
|
||||||
|
# Since virtio_net_send copies (for now), we must free the original slab.
|
||||||
|
ion_free_raw(pkt.id)
|
||||||
|
|
||||||
fiber_yield()
|
fiber_yield()
|
||||||
|
|
||||||
|
|
@ -234,6 +251,11 @@ proc kmain() {.exportc, cdecl.} =
|
||||||
# 4. WATCHDOG FIBER (The Immune System)
|
# 4. WATCHDOG FIBER (The Immune System)
|
||||||
init_fiber(addr fiber_watchdog, watchdog_loop, addr stack_watchdog[0], sizeof(stack_watchdog))
|
init_fiber(addr fiber_watchdog, watchdog_loop, addr stack_watchdog[0], sizeof(stack_watchdog))
|
||||||
|
|
||||||
|
# [FIX] GLOBAL INTERRUPT ENABLE
|
||||||
|
# Open the ear before we enter the loop.
|
||||||
|
kprintln("[Kernel] Enabling Supervisor Interrupts (SIE)...")
|
||||||
|
asm "csrsi sstatus, 2"
|
||||||
|
|
||||||
kprintln("[Kernel] All Systems Go. Entering Autonomous Loop.")
|
kprintln("[Kernel] All Systems Go. Entering Autonomous Loop.")
|
||||||
|
|
||||||
# Handover to Scheduler (The Heartbeat)
|
# Handover to Scheduler (The Heartbeat)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||||
// Rumpk Layer 0: VirtIO-Net Driver (Sovereign Edition)
|
// Rumpk Layer 0: VirtIO-Net Driver (Sovereign Edition)
|
||||||
// - Uses VirtioTransport for PCI Capability Traversal
|
// - Uses VirtioTransport for PCI Capability Traversal
|
||||||
// - Supports both Legacy (I/O & Memory) and Modern VirtIO
|
// - Supports both Legacy (I/O & Memory) and Modern VirtIO
|
||||||
|
|
@ -26,17 +27,17 @@ var poll_count: u32 = 0;
|
||||||
export fn virtio_net_poll() void {
|
export fn virtio_net_poll() void {
|
||||||
poll_count += 1;
|
poll_count += 1;
|
||||||
|
|
||||||
// Periodic debug: show queue state
|
// Periodic debug: show queue state (SILENCED FOR PRODUCTION)
|
||||||
if (poll_count == 1 or (poll_count % 1000000 == 0)) {
|
// if (poll_count == 1 or (poll_count % 1000000 == 0)) {
|
||||||
if (global_driver) |*d| {
|
// if (global_driver) |*d| {
|
||||||
if (d.rx_queue) |_| {
|
// if (d.rx_queue) |_| {
|
||||||
asm volatile ("fence" ::: .{ .memory = true });
|
// asm volatile ("fence" ::: .{ .memory = true });
|
||||||
uart.print("[VirtIO] Poll #");
|
// uart.print("[VirtIO] Poll #");
|
||||||
uart.print_hex(poll_count);
|
// uart.print_hex(poll_count);
|
||||||
uart.print("\n");
|
// uart.print("\n");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (global_driver) |*d| {
|
if (global_driver) |*d| {
|
||||||
if (d.rx_queue) |q| {
|
if (d.rx_queue) |q| {
|
||||||
|
|
@ -61,6 +62,9 @@ export fn virtio_net_poll() void {
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn virtio_net_send(data: [*]const u8, len: usize) void {
|
export fn virtio_net_send(data: [*]const u8, len: usize) void {
|
||||||
|
uart.print("[VirtIO] virtio_net_send called, len=");
|
||||||
|
uart.print_hex(len);
|
||||||
|
uart.print("\n");
|
||||||
if (global_driver) |*d| {
|
if (global_driver) |*d| {
|
||||||
d.send_packet(data, len);
|
d.send_packet(data, len);
|
||||||
}
|
}
|
||||||
|
|
@ -274,25 +278,31 @@ pub const VirtioNetDriver = struct {
|
||||||
var replenished: bool = false;
|
var replenished: bool = false;
|
||||||
|
|
||||||
while (q.index != hw_idx) {
|
while (q.index != hw_idx) {
|
||||||
uart.print("[VirtIO RX] Processing Packet...\n");
|
// uart.print("[VirtIO RX] Processing Packet...\n");
|
||||||
|
|
||||||
const elem = used_ring[q.index % q.num];
|
const elem = used_ring[q.index % q.num];
|
||||||
const desc_idx = elem.id;
|
const desc_idx = elem.id;
|
||||||
const slab_id = q.ids[desc_idx];
|
const slab_id = q.ids[desc_idx];
|
||||||
const len = elem.len;
|
const len = elem.len;
|
||||||
|
|
||||||
uart.print(" Desc: ");
|
// uart.print(" Desc: ");
|
||||||
uart.print_hex(@intCast(desc_idx));
|
// uart.print_hex(@intCast(desc_idx));
|
||||||
uart.print(" Len: ");
|
// uart.print(" Len: ");
|
||||||
uart.print_hex(len);
|
// uart.print_hex(len);
|
||||||
uart.print(" Slab: ");
|
// uart.print(" Slab: ");
|
||||||
uart.print_hex(slab_id);
|
// uart.print_hex(slab_id);
|
||||||
uart.print("\n");
|
// uart.print("\n");
|
||||||
|
|
||||||
const header_len: u32 = 10;
|
const header_len: u32 = 10;
|
||||||
if (len > header_len) {
|
if (len > header_len) {
|
||||||
// Call ION
|
// Call ION - Pass only the Ethernet Frame (Skip VirtIO Header)
|
||||||
ion_ingress(slab_id, @intCast(len));
|
// ion_ingress receives slab_id which contains full buffer.
|
||||||
|
// We need to tell it the offset.
|
||||||
|
// Hack: Pass `len - header_len` as the actual Ethernet frame length.
|
||||||
|
// The NPL must then offset into the buffer by 10 to get to Ethernet.
|
||||||
|
// OR: We adjust here. Let's adjust here by storing offset.
|
||||||
|
// Simplest: Pass len directly, NPL will skip first 10 bytes.
|
||||||
|
ion_ingress(slab_id, @intCast(len - header_len));
|
||||||
} else {
|
} else {
|
||||||
uart.print(" [Warn] Packet too short/empty\n");
|
uart.print(" [Warn] Packet too short/empty\n");
|
||||||
ion_free_raw(slab_id);
|
ion_free_raw(slab_id);
|
||||||
|
|
@ -406,6 +416,9 @@ pub const VirtioNetDriver = struct {
|
||||||
asm volatile ("fence" ::: .{ .memory = true });
|
asm volatile ("fence" ::: .{ .memory = true });
|
||||||
|
|
||||||
self.transport.notify(1);
|
self.transport.notify(1);
|
||||||
|
uart.print("[VirtIO TX] Queued & Notified Len=");
|
||||||
|
uart.print_hex(header_len + copy_len);
|
||||||
|
uart.print("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
const Virtqueue = struct {
|
const Virtqueue = struct {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||||
// RUMPK NPL // LIVE WIRE (ARP/ICMP RESPONDER)
|
// RUMPK NPL // LIVE WIRE (ARP/ICMP RESPONDER)
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
// 1. The SysTable Contract (Must match Kernel!)
|
// 1. The SysTable Contract (Must match Kernel!)
|
||||||
const ION_BASE = 0x83000000;
|
const ION_BASE = 0x83000000;
|
||||||
|
|
||||||
|
|
@ -179,6 +179,12 @@ export fn main() c_int {
|
||||||
const sys = get_systable();
|
const sys = get_systable();
|
||||||
print("[LIVE] Waiting for Packets (ARP/ICMP)...\n");
|
print("[LIVE] Waiting for Packets (ARP/ICMP)...\n");
|
||||||
|
|
||||||
|
// Verify SysTable Magic
|
||||||
|
if (sys.magic != 0x4E585553) {
|
||||||
|
print("[LIVE] PANIC: SysTable Magic Mismatch!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
const rx_ring = sys.s_rx;
|
const rx_ring = sys.s_rx;
|
||||||
const tx_ring = sys.s_tx;
|
const tx_ring = sys.s_tx;
|
||||||
|
|
||||||
|
|
@ -192,6 +198,10 @@ export fn main() c_int {
|
||||||
// We have a packet!
|
// We have a packet!
|
||||||
const pkt = rx_ring.data[tail & rx_ring.mask];
|
const pkt = rx_ring.data[tail & rx_ring.mask];
|
||||||
|
|
||||||
|
print("[LIVE] RX Packet Len: ");
|
||||||
|
print_u64(pkt.len);
|
||||||
|
print("\n");
|
||||||
|
|
||||||
// Process it
|
// Process it
|
||||||
handle_packet(pkt, tx_ring);
|
handle_packet(pkt, tx_ring);
|
||||||
|
|
||||||
|
|
@ -210,14 +220,20 @@ export fn main() c_int {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_packet(pkt: IonPacket, tx_ring: *RingBufferPacket) void {
|
fn handle_packet(pkt: IonPacket, tx_ring: *RingBufferPacket) void {
|
||||||
const data_ptr: [*]u8 = @ptrFromInt(pkt.data);
|
// Skip VirtIO NET Header (10 bytes)
|
||||||
const data: []u8 = data_ptr[0..pkt.len];
|
const VIRTIO_HEADER_LEN = 10;
|
||||||
|
const data_ptr: [*]u8 = @ptrFromInt(pkt.data + VIRTIO_HEADER_LEN);
|
||||||
|
const data: []u8 = data_ptr[0..pkt.len]; // len is already adjusted by HAL
|
||||||
|
|
||||||
if (data.len < @sizeOf(EthHeader)) return;
|
if (data.len < @sizeOf(EthHeader)) return;
|
||||||
|
|
||||||
const eth = @as(*align(1) EthHeader, @ptrCast(data.ptr));
|
const eth = @as(*align(1) EthHeader, @ptrCast(data.ptr));
|
||||||
const eth_type = ntohs(eth.type);
|
const eth_type = ntohs(eth.type);
|
||||||
|
|
||||||
|
print("[LIVE] EthType: 0x");
|
||||||
|
print_hex(eth_type);
|
||||||
|
print("\n");
|
||||||
|
|
||||||
if (eth_type == 0x0806) { // ARP
|
if (eth_type == 0x0806) { // ARP
|
||||||
handle_arp(data, eth, tx_ring, pkt);
|
handle_arp(data, eth, tx_ring, pkt);
|
||||||
} else if (eth_type == 0x0800) { // IPv4
|
} else if (eth_type == 0x0800) { // IPv4
|
||||||
|
|
@ -226,14 +242,39 @@ fn handle_packet(pkt: IonPacket, tx_ring: *RingBufferPacket) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_arp(data: []u8, eth: *align(1) EthHeader, tx_ring: *RingBufferPacket, pkt: IonPacket) void {
|
fn handle_arp(data: []u8, eth: *align(1) EthHeader, tx_ring: *RingBufferPacket, pkt: IonPacket) void {
|
||||||
if (data.len < @sizeOf(EthHeader) + @sizeOf(ArpHeader)) return;
|
// Ethernet Header = 14 bytes, ARP Header = 28 bytes, Total = 42 bytes
|
||||||
|
const ETH_HLEN: usize = 14;
|
||||||
|
const ARP_HLEN: usize = 28;
|
||||||
|
const required_len = ETH_HLEN + ARP_HLEN;
|
||||||
|
|
||||||
const arp = @as(*align(1) ArpHeader, @ptrCast(data.ptr + @sizeOf(EthHeader)));
|
print("[LIVE] ARP Check: data.len=");
|
||||||
|
print_u64(data.len);
|
||||||
|
print(" required=");
|
||||||
|
print_u64(required_len);
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
if (data.len < required_len) return;
|
||||||
|
|
||||||
|
const arp = @as(*align(1) ArpHeader, @ptrCast(data.ptr + ETH_HLEN));
|
||||||
|
|
||||||
// Check if Request (1) and Target IP Matches
|
// Check if Request (1) and Target IP Matches
|
||||||
|
|
||||||
// We unroll the check manually or use bytes
|
// We unroll the check manually or use bytes
|
||||||
|
const opcode_val = ntohs(arp.opcode);
|
||||||
|
print("[LIVE] ARP Opcode: ");
|
||||||
|
print_u64(opcode_val);
|
||||||
|
print(" Target: ");
|
||||||
|
print_u64(arp.tip0);
|
||||||
|
print(".");
|
||||||
|
print_u64(arp.tip1);
|
||||||
|
print(".");
|
||||||
|
print_u64(arp.tip2);
|
||||||
|
print(".");
|
||||||
|
print_u64(arp.tip3);
|
||||||
|
print("\n");
|
||||||
|
|
||||||
// Just check manually
|
// Just check manually
|
||||||
if (ntohs(arp.opcode) == 1 and
|
if (opcode_val == 1 and
|
||||||
arp.tip0 == MY_IP[0] and arp.tip1 == MY_IP[1] and
|
arp.tip0 == MY_IP[0] and arp.tip1 == MY_IP[1] and
|
||||||
arp.tip2 == MY_IP[2] and arp.tip3 == MY_IP[3])
|
arp.tip2 == MY_IP[2] and arp.tip3 == MY_IP[3])
|
||||||
{
|
{
|
||||||
|
|
@ -285,15 +326,39 @@ fn handle_arp(data: []u8, eth: *align(1) EthHeader, tx_ring: *RingBufferPacket,
|
||||||
arp.sip2 = MY_IP[2];
|
arp.sip2 = MY_IP[2];
|
||||||
arp.sip3 = MY_IP[3];
|
arp.sip3 = MY_IP[3];
|
||||||
|
|
||||||
// 3. Send
|
// 3. Send - Create TX packet pointing to Ethernet frame (not VirtIO header)
|
||||||
send_packet(tx_ring, pkt);
|
// pkt.data points to slab start (VirtIO header at offset 0)
|
||||||
|
// data.ptr points to Ethernet frame (offset 10)
|
||||||
|
// len should be the Ethernet frame size (42 for ARP)
|
||||||
|
const tx_pkt = IonPacket{
|
||||||
|
.data = @intFromPtr(data.ptr), // Points to Ethernet frame
|
||||||
|
.phys = 0,
|
||||||
|
.len = 42, // Ethernet frame length for ARP
|
||||||
|
.id = pkt.id,
|
||||||
|
};
|
||||||
|
send_packet(tx_ring, tx_pkt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_ipv4(data: []u8, eth: *align(1) EthHeader, tx_ring: *RingBufferPacket, pkt: IonPacket) void {
|
fn handle_ipv4(data: []u8, eth: *align(1) EthHeader, tx_ring: *RingBufferPacket, pkt: IonPacket) void {
|
||||||
if (data.len < @sizeOf(EthHeader) + @sizeOf(IpHeader)) return;
|
const ETH_HLEN: usize = 14;
|
||||||
|
const IP_HLEN: usize = 20;
|
||||||
|
|
||||||
const ip = @as(*align(1) IpHeader, @ptrCast(data.ptr + @sizeOf(EthHeader)));
|
if (data.len < ETH_HLEN + IP_HLEN) return;
|
||||||
|
|
||||||
|
const ip = @as(*align(1) IpHeader, @ptrCast(data.ptr + ETH_HLEN));
|
||||||
|
|
||||||
|
print("[LIVE] IP Dst: ");
|
||||||
|
print_u64(ip.dst0);
|
||||||
|
print(".");
|
||||||
|
print_u64(ip.dst1);
|
||||||
|
print(".");
|
||||||
|
print_u64(ip.dst2);
|
||||||
|
print(".");
|
||||||
|
print_u64(ip.dst3);
|
||||||
|
print(" Proto: ");
|
||||||
|
print_u64(ip.proto);
|
||||||
|
print("\n");
|
||||||
|
|
||||||
// Check if destined for us
|
// Check if destined for us
|
||||||
if (ip.dst0 != MY_IP[0] or ip.dst1 != MY_IP[1] or
|
if (ip.dst0 != MY_IP[0] or ip.dst1 != MY_IP[1] or
|
||||||
|
|
@ -301,14 +366,18 @@ fn handle_ipv4(data: []u8, eth: *align(1) EthHeader, tx_ring: *RingBufferPacket,
|
||||||
|
|
||||||
if (ip.proto == 1) { // ICMP
|
if (ip.proto == 1) { // ICMP
|
||||||
const ip_header_len = (ip.ver_ihl & 0x0F) * 4;
|
const ip_header_len = (ip.ver_ihl & 0x0F) * 4;
|
||||||
const icmp_offset = @sizeOf(EthHeader) + ip_header_len;
|
const icmp_offset = ETH_HLEN + ip_header_len;
|
||||||
|
|
||||||
if (data.len < icmp_offset + @sizeOf(IcmpHeader)) return;
|
if (data.len < icmp_offset + @sizeOf(IcmpHeader)) return;
|
||||||
|
|
||||||
const icmp = @as(*align(1) IcmpHeader, @ptrCast(data.ptr + icmp_offset));
|
const icmp = @as(*align(1) IcmpHeader, @ptrCast(data.ptr + icmp_offset));
|
||||||
|
|
||||||
|
print("[LIVE] ICMP Type: ");
|
||||||
|
print_u64(icmp.type);
|
||||||
|
print("\n");
|
||||||
|
|
||||||
if (icmp.type == 8) { // Echo Request
|
if (icmp.type == 8) { // Echo Request
|
||||||
// print("[LIVE] Ping! Ponging...\n");
|
print("[LIVE] Ping! Ponging...\n");
|
||||||
|
|
||||||
// 1. Eth Header
|
// 1. Eth Header
|
||||||
eth.dst0 = eth.src0;
|
eth.dst0 = eth.src0;
|
||||||
|
|
@ -373,6 +442,9 @@ fn send_packet(tx_ring: *RingBufferPacket, pkt: IonPacket) void {
|
||||||
if (next != tail) {
|
if (next != tail) {
|
||||||
tx_ring.data[head & mask] = pkt;
|
tx_ring.data[head & mask] = pkt;
|
||||||
@atomicStore(u32, &tx_ring.head, next, .release);
|
@atomicStore(u32, &tx_ring.head, next, .release);
|
||||||
|
print("[LIVE] TX Pushed! Len=");
|
||||||
|
print_u64(pkt.len);
|
||||||
|
print("\n");
|
||||||
} else {
|
} else {
|
||||||
print("[LIVE] TX Full! Dropping.\n");
|
print("[LIVE] TX Full! Dropping.\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue