# 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: "rumpk_timer_now_ns", cdecl.} # Project LibWeb: LWF Adapter (Zig FFI) proc lwf_validate(data: pointer, len: uint16): uint8 {.importc, cdecl.} const ETHERTYPE_LWF = 0x4C57'u16 # "LW" — Libertaria Wire Frame # 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 # NOTE(LibWeb): IPv6 is the first-class citizen for sovereign mesh. # Most chapter nodes sit behind consumer NAT — IPv6 provides # end-to-end addressability without traversal hacks. # IPv4 is the fallback, not the default. Membrane/Transport # layer enforces preference order (IPv6 → IPv4). # 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-700) # TODO: Route to dedicated UTCP channel # kprintln("[NetSwitch] UTCP Sovereign Packet Identified") ion_free(pkt) return true # Handled (dropped) of ETHERTYPE_LWF: # Project LibWeb: Libertaria Wire Frame # Validate LWF magic before routing (Fast Drop) let lwf_data = cast[pointer](cast[uint64](pkt.data) + 14) # Skip Eth header let lwf_len = if pkt.len > 14: uint16(pkt.len - 14) else: 0'u16 if lwf_len >= 88 and lwf_validate(lwf_data, lwf_len) == 1: # Valid LWF — route to dedicated LWF channel if not chan_lwf_rx.send(pkt): ion_free(pkt) # Backpressure return false return true else: # Invalid LWF frame — drop ion_free(pkt) return false else: # Drop unknown EtherTypes (Security/Sovereignty) ion_free(pkt) return false proc fiber_netswitch_entry*() {.cdecl.} = 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() # [Cleaned] Driven by Userland now # 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 (Legacy/LwIP) 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 # 3b. TX PATH: LWF Egress (Project LibWeb) var lwf_pkt: IonPacket while chan_lwf_tx.recv(lwf_pkt): if lwf_pkt.data != nil and lwf_pkt.len > 0: virtio_net_send(cast[pointer](lwf_pkt.data), uint32(lwf_pkt.len)) inc tx_count ion_free(lwf_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.}