rumpk/core/netswitch.nim

148 lines
4.1 KiB
Nim

# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: Software Network Switch
# core/rumpk/core/netswitch.nim
# Phase 36.2: The Traffic Cop (Network Membrane Layer 2 Switch)
#
# Responsibilities:
# - Poll VirtIO-Net hardware for incoming packets
# - Route RX packets to s_net_rx ring (Kernel -> Userland)
# - Drain s_net_tx ring and transmit via VirtIO-Net (Userland -> Kernel)
# - Never yield during active traffic (War Mode latency optimization)
{.push stackTrace: off, lineTrace: off.}
import ion
# Forward declare fiber_yield to avoid circular import
proc fiber_yield*() {.importc, cdecl.}
proc fiber_sleep*(ms: int) {.importc, cdecl.}
# HAL Imports
proc virtio_net_poll() {.importc, cdecl.}
proc virtio_net_send(data: pointer, len: uint32) {.importc, cdecl.}
# Logging
proc kprintln(s: cstring) {.importc, cdecl.}
proc kprint(s: cstring) {.importc, cdecl.}
proc kprint_hex(v: uint64) {.importc, cdecl.}
proc get_now_ns(): uint64 {.importc, cdecl.}
# Membrane Infrastructure (LwIP Glue)
proc membrane_init*() {.importc, cdecl.}
proc pump_membrane_stack*() {.importc, cdecl.}
var netswitch_initialized: bool = false
proc netswitch_init*() =
## Initialize network channels and populate SysTable
## MUST be called before userland starts!
ion_init_network()
kprintln("[NetSwitch] Network Rings Initialized")
netswitch_initialized = true
proc netswitch_attach_systable*(sys: ptr SysTable) =
## Attach network ring pointers to SysTable for userland access
sys.s_net_rx = chan_net_rx.ring
sys.s_net_tx = chan_net_tx.ring
kprintln("[NetSwitch] SysTable Rings Attached")
type
EthHeader* {.packed.} = object
dst*: array[6, byte]
src*: array[6, byte]
ethertype*: uint16 # Big Endian
proc swap16(v: uint16): uint16 =
((v and 0xFF) shl 8) or (v shr 8)
proc netswitch_process_packet(pkt: IonPacket): bool =
## Layer 2 Demultiplexer
if pkt.len < 14:
ion_free(pkt)
return false
let eth = cast[ptr EthHeader](pkt.data)
let etype = swap16(eth.ethertype)
case etype:
of 0x0800, 0x0806, 0x86DD: # IPv4, ARP, IPv6
# Route to Legacy/LwIP Membrane
if not chan_net_rx.send(pkt):
# Ring full (Backpressure)
ion_free(pkt)
return false
return true
of 0x88B5: # Sovereign UTCP (SPEC-410)
# TODO: Route to dedicated UTCP channel
# kprintln("[NetSwitch] UTCP Sovereign Packet Identified")
ion_free(pkt)
return true # Handled (dropped)
else:
# Drop unknown EtherTypes (Security/Sovereignty)
ion_free(pkt)
return false
proc fiber_netswitch_entry*() {.cdecl.} =
membrane_init()
kprintln("[NetSwitch] Fiber Entry - The Traffic Cop is ON DUTY")
var rx_activity: bool = false
var tx_activity: bool = false
var rx_count: uint64 = 0
var tx_count: uint64 = 0
var last_stat_print: uint64 = 0
while true:
rx_activity = false
tx_activity = false
# 1. Drive the hardware poll (fills chan_netswitch_rx)
virtio_net_poll()
# 2. Drive the LwIP Stack (Timers/RX)
pump_membrane_stack()
# 2. Consume from the Driver -> Switch internal ring
var raw_pkt: IonPacket
while chan_netswitch_rx.recv(raw_pkt):
if netswitch_process_packet(raw_pkt):
rx_activity = true
inc rx_count
# 3. TX PATH: Userland -> Hardware
var tx_pkt: IonPacket
while chan_net_tx.recv(tx_pkt):
if tx_pkt.data != nil and tx_pkt.len > 0:
virtio_net_send(cast[pointer](tx_pkt.data), uint32(tx_pkt.len))
inc tx_count
ion_free(tx_pkt)
tx_activity = true
# 4. Periodically print stats
let now = get_now_ns()
if now - last_stat_print > 5000000000'u64: # 5 seconds
kprint("[NetSwitch] STATS - RX: ")
kprint_hex(rx_count)
kprint(" TX: ")
kprint_hex(tx_count)
kprintln("")
last_stat_print = now
# 5. Yield Strategy
if rx_activity or tx_activity:
# War Mode: High priority processing
continue
else:
fiber_sleep(10)
{.pop.}